134 lines
2.5 KiB
Go
134 lines
2.5 KiB
Go
package utils
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
// ClientIP 获取客户端真实IP
|
|
func ClientIP(c *gin.Context) string {
|
|
// 优先取反向代理头
|
|
for _, header := range []string{"X-Real-IP", "X-Forwarded-For"} {
|
|
if v := c.GetHeader(header); v != "" {
|
|
ips := strings.Split(v, ",")
|
|
ip := strings.TrimSpace(ips[0])
|
|
if ip != "" {
|
|
return ip
|
|
}
|
|
}
|
|
}
|
|
return c.ClientIP()
|
|
}
|
|
|
|
// SanitizePath 清理虚拟路径,防止路径穿越
|
|
func SanitizePath(p string) string {
|
|
p = strings.ReplaceAll(p, "\\", "/")
|
|
parts := make([]string, 0, 8)
|
|
for _, seg := range strings.Split(p, "/") {
|
|
seg = strings.TrimSpace(seg)
|
|
if seg == "" || seg == "." {
|
|
continue
|
|
}
|
|
if seg == ".." {
|
|
if len(parts) > 0 {
|
|
parts = parts[:len(parts)-1]
|
|
}
|
|
continue
|
|
}
|
|
parts = append(parts, seg)
|
|
}
|
|
return strings.Join(parts, "/")
|
|
}
|
|
|
|
// IsValidPassword 检查密码强度:至少8位,包含字母和数字
|
|
func IsValidPassword(pwd string) bool {
|
|
if len(pwd) < 8 {
|
|
return false
|
|
}
|
|
hasLetter, hasDigit := false, false
|
|
for _, ch := range pwd {
|
|
switch {
|
|
case ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z':
|
|
hasLetter = true
|
|
case ch >= '0' && ch <= '9':
|
|
hasDigit = true
|
|
}
|
|
}
|
|
return hasLetter && hasDigit
|
|
}
|
|
|
|
// IsEmail 简单校验邮箱格式
|
|
func IsEmail(s string) bool {
|
|
at := strings.IndexByte(s, '@')
|
|
if at <= 0 || at == len(s)-1 {
|
|
return false
|
|
}
|
|
domain := s[at+1:]
|
|
return strings.Contains(domain, ".") && strings.IndexByte(domain, '.') != 0 && strings.IndexByte(domain, '.') != len(domain)-1
|
|
}
|
|
|
|
// HumanSize 将字节数转为可读大小
|
|
func HumanSize(n int64) string {
|
|
const unit = 1024
|
|
if n < unit {
|
|
return itoa(n) + " B"
|
|
}
|
|
div, exp := int64(unit), 0
|
|
for m := n / unit; m >= unit && exp < 4; m /= unit {
|
|
div *= unit
|
|
exp++
|
|
}
|
|
val := float64(n) / float64(div)
|
|
s := trimFloat(val)
|
|
units := []string{"KB", "MB", "GB", "TB", "PB"}
|
|
return s + " " + units[exp]
|
|
}
|
|
|
|
func itoa(n int64) string {
|
|
if n == 0 {
|
|
return "0"
|
|
}
|
|
neg := n < 0
|
|
if neg {
|
|
n = -n
|
|
}
|
|
var buf [20]byte
|
|
i := len(buf)
|
|
for n > 0 {
|
|
i--
|
|
buf[i] = byte('0' + n%10)
|
|
n /= 10
|
|
}
|
|
if neg {
|
|
i--
|
|
buf[i] = '-'
|
|
}
|
|
return string(buf[i:])
|
|
}
|
|
|
|
func trimFloat(f float64) string {
|
|
// 保留两位小数并去掉末尾多余的0
|
|
s := itoa(int64(f))
|
|
frac := f - float64(int64(f))
|
|
if frac < 0.005 {
|
|
return s
|
|
}
|
|
d1 := int64(frac * 10)
|
|
if d1 > 9 {
|
|
d1 = 9
|
|
}
|
|
frac = frac*10 - float64(d1)
|
|
d2 := int64(frac * 10)
|
|
if d2 > 9 {
|
|
d2 = 9
|
|
}
|
|
if d2 < 5 {
|
|
if d1 == 0 {
|
|
return s
|
|
}
|
|
return s + "." + itoa(d1)
|
|
}
|
|
return s + "." + itoa(d1) + itoa(d2)
|
|
}
|