package xstring import ( "bytes" "encoding/base64" "encoding/json" "fmt" "github.com/pkg/errors" "reflect" "regexp" "sort" "strconv" "strings" "unicode" ) func TableFieldNames(obj any) ([]string, string) { v := reflect.TypeOf(obj) cols := []string{} primary := "" for i := 0; i < v.NumField(); i++ { cols = append(cols, v.Field(i).Tag.Get("db")) if primary == "" { primary = v.Field(i).Tag.Get("primaryKey") } } return cols, primary } func Remove[T string](cols []T, key T) []T { arr := make([]T, 0) for _, v := range cols { if key != v { arr = append(arr, v) } } return arr } func NamedSql(cls []string) string { str := []string{} for _, v := range cls { str = append(str, fmt.Sprintf("%s=:%s", v, v)) } return strings.Join(str, ",") } func StripTags(content string) string { re := regexp.MustCompile(`<(.|\n)*?>`) return re.ReplaceAllString(content, "") } func SubString(str string, begin, length int) string { rs := []rune(str) lth := len(rs) if begin < 0 { begin = 0 } if begin >= lth { begin = lth } end := begin + length if end > lth { end = lth } return string(rs[begin:end]) } func Nl2br(str string) string { return strings.Join(strings.Split(strings.Join(strings.Split(str, "\r"), "
"), "\n"), "
") } func Serialize(value interface{}) ([]byte, error) { if value == nil { return MarshalNil(), nil } t := reflect.TypeOf(value) switch t.Kind() { case reflect.Bool: return MarshalBool(value.(bool)), nil case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64: return MarshalNumber(value), nil case reflect.String: return MarshalString(value.(string)), nil case reflect.Map: return MarshalMap(value) case reflect.Slice: return MarshalSlice(value) default: return nil, fmt.Errorf("Marshal: Unknown type %T with value %#v", t, value) } } func MarshalNil() []byte { return []byte("N;") } func MarshalBool(value bool) []byte { if value { return []byte("b:1;") } return []byte("b:0;") } func MarshalNumber(value interface{}) []byte { var val string isFloat := false switch value.(type) { default: val = "0" case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64: val, _ = NumericalToString(value) case float32, float64: val, _ = NumericalToString(value) isFloat = true } if isFloat { return []byte("d:" + val + ";") } else { return []byte("i:" + val + ";") } } func NumericalValue(value reflect.Value) (float64, bool) { switch value.Type().Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return float64(value.Int()), true case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: return float64(value.Uint()), true case reflect.Float32, reflect.Float64: return value.Float(), true default: return 0, false } } func MarshalString(value string) []byte { return []byte(fmt.Sprintf("s:%d:\"%s\";", len(value), value)) } func LessValue(a, b reflect.Value) bool { aValue, aNumerical := NumericalValue(a) bValue, bNumerical := NumericalValue(b) if aNumerical && bNumerical { return aValue < bValue } if !aNumerical && !bNumerical { // In theory this should mean they are both strings. In reality // they could be any other type and the String() representation // will be something like "" if it is not a string. Since // distinct values of non-strings still return the same value // here that's what makes the ordering undefined. return strings.Compare(a.String(), b.String()) < 0 } // Numerical values are always treated as less than other types // (including strings that might represent numbers themselves). The // inverse is also true. return aNumerical && !bNumerical } func MarshalMap(value interface{}) ([]byte, error) { s := reflect.ValueOf(value) mapKeys := s.MapKeys() sort.Slice(mapKeys, func(i, j int) bool { return LessValue(mapKeys[i], mapKeys[j]) }) var buffer bytes.Buffer for _, mapKey := range mapKeys { m, err := Serialize(mapKey.Interface()) if err != nil { return nil, err } buffer.Write(m) m, err = Serialize(s.MapIndex(mapKey).Interface()) if err != nil { return nil, err } buffer.Write(m) } return []byte(fmt.Sprintf("a:%d:{%s}", s.Len(), buffer.String())), nil } func MarshalSlice(value interface{}) ([]byte, error) { s := reflect.ValueOf(value) var buffer bytes.Buffer for i := 0; i < s.Len(); i++ { m, err := Serialize(i) if err != nil { return nil, err } buffer.Write(m) m, err = Serialize(s.Index(i).Interface()) if err != nil { return nil, err } buffer.Write(m) } return []byte(fmt.Sprintf("a:%d:{%s}", s.Len(), buffer.String())), nil } const UNSERIALIZABLE_OBJECT_MAX_LEN = int64(10 * 1024 * 1024 * 1024) func UnSerialize(data []byte) (interface{}, error) { reader := bytes.NewReader(data) return unMarshalByReader(reader) } func UnSerializeBind(data []byte, post any) error { reader := bytes.NewReader(data) b, err := unMarshalByReader(reader) if err != nil { return err } bb, err := json.Marshal(b) if err != nil { return err } return json.Unmarshal(bb, post) } func unMarshalByReader(reader *bytes.Reader) (interface{}, error) { for { if token, _, err := reader.ReadRune(); err == nil { switch token { default: return nil, fmt.Errorf("UnMarshal: Unknown token %#U", token) case 'N': return unMarshalNil(reader) case 'b': return unMarshalBool(reader) case 'i': return unMarshalNumber(reader, false) case 'd': return unMarshalNumber(reader, true) case 's': return unMarshalString(reader, true) case 'a': return unMarshalArray(reader) // case 'O': // case 'C': // case 'R', 'r': // case 'x': } } } } func unMarshalNil(reader *bytes.Reader) (interface{}, error) { _ = expect(reader, ';') return nil, nil } func unMarshalBool(reader *bytes.Reader) (interface{}, error) { var ( raw rune err error ) err = expect(reader, ':') if err != nil { return nil, err } if raw, _, err = reader.ReadRune(); err != nil { return nil, fmt.Errorf("UnMarshal: Error while reading bool value: %v", err) } err = expect(reader, ';') if err != nil { return nil, err } return raw == '1', nil } func unMarshalNumber(reader *bytes.Reader, isFloat bool) (interface{}, error) { var ( raw string err error val interface{} ) err = expect(reader, ':') if err != nil { return nil, err } if raw, err = readUntil(reader, ';'); err != nil { return nil, fmt.Errorf("UnMarshal: Error while reading number value: %v", err) } else { if isFloat { if val, err = strconv.ParseFloat(raw, 64); err != nil { return nil, fmt.Errorf("UnMarshal: Unable to convert %s to float: %v", raw, err) } } else { if val, err = strconv.Atoi(raw); err != nil { return nil, fmt.Errorf("UnMarshal: Unable to convert %s to int: %v", raw, err) } } } return val, nil } func unMarshalString(reader *bytes.Reader, isFinal bool) (interface{}, error) { var ( err error val interface{} strLen int readLen int ) strLen, err = readLength(reader) if err != nil { return nil, err } err = expect(reader, '"') if err != nil { return nil, err } if strLen > 0 { buf := make([]byte, strLen) if readLen, err = reader.Read(buf); err != nil { return nil, fmt.Errorf("UnMarshal: Error while reading string value: %v", err) } else { if readLen != strLen { return nil, fmt.Errorf("UnMarshal: Unable to read string. Expected %d but have got %d bytes", strLen, readLen) } else { val = string(buf) } } } err = expect(reader, '"') if err != nil { return nil, err } if isFinal { err = expect(reader, ';') if err != nil { return nil, err } } return val, nil } func unMarshalArray(reader *bytes.Reader) (interface{}, error) { var arrLen int var err error val := make(map[string]interface{}) arrLen, err = readLength(reader) if err != nil { return nil, err } err = expect(reader, '{') if err != nil { return nil, err } indexLen := 0 for i := 0; i < arrLen; i++ { k, err := unMarshalByReader(reader) if err != nil { return nil, err } v, err := unMarshalByReader(reader) if err != nil { return nil, err } // if errKey == nil && errVal == nil { // val[k] = v switch t := k.(type) { default: return nil, fmt.Errorf("UnMarshal: Unexpected key type %T", t) case string: stringKey, _ := k.(string) val[stringKey] = v case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64: // intKey, _ := k.(int) // val[strconv.Itoa(intKey)] = v stringKey, _ := NumericalToString(k) val[stringKey] = v // stringI, _ := utils.NumericalToString(i) if i == k { indexLen++ } } // } else { // return nil, fmt.Errorf("UnMarshal: Error while reading key or(and) value of array") // } } err = expect(reader, '}') if err != nil { return nil, err } if indexLen == arrLen { var slice []interface{} for _, row := range val { slice = append(slice, row) } return slice, nil } return val, nil } func expect(reader *bytes.Reader, expected rune) error { if token, _, err := reader.ReadRune(); err != nil { return fmt.Errorf("UnMarshal: Error while reading expected rune %#U: %v", expected, err) } else if token != expected { return fmt.Errorf("UnMarshal: Expected %#U but have got %#U", expected, token) } return nil } func readUntil(reader *bytes.Reader, stop rune) (string, error) { var ( token rune err error ) buf := bytes.NewBuffer([]byte{}) for { if token, _, err = reader.ReadRune(); err != nil || token == stop { break } else { buf.WriteRune(token) } } return buf.String(), err } func readLength(reader *bytes.Reader) (int, error) { var ( raw string err error val int ) err = expect(reader, ':') if err != nil { return 0, err } if raw, err = readUntil(reader, ':'); err != nil { return 0, fmt.Errorf("UnMarshal: Error while reading lenght of value: %v", err) } else { if val, err = strconv.Atoi(raw); err != nil { return 0, fmt.Errorf("UnMarshal: Unable to convert %s to int: %v", raw, err) } else if int64(val) > UNSERIALIZABLE_OBJECT_MAX_LEN { return 0, fmt.Errorf("UnMarshal: Unserializable object length looks too big(%d). If you are sure you wanna unserialise it, please increase UNSERIALIZABLE_OBJECT_MAX_LEN const", val) } } return val, nil } func NumericalToString(value interface{}) (string, bool) { var val string switch intVal := value.(type) { default: return "0", false case int: val = strconv.FormatInt(int64(intVal), 10) case int8: val = strconv.FormatInt(int64(intVal), 10) case int16: val = strconv.FormatInt(int64(intVal), 10) case int32: val = strconv.FormatInt(int64(intVal), 10) case int64: val = strconv.FormatInt(int64(intVal), 10) case uint: val = strconv.FormatUint(uint64(intVal), 10) case uint8: val = strconv.FormatUint(uint64(intVal), 10) case uint16: val = strconv.FormatUint(uint64(intVal), 10) case uint32: val = strconv.FormatUint(uint64(intVal), 10) case uint64: val = strconv.FormatUint(intVal, 10) case float32: val = strconv.FormatFloat(float64(intVal), 'f', -1, 32) case float64: val = strconv.FormatFloat(intVal, 'f', -1, 64) } return val, true } //func StrToArr(str string) []string { // re := regexp.MustCompile(`<(.|\n)*?>`) // str = re.ReplaceAllString(str, " ") // str = strings.ReplaceAll(str, `"`, "") // str = strings.ReplaceAll(str, `'`, "") // str = strings.ReplaceAll(str, "`", "") // str = strings.ReplaceAll(str, ",", "") // str = strings.ReplaceAll(str, " ", "") // newStr := []string{} // tmp := "" // for i := 0; i < len(str); { // r, n := utf8.DecodeRuneInString(str[i:]) // if n == 3 { // tmp = "" // newStr = append(newStr, string(r)) // } else { // // if string(r) == " " { // newStr = append(newStr, tmp) // tmp = "" // } else if string(r) != "\n" { // tmp = fmt.Sprintf("%s%c", tmp, r) // } // } // i += n // } // if tmp != "" { // newStr = append(newStr, tmp) // tmp = "" // } // newStr1 := make([]string, 0) // for _, v := range newStr { // if strings.TrimSpace(v) == "" { // continue // } // newStr1 = append(newStr1, strings.TrimSpace(v)) // } // return newStr1 //} //func StrToUrl(str string) string { // strs := []string{} // for _, v := range StrToArr(str) { // fmt.Println(v) // } // // return strings.Join(strs, "-") //} func Base64Encode(s string) string { return base64.StdEncoding.EncodeToString([]byte(s)) } func Base64Decode(s string) (string, error) { b, err := base64.StdEncoding.DecodeString(s) if err != nil { return "", errors.Wrap(err, "") } return string(b), nil } func Ucfirst(str string) string { for i, v := range str { return string(unicode.ToUpper(v)) + str[i+1:] } return "" } func Lcfirst(str string) string { for i, v := range str { return string(unicode.ToLower(v)) + str[i+1:] } return "" } func GetUrlRequestURI(url string) string { urls := strings.Split(url, "?") urls = strings.Split(urls[0], " ") if len(urls) > 1 { return urls[1] } return "" } func CoverInt64(str string) int64 { i, _ := strconv.ParseInt(str, 10, 64) return i } func ToInterfaceSlice(slice interface{}) []interface{} { s := reflect.ValueOf(slice) if s.Kind() != reflect.Slice { panic("InterfaceSlice() given a non-slice type") } ret := make([]interface{}, s.Len()) for i := 0; i < s.Len(); i++ { ret[i] = s.Index(i).Interface() } return ret }