/* ================================================================================= * License: GPL-2.0 license * Author: 众产® https://ciy.cn/code * Version: 0.1.0 ================================================================================= 命名规范。引入默认包 NewCiy* 类库实例 Ciy* 私有类库struct Ciy*inf 接口定义 Ciy* 全局变量 CIY* 全局常量 ================================================================================= Log 日志全局变量 ================================================================================= * 功能函数相关 * Sleep 延时函数。秒为单位,支持0.5秒 * Pr 带时间的打印函数 * Iff 三元运算符 * Is_numeric 是否数字 * Is_int 是否整数 * Tostr 转字符串 * Toint 转int * Tofloat 转float64 * Tobool 转bool * Tostamp 转时间戳。将Y-m-d H:i:s格式转时间戳,同时识别字符串时间戳 * Todate 时间格式化。传递0为当前时间。支持Y-m-d H:i:s。支持1970以前 * Locinzone 当前经纬度是否在围栏中 * Timems 获取当前微秒数 * Ismobile 判断手机号是否合法 x Isweixin 判断客户端是否在微信中 post.go * Idcard 判断身份证号合法 * Iduscc 判断统一社会信用代码合法 * 加解密相关 * CiySign 最多8位签名 * Encrypt 字符串加解密 * EnID/DeID ID数字加解密 * Conv33_10/Conv10_33 数字转33进制 * MD5/MD5Byte * 字符串/数组相关 * Uniqid 生成唯一ID * Array_unshift 数组顶部插入数据 * In_array 某元素在数组中存在位置 * Array_rand 随机抽取数组元素并删除 * Startwith/Endwith 首字符/尾字符匹配,可用strings.HasPrefix / strings.HasSuffix替代 * Strpos_first 字符数组优先匹配,一般匹配 ' " * Gb_substr/Gb_strlen/Gb_haschinese 中文字符串处理函数 * Getstrparam/Setstrparam 比json还简化的数据保存方式,一般用于数据字典保存。例: name=AAA|age=12|cc=CCTT * 数据库相关 * FieldAdd 手动增加列表显示字段,并返回排序字段字符串 * Getrelation 获取表内关联数据,用于大数据量表的所属ID转文字 * Tran_delcheck/Tran_delall/me 事务删除前确认/删除相关数据 * Getconfig/Setconfig 从配置表中读写配置项 * 字典相关 * Getcatas/Getsaascatas 从字典库/SaaS字典中读取 代码数组 * Id2map 将 id/name代码数组对 转换为 键值对 * Ccode 代码数组中,通过代码值找代码名 * Mcode 代码数组中,通过代码值找代码名,多级 * Scode 代码数组中,查找多个代码值,返回数组 * Dcode 代码数组中,通过代码名找代码值 * LOG相关 * SaveLog log信息记录到数据库log表 * SaveLogDB 增删改数据变更记录到数据库log表 x SaveLogFile 保存log信息写入到本地文件 log.go * 文件相关 * DirMake/FileDel/Copy/Save/Load 目录创建,多级目录创建。默认权限666 创建多层新文件夹/文件静默删除/拷贝/保存/读取 * DirExist/FileExist 目录/文件是否存在 * Saaspath 获取SaaS多租户文件存储路径 * fileext 获取文件扩展名,如jpg */ package zciyon import ( "bufio" "bytes" "crypto/hmac" "crypto/md5" "crypto/sha256" "crypto/sha512" "encoding/base64" "encoding/hex" "fmt" "io" "math" "math/rand" "os" "os/exec" "regexp" "strconv" "strings" "syscall" "time" "unicode" ) const ( CIYRUN_DEV = 0 CIYRUN_PROD = 2 ) type Ciy_Vars struct { Version string Ini CiyINI Func_succ int Func_fail int Func_commit int Func_rollback int Func_runms int } var Log *CiyLog //日志 var CiyVars *Ciy_Vars //应用全局变量 var CiyRunMode int //运行模式: 0 dev/1 test/2 prod var CiyWebDir string //当前目录,尾缀不包含/ var CiyDirSep string //操作系统目录分隔符 var CiyDB *CiyMysql //单一数据库服务器或写库服务器连接池 var CiyRouteDB *CiyDBRoute //多台同一镜像读库服务器 // 对于单一数据库的多个微业务线,建议用map数据仓管理 如: c.DB["ag"].Get 或 CiyDBxxx // 对于海量分库业务线,建议封装分布策略,聚合管理读写库 func init() { CiyRunMode = CIYRUN_DEV CiyVars = &Ciy_Vars{} CiyVars.Version = "" CiyVars.Func_succ = 0 CiyVars.Func_fail = 0 CiyVars.Func_commit = 0 CiyVars.Func_rollback = 0 CiyVars.Func_runms = 0 CiyDirSep = string(os.PathSeparator) dir, err := os.Getwd() if err == nil { DirMake(dir + "/log") DirMake(dir + "/web/ud/tmp") CiyWebDir = strings.Replace(dir, CiyDirSep, "/", -1) + "/web" } } func Sleep(s float64) { if s < 1 { time.Sleep(time.Duration(s*1000) * time.Millisecond) } else { if CiyRunMode == CIYRUN_DEV { for i := 0; i < int(s); i++ { time.Sleep(time.Duration(1000) * time.Millisecond) } } else { time.Sleep(time.Duration(s*1000) * time.Millisecond) } } } func Clog(format any, args ...any) { //https://github.com/go-ffmt/ffmt now := time.Now() millis := (now.UnixNano() / int64(time.Millisecond)) % 1000 fmt.Print(Todate(-1), ".", fmt.Sprintf("%03d", millis), ": ") if fmstr, ok := format.(string); ok { if strings.Contains(fmstr, "%") { fmt.Printf(fmstr, args...) fmt.Println("") return } } args = Array_unshift(args, format) fmt.Println(args...) // for _, arg := range args { // typ := fmt.Sprintf("%T", arg) // if typ == "uint8" { // typ = "byte" // } // fmt.Printf(typ + ": ") // switch { // case typ == "string": // fmt.Println(arg) // case typ == "byte": // fmt.Println(arg, fmt.Sprintf("%c", arg)) // // case int, int64, int32, int16, int8, uint, uint64, uint32, uint16: // // fmt.Println(arg) // // case float32, float64: // // fmt.Println("["+fmt.Sprintf("%T", arg)+"]:", arg, fmt.Sprintf("%f", arg)) // // case complex64, complex128: // // fmt.Println("["+fmt.Sprintf("%T", arg)+"]:", arg) // // case bool: // // fmt.Println("[bool]:", arg) // case strings.HasPrefix(typ, "[]"): // printarr(reflect.ValueOf(arg), 1) // case strings.HasPrefix(typ, "map"): // printmap(reflect.ValueOf(arg), 1) // default: // fmt.Println(arg) // } // } } func Iff[T int | float32 | float64 | string](b bool, t, f T) T { if b { return t } return f } func Is_numeric(a any) bool { switch v := a.(type) { case float32, float64, int, uint, int64, int32, int16, int8, uint64, uint32, uint16, uint8: return true default: floatRegex := regexp.MustCompile(`^[-+]?(\d+(\.\d*)?|\.\d+)$`) return floatRegex.MatchString(Tostr(v)) } } func Is_int(a any) bool { switch v := a.(type) { case float32, float64, int, uint, int64, int32, int16, int8, uint64, uint32, uint16, uint8: return true default: integerRegex := regexp.MustCompile(`^-?[0-9]+$`) return integerRegex.MatchString(Tostr(v)) } } func Randstr(nun int, argletter ...string) string { letter := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" if len(argletter) > 0 { letter = argletter[0] } b := make([]byte, 10) // 创建一个长度为10的字节切片 for i := range b { b[i] = letter[rand.Intn(len(letter))] // 随机生成字符 } return string(b) } func Tostr(dat any, argdef ...string) (ret string) { ret = "" defer func() { if r := recover(); r != nil { Clog("Tostr panic:", r) if len(argdef) > 0 { ret = argdef[0] } } }() switch v := dat.(type) { case int: return strconv.Itoa(v) case uint: return strconv.Itoa(int(v)) case int64: return strconv.Itoa(int(v)) case int32: return strconv.Itoa(int(v)) case int16: return strconv.Itoa(int(v)) case int8: return strconv.Itoa(int(v)) case uint64: return strconv.Itoa(int(v)) case uint32: return strconv.Itoa(int(v)) case uint16: return strconv.Itoa(int(v)) case uint8: return strconv.Itoa(int(v)) case []byte: return string(v) case string: return v case float32, float64: s := fmt.Sprintf("%.4f", v) s = strings.TrimRight(s, "0") s = strings.TrimRight(s, ".") return s case bool: if v { return "true" } else { return "false" } default: if len(argdef) > 0 { ret = argdef[0] } } return ret } func Toint(dat any, argdef ...int) (ret int) { ret = 0 defer func() { if r := recover(); r != nil { Clog("Toint panic:", r) if len(argdef) > 0 { ret = argdef[0] } } }() switch v := dat.(type) { case int: return v case uint: return int(v) case int64: return int(v) case int32: return int(v) case int16: return int(v) case int8: return int(v) case uint64: return int(v) case uint32: return int(v) case uint16: return int(v) case uint8: return int(v) case float32: return int(v) case float64: return int(v) case []byte: num, err := strconv.Atoi(strings.TrimSpace(string(v))) if err == nil { return num } else { num, err := strconv.ParseFloat(strings.TrimSpace(string(v)), 64) if err == nil { return int(num) } } case string: num, err := strconv.Atoi(strings.TrimSpace(v)) if err == nil { return num } else { num, err := strconv.ParseFloat(strings.TrimSpace(v), 64) if err == nil { return int(num) } } case bool: if v { return 1 } else { return 0 } default: if len(argdef) > 0 { ret = argdef[0] } } return ret } func Tofloat(dat any, argdef ...float64) (ret float64) { ret = 0.0 defer func() { if r := recover(); r != nil { Clog("Tofloat panic:", r) if len(argdef) > 0 { ret = argdef[0] } } }() switch v := dat.(type) { case float64: return v case int: return float64(v) case uint: return float64(v) case int64: return float64(v) case int32: return float64(v) case int16: return float64(v) case int8: return float64(v) case uint64: return float64(v) case uint32: return float64(v) case uint16: return float64(v) case uint8: return float64(v) case float32: return float64(v) case []byte: num, err := strconv.ParseFloat(string(v), 64) if err == nil { return num } case string: num, err := strconv.ParseFloat(v, 64) if err == nil { return num } case bool: if v { return 1.0 } else { return 0.0 } default: if len(argdef) > 0 { ret = argdef[0] } } return ret } func Tobool(dat any, argdef ...bool) (ret bool) { ret = false defer func() { if r := recover(); r != nil { Clog("Tobool panic:", r) if len(argdef) > 0 { ret = argdef[0] } } }() switch v := dat.(type) { case int, uint, uint64, uint32, uint16, uint8, int64, int32, int16, int8: return v != 0 case float32: return v > 0.0 case float64: return v > 0.0 case []byte: str := strings.TrimSpace(strings.ToLower(string(v))) return str == "true" || str != "0" case string: str := strings.TrimSpace(strings.ToLower(v)) return str == "true" || str != "0" case bool: return v default: if len(argdef) > 0 { ret = argdef[0] } } return ret } func Tostamp(argstr ...string) int { str := "now" if len(argstr) > 0 { str = argstr[0] } if str == "now" { timestamp := time.Now().Unix() return int(timestamp) } str = strings.Replace(str, "/", "-", -1) if strings.Contains(str, "-") { var ind, year, hour, minute, second int var month, day = 1, 1 cnt := strings.Count(str, "-") if cnt >= 2 { ind = strings.Index(str, "-") if ind > -1 { year = Toint(str[:ind]) str = strings.TrimSpace(str[ind+1:]) } } else { //判读是否4位 ind = strings.Index(str, "-") if ind > 3 { year = Toint(str[:ind]) str = strings.TrimSpace(str[ind+1:]) } else { year = time.Now().Year() } } ind = strings.Index(str, "-") if ind == -1 { month = Toint(str) } else { month = Toint(str[:ind]) str = strings.TrimSpace(str[ind+1:]) ind = strings.Index(str, " ") if ind == -1 { day = Toint(str) } else { day = Toint(str[:ind]) str = strings.TrimSpace(str[ind+1:]) ind = strings.Index(str, ":") if ind == -1 { hour = Toint(str) } else { hour = Toint(str[:ind]) str = strings.TrimSpace(str[ind+1:]) ind = strings.Index(str, ":") if ind == -1 { minute = Toint(str) } else { minute = Toint(str[:ind]) str = strings.TrimSpace(str[ind+1:]) second = Toint(str) } } } } t := time.Date(year, time.Month(month), day, hour, minute, second, 0, time.Local) timestamp := t.Unix() return int(timestamp) } return 0 } func Todate(tim int, format ...string) string { var t time.Time if tim == -1 { t = time.Now() } else if tim == 0 { return "" } else { t = time.Unix(int64(tim), 0) } str := "Y-m-d H:i:s" if len(format) > 0 { str = format[0] } str = strings.Replace(str, "Y", fmt.Sprintf("%04d", t.Year()), -1) str = strings.Replace(str, "y", fmt.Sprintf("%02d", t.Year()%100), -1) str = strings.Replace(str, "m", fmt.Sprintf("%02d", t.Month()), -1) str = strings.Replace(str, "d", fmt.Sprintf("%02d", t.Day()), -1) str = strings.Replace(str, "H", fmt.Sprintf("%02d", t.Hour()), -1) str = strings.Replace(str, "i", fmt.Sprintf("%02d", t.Minute()), -1) str = strings.Replace(str, "s", fmt.Sprintf("%02d", t.Second()), -1) return str } func Locinzone(paths string, zlat float64, zlng float64) bool { //30.434272 120.274938,30.433977 120.277270,30.432403 120.277957,30.431764 120.276340,30.432270 120.273358,30.433997 120.273283 fences := strings.Split(paths, ",") nvert := len(fences) vertx := make([]float64, nvert) verty := make([]float64, nvert) for i, r := range fences { latlng := strings.Split(r, " ") vertx[i] = Tofloat(latlng[0]) verty[i] = Tofloat(latlng[1]) } i, j := 0, nvert-1 c := false for i < nvert { if ((verty[i] > zlng) != (verty[j] > zlng)) && (zlat < (vertx[j]-vertx[i])*(zlng-verty[i])/(verty[j]-verty[i])+vertx[i]) { c = !c } j = i i++ } return c } func RunCmd(name string, arg ...string) []string { cmd := exec.Command(name, arg...) var out bytes.Buffer cmd.Stdout = &out err := cmd.Run() if err != nil { fmt.Println("Error executing ps command:", err) return make([]string, 0) } return strings.Split(out.String(), "\n") } func Timems() int { return Toint(time.Now().UnixNano() / 1000000) } func Ismobile(mob string) bool { match, _ := regexp.MatchString("^1\\d{10}$", mob) return match } func Idcard(str string) (map[string]string, error) { str = strings.ToLower(strings.TrimSpace(str)) if str == "" { return nil, fmt.Errorf("身份证未输入") } if len(str) != 18 { return nil, fmt.Errorf("身份证长度错误") } province := []string{"11", "12", "13", "14", "15", "21", "22", "23", "31", "32", "33", "34", "35", "36", "37", "41", "42", "43", "44", "45", "46", "50", "51", "52", "53", "54", "61", "62", "63", "64", "65", "71", "81", "82", "91"} if !strings.Contains(strings.Join(province, ""), str[:2]) { return nil, fmt.Errorf("身份证地区不合法") } birthyear := str[6:10] birthmonth := str[10:12] birthday := str[12:14] birth := birthyear + "-" + birthmonth + "-" + birthday stamp := Tostamp(birth) if Todate(stamp, "Y-m-d") != birth { return nil, fmt.Errorf("身份证生日错误") } if stamp > Tostamp() { return nil, fmt.Errorf("身份证生日不能超过今天") } ahead17_char := str[:17] last_char := str[17:] factor := []int{7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2} c := []string{"1", "0", "x", "9", "8", "7", "6", "5", "4", "3", "2"} t_res := 0 for i := 0; i < 17; i++ { t_res += int(ahead17_char[i]) * factor[i] } calc_last_char := c[t_res%11] if last_char != calc_last_char { return nil, fmt.Errorf("身份证校验位错误") } sex := Toint(str[16:17]) if sex%2 == 0 { sex = 2 } else { sex = 1 } return map[string]string{"code": str, "birth": birth, "sex": Tostr(sex), "area": str[:6]}, nil } func Iduscc(uscc string) (map[string]string, error) { uscc = strings.ToUpper(strings.TrimSpace(uscc)) if uscc == "" { return nil, fmt.Errorf("统一社会信用代码未输入") } if len(uscc) != 18 { return nil, fmt.Errorf("统一社会信用代码不是18位") } province := []string{"11", "12", "13", "14", "15", "21", "22", "23", "31", "32", "33", "34", "35", "36", "37", "41", "42", "43", "44", "45", "46", "50", "51", "52", "53", "54", "61", "62", "63", "64", "65", "71", "81", "82", "91"} if In_array(province, uscc[2:4]) == -1 { return nil, fmt.Errorf("统一社会信用代码地区不合法") } lcrc := _tsucc(uscc[:17]) if Tostr(uscc[17]) != lcrc { return nil, fmt.Errorf("统一社会信用代码校验位错误") } return map[string]string{"code": uscc, "area": uscc[2:8], "pn": uscc[:2]}, nil } func _tsucc(usc string) string { list := map[string]int{"0": 0, "1": 1, "2": 2, "3": 3, "4": 4, "5": 5, "6": 6, "7": 7, "8": 8, "9": 9, "A": 10, "B": 11, "C": 12, "D": 13, "E": 14, "F": 15, "G": 16, "H": 17, "J": 18, "K": 19, "L": 20, "M": 21, "N": 22, "P": 23, "Q": 24, "R": 25, "T": 26, "U": 27, "W": 28, "X": 29, "Y": 30} listf := map[int]string{} for k, v := range list { listf[v] = k } wi := []int{1, 3, 9, 27, 19, 26, 16, 17, 20, 29, 25, 13, 8, 24, 10, 30, 28} num := 0 for i := 0; i < 17; i++ { num += list[usc[i:i]] * wi[i] } result := 0 switch num % 31 { case 0: result = 0 default: result = 31 - num%31 } return listf[result] } func CiySign(str string, key string) string { h := hmac.New(sha256.New, []byte(key)) h.Write([]byte(str)) signature := h.Sum(nil) sid := fmt.Sprintf("%x", signature) sid = sid[:16] sid = strings.ReplaceAll(sid, "d", "p") sid = strings.ReplaceAll(sid, "e", "z") sid = strings.ReplaceAll(sid, "f", "m") return sid } /* * ******************************************************************* * 函数名称:encrypt * 函数作用:加密解密字符串 * 安全函数,建议有能力自行修改一些,源码不泄露,很难猜算法。 * 使用方法: * 加密 :encrypt('str','E','nowamagic'); * 解密 :encrypt('被加密过的字符串','D','nowamagic'); * 参数说明: * $string :需要加密解密的字符串 * $operation:判断是加密还是解密:E:加密 D:解密 * $key :加密的钥匙(密匙); * ******************************************************************* */ // authstr := "加密字串" // enstr := Encrypt(authstr, "E", p.Project_Commonkey) // destr := Encrypt(enstr, "D", p.Project_Commonkey) // Clog(authstr == destr, authstr, enstr, destr) func Encrypt(str string, operation string, argkey ...string) string { key := "" if len(argkey) > 0 { key = argkey[0] } keybyt := MD5Byte([]byte(key)) strbyt := []byte(str) key_length := len(keybyt) var byts []byte if operation == "D" { var err error byts, err = base64.StdEncoding.DecodeString(strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(str, "*", "="), "-", "+"), "_", "/")[1:]) if err != nil { return "" } } else { mdbyt := MD5Byte(strbyt, keybyt) var buffer2 bytes.Buffer buffer2.Write(mdbyt[:8]) buffer2.Write(strbyt) byts = buffer2.Bytes() } string_length := len(byts) rndkey := make([]byte, 256) box := make([]byte, 256) result := make([]byte, 0) for i := 0; i < 256; i++ { rndkey[i] = keybyt[i%key_length] box[i] = uint8(i) } for j, i := 0, 0; i < 256; i++ { j = int(j+int(box[i])+int(rndkey[i])) % 256 tmp := box[i] box[i] = box[j] box[j] = tmp } for a, j, i := 0, 0, 0; i < string_length; i++ { a = (a + 1) % 256 j = (j + int(box[a])) % 256 tmp := box[a] box[a] = box[j] box[j] = tmp result = append(result, byts[i]^box[(int(box[a])+int(box[j]))%256]) } if operation == "D" { if bytes.Equal(result[:8], MD5Byte(result[8:], keybyt)[:8]) { return string(result[8:]) } else { return "" } } else { return "1" + strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(base64.StdEncoding.EncodeToString(result), "=", "*"), "+", "-"), "/", "_") } } /* * ******************************************************************* * 函数名称:enid/deid * 函数作用:id加密函数/id解密函数。 * 安全函数,建议有能力自行修改一些 * 参数说明: * $id 两位数的数字id(id>=10) * 返回值:加密后的数字 * 例:enid(8245) = 872435 * 例:deid(872435) = 8245 * ******************************************************************* */ func EnID(id int, argkey ...int) string { key := 253 if len(argkey) > 0 { key = argkey[0] } strid := "" if id <= 0 { return "0" } if id < 10 { strid = "0" + Tostr(id) } else { strid = Tostr(id) } fx := _calnumber(id, key) ulen := len(strid) return strid[:1] + fx[0:1] + strid[1:ulen-1] + fx[1:] + strid[len(strid)-1:] } func DeID(strid string, argkey ...int) int { key := 253 if len(argkey) > 0 { key = argkey[0] } ulen := len(strid) fx := strid[1:2] + strid[ulen-2:ulen-1] id := Toint(strid[:1] + strid[2:ulen-2] + strid[ulen-1:]) if fx == _calnumber(id, key) { return id } return 0 } /* * ******************************************************************* * 函数名称:calnumber * 函数作用:换算id的加密校验数,被enid、deid函数调用。 * 参数说明: * $key 默认加密因子,可以自行修改。尽量用奇数100-1000 * $len 返回校验数位数。 * 返回值:len位数字字符串 * 例:calnumber(8245,224,2) = 73 * ******************************************************************* */ func _calnumber(num, key int) string { len := 2 if num > 250600 { num %= 250600 } n := num % 8566 if n < 100 { n += 100 } xx := num*n + key if xx < 0 { xx = -xx } if xx%13 > 8 { xx += key } if xx%13 > 4 { xx += key + key + key } ret := xx % Toint(math.Pow(10, Tofloat(len))) if ret < 0 { ret = -ret } return fmt.Sprintf("%0"+Tostr(len)+"d", ret) } func Conv33_10(num string) int { n := 33 var new_num float64 new_num = 0.0 nNum := len(strings.Split(num, "")) - 1 for _, value := range strings.Split(num, "") { tmp := -1 var nummap map[int]string = map[int]string{0: "a", 1: "b", 2: "c", 3: "d", 4: "e", 5: "f", 6: "g", 7: "h", 8: "i", 9: "j", 10: "k", 11: "m", 12: "n", 13: "p", 14: "q", 15: "r", 16: "s", 17: "t", 18: "u", 19: "v", 20: "w", 21: "x", 22: "y", 23: "z", 24: "1", 25: "2", 26: "3", 27: "4", 28: "5", 29: "6", 30: "7", 31: "8", 32: "9"} for k, v := range nummap { if value == v { tmp = k } } if tmp != -1 { new_num = new_num + float64(tmp)*math.Pow(float64(n), float64(nNum)) nNum = nNum - 1 } else { break } } return int(new_num) } func Conv10_33(num int) string { var nummap map[int]string = map[int]string{0: "a", 1: "b", 2: "c", 3: "d", 4: "e", 5: "f", 6: "g", 7: "h", 8: "i", 9: "j", 10: "k", 11: "m", 12: "n", 13: "p", 14: "q", 15: "r", 16: "s", 17: "t", 18: "u", 19: "v", 20: "w", 21: "x", 22: "y", 23: "z", 24: "1", 25: "2", 26: "3", 27: "4", 28: "5", 29: "6", 30: "7", 31: "8", 32: "9"} n := 33 new_num_str := "" var remainder int var remainder_string string for num != 0 { remainder = num % n if 76 > remainder && remainder > 9 { remainder_string = nummap[remainder] } else { remainder_string = strconv.Itoa(remainder) } new_num_str = remainder_string + new_num_str num = num / n } return new_num_str } func MD5file(file string) string { f, err := os.Open(file) if err != nil { return "" } defer f.Close() h := md5.New() if _, err := io.Copy(h, f); err != nil { return "" } return hex.EncodeToString(h.Sum(nil)) } func MD5(src string) string { h := md5.New() h.Write([]byte(src)) return hex.EncodeToString(h.Sum(nil)) } func MD5Byte(src ...[]byte) []byte { h := md5.New() for _, byt := range src { h.Write(byt) } return h.Sum(nil) } func Sha256(src string) string { hash := sha256.Sum256([]byte(src)) return hex.EncodeToString(hash[:]) } func Sha512(src string) string { hash := sha512.Sum512([]byte(src)) return hex.EncodeToString(hash[:]) } func Uniqid(length int) string { numbers := make([]byte, length) for i := range numbers { numbers[i] = byte(rand.Intn(256)) } return fmt.Sprintf("%x", numbers) } func Array_unshift[T string | any](arr []T, value T, arginpoint ...int) []T { if arr == nil { return []T{value} } size := len(arr) newArr := make([]T, size+1) inpoint := 0 if len(arginpoint) > 0 { inpoint = arginpoint[0] } for i := 0; i < inpoint; i++ { newArr[i] = arr[i] } newArr[inpoint] = value for i := inpoint; i < size; i++ { newArr[i+1] = arr[i] } return newArr } func In_array[T string | int | float64](arr []T, val T) int { for i, v := range arr { if v == val { return i } } return -1 } func Array_rand[T string | int | float64 | any](arr []T, num int) []T { retarr := make([]T, num) if len(arr) < num { num = len(arr) } for i := 0; i < num; i++ { ind := rand.Intn(len(arr)) retarr[i] = arr[ind] arr = append(arr[:ind], arr[ind+1:]...) } return retarr } func Startwith(str string, suf string) bool { return strings.HasPrefix(str, suf) } func Endwith(str string, suf string) bool { return strings.HasSuffix(str, suf) } func Strpos_first(search string, offset int, findstrs ...string) (int, string, string) { ind := strings.IndexAny(search[offset:], strings.Join(findstrs, "")) if ind == -1 { return -1, "", "" } ind += offset f_str := search[ind : ind+1] ind2 := strings.Index(search[ind+1:], f_str) if ind2 > -1 { ind2 += ind + 1 return ind, f_str, search[ind+1 : ind2] } return ind, f_str, "" } func Gb_substr(str string, length int, argdot ...string) string { dot := "" if len(argdot) > 0 { dot = argdot[0] } ret := "" for _, v := range str { if unicode.Is(unicode.Han, v) { length-- } length-- ret += string(v) if length <= 0 { ret += dot break } } return ret } func Gb_strlen(str string) int { count := 0 for _, v := range str { if unicode.Is(unicode.Han, v) { count++ } count++ } return count } func Gb_haschinese(str string) bool { for _, v := range str { if unicode.Is(unicode.Han, v) { return true } } return false } func Getstrparam(pstr string, argsplit ...string) map[string]string { jsn := map[string]string{} split := "|" if len(argsplit) > 0 { split = argsplit[0] } pstrs := strings.Split(pstr, split) for _, str := range pstrs { ind := strings.Index(str, "=") if ind > 0 { jsn[strings.TrimSpace(str[:ind])] = strings.TrimSpace(str[ind+1:]) } else { jsn[strings.TrimSpace(str)] = "" } } return jsn } func Setstrparam(parr map[string]string, argsplit ...string) string { rets := make([]string, 0) split := "|" if len(argsplit) > 0 { split = argsplit[0] } for k, v := range parr { rets = append(rets, k+"="+v) } return strings.Join(rets, split) } func FieldAdd(field *map[string]map[string]any, fshow *string, inpoint int, fname string, comment string) { (*field)[fname] = map[string]any{ "c": comment, } fshows := strings.Split(*fshow, ",") if inpoint == -1 { if len(fshows[0]) == 0 { fshows[0] = fname } else { fshows = append(fshows, fname) } } else { fshows = Array_unshift(fshows, fname, inpoint) } *fshow = strings.Join(fshows, ",") } // Getrelation(CiyDB, rows, "xx_user", "xxid", map[string]string{"column": "id,name"}, map[string]string{"queryid": "id"}) func Getrelation(db *CiyMysql, rows []map[string]any, table string, field string, argopn ...map[string]string) []map[string]any { column := "id,name" queryid := "id" if len(argopn) > 0 { for _, arg := range argopn { if v, ok := arg["column"]; ok { column = v } if v, ok := arg["queryid"]; ok { queryid = v } } } ids := []string{} for _, row := range rows { ids = append(ids, Tostr(row[field])) } if len(ids) == 0 { return []map[string]any{} } csql := NewCiySQL(table) csql.Where(queryid+" in ", strings.Join(ids, ",")) csql.Column(column) rows2, _, err := db.Get(csql) if err != nil { return []map[string]any{} } return rows2 } func Delcheck(db *CiyMysql, delid int, table, field, msg string) { csql := NewCiySQL(table) csql.Where(field, delid) cnt := Toint(db.Get1(csql)) if cnt > 0 { panic(fmt.Sprintf("存在%d个%v,不能删除", cnt, msg)) } } func Delall(db *CiyMysql, delid int, table, field, msg string) { csql := NewCiySQL(table) csql.Where(field, delid) _, err := db.Delete(csql) if err != nil { panic(msg + "删除失败:" + err.Error()) } } func Delme(db *CiyMysql, delid int, table string) { csql := NewCiySQL(table) csql.Where("id", delid) _, err := db.Delete(csql) if err != nil { panic("删除失败:" + err.Error()) } } func Mapid2data(datas []map[string]any) map[int]map[string]any { ret := map[int]map[string]any{} for _, data := range datas { ret[Toint(data["id"])] = data } return ret } func Ccode(rows []map[string]any, code int) string { showcode := "id" showtitle := "name" for _, row := range rows { if code == Toint(row[showcode]) { return Tostr(row[showtitle]) } } return "--" } func Mcode(rows []map[string]any, code int) []string { showcode := "id" showtitle := "name" upcode := "upid" codes := make([]string, 0) for i := 0; i < 10; i++ { if code <= 0 { break } bfind := false for _, row := range rows { if code == Toint(row[showcode]) { codes = append(codes, Tostr(row[showtitle])) code = Toint(row[upcode]) bfind = true break } } if !bfind { break } } lencode := len(codes) ret := make([]string, lencode) for i := 0; i < lencode; i++ { ret[i] = codes[lencode-1-i] } return ret } func Scode(rows []map[string]any, code string) []string { showcode := "id" showtitle := "name" rets := make([]string, 0) codes := strings.Split(code, ",") for _, c := range codes { if c == "" { continue } for _, row := range rows { if c == row[showcode] { rets = append(rets, Tostr(row[showtitle])) break } } } return rets } func Dcode(rows []map[string]any, codename string) int { showcode := "id" showtitle := "name" for _, row := range rows { if codename == row[showtitle] { return Toint(row[showcode]) } } return -1 } func LogDBStr(oldrow map[string]any, newrow map[string]any) string { msg := "" if oldrow != nil && newrow != nil { msg = "Upd=" + Tostr(oldrow["id"]) modify := false for f, v := range newrow { if _, ok := oldrow[f]; !ok { continue } if oldrow[f] != v { msg += "_|@|_" + f + "=" + Tostr(oldrow[f]) + "→" + Tostr(v) modify = true } } if !modify { return "" } } else if newrow != nil { msg = "Ins=" + Tostr(newrow["newid"]) for f, v := range newrow { if f == "newid" || f == "id" { continue } msg += "_|@|_" + f + "=" + Tostr(v) } } else if oldrow != nil { msg = "Del=" + Tostr(oldrow["id"]) for f, v := range oldrow { if f == "id" { continue } msg += "_|@|_" + f + "=" + Tostr(v) } } else { return "" } return msg } func DirMake(dir string, argpower ...int) error { power := 0777 if len(argpower) > 0 { power = argpower[0] } if dir == "" { return fmt.Errorf("DirMake Error:dir is empty") } err := DirExist(dir) if err == nil { return nil } err = os.MkdirAll(dir, os.ModeDir) if err != nil { err = fmt.Errorf("dirMake Error:%v[%v]", err, dir) Log.Error("DIR", err.Error()) return err } err = syscall.Chmod(dir, uint32(power)) if err != nil { err = fmt.Errorf("dirMake setting permissions Error:%v[%v]", err, dir) Log.Error("DIR", err.Error()) return err } return nil } func FileDel(file string) error { err := os.Remove(file) if err != nil { if !os.IsNotExist(err) { err = fmt.Errorf("Delete Error:%v[%v]", err, file) Log.Error("FILE", err.Error()) return err } } return nil } func FileCopy(srcfile string, dstfile string) error { srcF, err := os.Open(srcfile) if err != nil { err = fmt.Errorf("copy open error:%v[%v]", err, srcfile) Log.Error("FILE", err.Error()) return err } defer srcF.Close() reader := bufio.NewReader(srcF) dstF, err := os.OpenFile(dstfile, os.O_WRONLY|os.O_CREATE, 0644) if err != nil { err = fmt.Errorf("copy create error:%v[%v]", err, dstfile) Log.Error("FILE", err.Error()) return err } defer dstF.Close() writer := bufio.NewWriter(dstF) _, err = io.Copy(writer, reader) if err != nil { err = fmt.Errorf("copy write error:%v[%v][%v]", err, srcfile, dstfile) Log.Error("FILE", err.Error()) return err } return nil } func FileSave(filename string, text any) error { f, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644) if err != nil { return err } defer f.Close() writer := bufio.NewWriter(f) switch v := text.(type) { case string: _, err = writer.WriteString(v) case []byte: _, err = writer.Write(v) case []string: for _, s := range v { _, err = writer.WriteString(s) if err != nil { return err } } default: _, err = writer.WriteString(Tostr(v)) } if err != nil { return err } err = writer.Flush() if err != nil { return err } return nil } func FileLoad(filename string) []string { f, err := os.Open(filename) if err != nil { return nil } defer f.Close() scanner := bufio.NewScanner(f) scanner.Split(bufio.ScanLines) lines := make([]string, 0) for scanner.Scan() { lines = append(lines, scanner.Text()) } return lines } func DirExist(pathname string) error { info, err := os.Stat(pathname) if err != nil { return err } if info.IsDir() { return nil } return fmt.Errorf("%s is not a directory", pathname) } func FileExist(filename string) error { if _, err := os.Stat(filename); err == nil { return nil } else if os.IsNotExist(err) { return err } return fmt.Errorf("%s is not a file", filename) } func Fileext(file string) (string, string) { ind := strings.LastIndex(file, ".") if ind == -1 { return file, "" } return file[:ind], strings.ToLower(file[ind+1:]) }