mirror of
https://gitlab.52pay.top/go/easygoadmin.git
synced 2025-10-01 00:24:15 +08:00
436 lines
9.2 KiB
Go
436 lines
9.2 KiB
Go
/**
|
||
* 系统工具类
|
||
* @author
|
||
* @since 2021/8/25
|
||
* @File : utils
|
||
*/
|
||
package utils
|
||
|
||
import (
|
||
"crypto/md5"
|
||
"encoding/hex"
|
||
"encoding/json"
|
||
"errors"
|
||
"fmt"
|
||
"github.com/gin-contrib/sessions"
|
||
"github.com/gin-gonic/gin"
|
||
"github.com/gogf/gf/container/garray"
|
||
"gitlab.52pay.top/go/easygoadmin/library/cfg"
|
||
"gitlab.52pay.top/go/easygoadmin/utils/gconv"
|
||
"gitlab.52pay.top/go/easygoadmin/utils/gmd5"
|
||
"gitlab.52pay.top/go/easygoadmin/utils/gstr"
|
||
"log"
|
||
"os"
|
||
"regexp"
|
||
"strconv"
|
||
"strings"
|
||
"time"
|
||
)
|
||
|
||
// 调试模式
|
||
func AppDebug() bool {
|
||
// 获取配置实例
|
||
config := cfg.Instance()
|
||
return config.EasyGoAdmin.Debug
|
||
}
|
||
|
||
// 登录用户ID
|
||
func Uid(ctx *gin.Context) int {
|
||
// 初始化session对象
|
||
session := sessions.Default(ctx)
|
||
// 获取用户ID
|
||
userId := gconv.Int(session.Get("userId"))
|
||
// 返回用户ID
|
||
return userId
|
||
}
|
||
|
||
// 判断用户登录状态
|
||
func IsLogin(ctx *gin.Context) bool {
|
||
// 初始化session对象
|
||
session := sessions.Default(ctx)
|
||
// 获取用户ID
|
||
userId := session.Get("userId")
|
||
return userId != nil
|
||
}
|
||
|
||
// 检测用户签名
|
||
func CheckSign(ctx *gin.Context) bool {
|
||
ctx.Request.ParseForm()
|
||
dataMap := make(map[string]string)
|
||
sign := ""
|
||
appId := ""
|
||
//说明:须post方法,加: 'Content-Type': 'application/x-www-form-urlencoded'
|
||
for key := range ctx.Request.PostForm {
|
||
if key == "sign" {
|
||
sign = ctx.PostForm(key)
|
||
}
|
||
if key == "app_id" {
|
||
appId = ctx.PostForm(key)
|
||
}
|
||
dataMap[key] = ctx.PostForm(key)
|
||
}
|
||
//
|
||
for key := range ctx.Request.URL.Query() {
|
||
if key == "sign" {
|
||
sign = ctx.Query(key)
|
||
}
|
||
if key == "app_id" {
|
||
appId = ctx.Query(key)
|
||
}
|
||
dataMap[key] = ctx.Query(key)
|
||
}
|
||
|
||
if len(dataMap) < 0 || sign == "" {
|
||
return false
|
||
}
|
||
|
||
keyArray := garray.NewStrArray()
|
||
for key := range dataMap {
|
||
if key == "sign" {
|
||
continue
|
||
}
|
||
keyArray.Append(key)
|
||
}
|
||
|
||
secret := GetAppSecret(ctx, appId)
|
||
if secret == "" {
|
||
return false
|
||
}
|
||
newSign := GetNewSign(dataMap, keyArray, secret)
|
||
|
||
if newSign != sign {
|
||
return false
|
||
}
|
||
|
||
return true
|
||
}
|
||
|
||
// 获取签名
|
||
func GetNewSign(dataMap map[string]string, keyArray *garray.StrArray, secret string) string {
|
||
keyArray.Sort()
|
||
str := ""
|
||
keyArray.Iterator(func(k int, v string) bool {
|
||
val := dataMap[v]
|
||
tmp := fmt.Sprintf("%s=%s", v, val)
|
||
if k == 0 {
|
||
str = tmp
|
||
} else {
|
||
str = fmt.Sprintf("%s&%s", str, tmp)
|
||
}
|
||
return true
|
||
})
|
||
str = fmt.Sprintf("%s&key=%s", str, secret)
|
||
d := []byte(str)
|
||
m := md5.New()
|
||
m.Write(d)
|
||
newSign := hex.EncodeToString(m.Sum(nil))
|
||
newSign = strings.ToUpper(newSign)
|
||
return newSign
|
||
}
|
||
|
||
type PbSettingAppUtils struct {
|
||
Id int `json:"id" xorm:"not null pk autoincr comment('主键ID') INT(10)"`
|
||
AppId string `json:"app_id"`
|
||
AppName string `json:"app_name"`
|
||
Phone string `json:"phone"`
|
||
AppKey string `json:"app_key"`
|
||
Status int64 `json:"status"`
|
||
CouponSmsContent string `json:"coupon_sms_content"`
|
||
ServiceAddress string `json:"service_address"`
|
||
ComName string `json:"com_name"`
|
||
FilingNo string `json:"filing_no"`
|
||
}
|
||
|
||
func (r *PbSettingAppUtils) TableName() string {
|
||
return "pb_setting_app"
|
||
}
|
||
|
||
// 根据 appid 获取 appSecret
|
||
func GetAppSecret(ctx *gin.Context, appId string) string {
|
||
cache := GetRedisHelper()
|
||
cacheKey := fmt.Sprintf("Utils:GetAppSecretV2:%s", appId)
|
||
val := cache.Get(ctx, cacheKey).Val()
|
||
if val != "" {
|
||
return val
|
||
}
|
||
var info PbSettingAppUtils
|
||
_, err := XormDb.Where("app_id = ?", appId).Get(&info)
|
||
|
||
if err != nil {
|
||
return ""
|
||
}
|
||
cache.Set(ctx, cacheKey, info.AppKey, 3*time.Minute)
|
||
return info.AppKey
|
||
}
|
||
|
||
// 根据 appid 获取 appSecret
|
||
func GetAppInfo(ctx *gin.Context, appId string) PbSettingAppUtils {
|
||
cache := GetRedisHelper()
|
||
cacheKey := fmt.Sprintf("Utils:GetAppInfo:V2:%s", appId)
|
||
val := cache.Get(ctx, cacheKey).Val()
|
||
var info PbSettingAppUtils
|
||
if val != "" {
|
||
json.Unmarshal([]byte(val), &info)
|
||
return info
|
||
}
|
||
_, err := XormDb.Where("app_id = ?", appId).Get(&info)
|
||
|
||
if err != nil {
|
||
return PbSettingAppUtils{}
|
||
}
|
||
jsonStr, _ := json.Marshal(info)
|
||
cache.Set(ctx, cacheKey, jsonStr, 4*time.Minute)
|
||
return info
|
||
}
|
||
|
||
// 获取数据库表
|
||
func GetDatabase() (string, error) {
|
||
config := cfg.Instance()
|
||
if config == nil {
|
||
fmt.Printf("参数错误")
|
||
}
|
||
|
||
// 获取数据库连接
|
||
link := config.Database.Master
|
||
if link == "" {
|
||
return "", errors.New("数据库配置读取错误")
|
||
}
|
||
// 分裂字符串
|
||
linkArr := strings.Split(link, "/")
|
||
return strings.Split(linkArr[1], "?")[0], nil
|
||
}
|
||
|
||
func Md5(password string) (string, error) {
|
||
// 第一次MD5加密
|
||
password, err := gmd5.Encrypt(password)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
// 第二次MD5加密
|
||
password2, err := gmd5.Encrypt(password)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
return password2, nil
|
||
}
|
||
|
||
// 数组反转
|
||
func Reverse(arr *[]string) {
|
||
length := len(*arr)
|
||
var temp string
|
||
for i := 0; i < length/2; i++ {
|
||
temp = (*arr)[i]
|
||
(*arr)[i] = (*arr)[length-1-i]
|
||
(*arr)[length-1-i] = temp
|
||
}
|
||
}
|
||
|
||
// 获取客户端IP
|
||
func GetClientIp(ctx *gin.Context) string {
|
||
ip := ctx.Request.Header.Get("X-Forwarded-For")
|
||
if ip == "" {
|
||
ip = ctx.ClientIP()
|
||
}
|
||
return ip
|
||
}
|
||
|
||
func ImageUrl() string {
|
||
// 获取配置实例
|
||
config := cfg.Instance()
|
||
return config.EasyGoAdmin.Image
|
||
}
|
||
|
||
// 获取文件地址
|
||
func GetImageUrl(path string) string {
|
||
parts := strings.Split(path, ",")
|
||
var urls []string
|
||
for _, part := range parts {
|
||
urls = append(urls, ImageUrl()+part)
|
||
}
|
||
return strings.Join(urls, ",")
|
||
}
|
||
|
||
func InStringArray(value string, array []string) bool {
|
||
for _, v := range array {
|
||
if v == value {
|
||
return true
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
|
||
// 判断元素是否在数组中
|
||
func InArray(value string, array []interface{}) bool {
|
||
for _, v := range array {
|
||
if gconv.String(v) == value {
|
||
return true
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
|
||
// 附件目录
|
||
func UploadPath() string {
|
||
|
||
// 获取配置实例
|
||
config := cfg.Instance()
|
||
// 附件存储路径
|
||
upload_dir := config.EasyGoAdmin.Uploads
|
||
if upload_dir != "" {
|
||
return upload_dir
|
||
} else {
|
||
// 获取项目根目录
|
||
curDir, _ := os.Getwd()
|
||
return curDir + "/public/uploads"
|
||
}
|
||
}
|
||
|
||
// 临时目录
|
||
func TempPath() string {
|
||
return UploadPath() + "/temp"
|
||
}
|
||
|
||
// 图片存放目录
|
||
func ImagePath() string {
|
||
return UploadPath() + "/images"
|
||
}
|
||
|
||
// 文件目录(非图片目录)
|
||
func FilePath() string {
|
||
return UploadPath() + "/file"
|
||
}
|
||
|
||
// 创建文件夹并设置权限
|
||
func CreateDir(path string) bool {
|
||
// 判断文件夹是否存在
|
||
if IsExist(path) {
|
||
return true
|
||
}
|
||
// 创建多层级目录
|
||
err2 := os.MkdirAll(path, os.ModePerm)
|
||
if err2 != nil {
|
||
log.Println(err2)
|
||
return false
|
||
}
|
||
return true
|
||
}
|
||
|
||
// 判断文件/文件夹是否存在(返回true是存在)
|
||
func IsExist(path string) bool {
|
||
// 读取文件信息,判断文件是否存在
|
||
_, err := os.Stat(path)
|
||
if err != nil {
|
||
log.Println(err)
|
||
if os.IsExist(err) {
|
||
// 根据错误类型进行判断
|
||
return true
|
||
}
|
||
return false
|
||
}
|
||
return true
|
||
}
|
||
|
||
func SaveImage(url string, dirname string) (string, error) {
|
||
// 判断文件地址是否为空
|
||
if gstr.Equal(url, "") {
|
||
return "", errors.New("文件地址不能为空")
|
||
}
|
||
|
||
// 判断是否本站图片
|
||
if gstr.Contains(url, ImageUrl()) {
|
||
// 本站图片
|
||
|
||
// 是否临时图片
|
||
if gstr.Contains(url, "temp") {
|
||
// 临时图片
|
||
|
||
// 创建目录
|
||
dirPath := ImagePath() + "/" + dirname + "/" + time.Now().Format("20060102")
|
||
if !CreateDir(dirPath) {
|
||
return "", errors.New("文件目录创建失败")
|
||
}
|
||
// 原始图片地址
|
||
oldPath := gstr.Replace(url, ImageUrl(), UploadPath())
|
||
// 目标目录地址
|
||
newPath := ImagePath() + "/" + dirname + gstr.Replace(url, ImageUrl()+"/temp", "")
|
||
// 移动文件
|
||
os.Rename(oldPath, newPath)
|
||
return gstr.Replace(newPath, UploadPath(), ""), nil
|
||
} else {
|
||
// 非临时图片
|
||
path := gstr.Replace(url, ImageUrl(), "")
|
||
return path, nil
|
||
}
|
||
} else {
|
||
// 远程图片
|
||
// TODO...
|
||
}
|
||
return "", errors.New("保存文件异常")
|
||
}
|
||
|
||
// 处理富文本
|
||
func SaveImageContent(content string, title string, dirname string) string {
|
||
str := `<img src="(?s:(.*?))"`
|
||
//解析、编译正则
|
||
ret := regexp.MustCompile(str)
|
||
// 提取图片信息
|
||
alls := ret.FindAllStringSubmatch(content, -1)
|
||
// 遍历图片数据
|
||
for _, v := range alls {
|
||
// 获取图片地址
|
||
item := v[1]
|
||
if item == "" {
|
||
continue
|
||
}
|
||
// 保存图片至正式目录
|
||
image, _ := SaveImage(item, dirname)
|
||
if image != "" {
|
||
content = strings.ReplaceAll(content, item, "[IMG_URL]"+image)
|
||
}
|
||
}
|
||
// 设置ALT标题
|
||
if strings.Contains(content, "alt=\"\"") && title != "" {
|
||
content = strings.ReplaceAll(content, "alt=\"\"", "alt=\""+title+"\"")
|
||
}
|
||
return content
|
||
}
|
||
|
||
// 截取字符串,支持多字节字符
|
||
// start:起始下标,负数从从尾部开始,最后一个为-1
|
||
// length:截取长度,负数表示截取到末尾
|
||
func SubStr(str string, start int, length int) (result string) {
|
||
s := []rune(str)
|
||
total := len(s)
|
||
if total == 0 {
|
||
return
|
||
}
|
||
// 允许从尾部开始计算
|
||
if start < 0 {
|
||
start = total + start
|
||
if start < 0 {
|
||
return
|
||
}
|
||
}
|
||
if start > total {
|
||
return
|
||
}
|
||
// 到末尾
|
||
if length < 0 {
|
||
length = total
|
||
}
|
||
|
||
end := start + length
|
||
if end > total {
|
||
result = string(s[start:])
|
||
} else {
|
||
result = string(s[start:end])
|
||
}
|
||
|
||
return
|
||
|
||
}
|
||
func FloatToInt(f float64) int {
|
||
i, _ := strconv.Atoi(fmt.Sprintf("%1.0f", f))
|
||
return i
|
||
}
|