c5_labsci/zciyon/c.go
2026-01-27 00:52:00 +08:00

1345 lines
33 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
=================================================================================
* 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 两位数的数字idid>=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:])
}