first commit

This commit is contained in:
zzw
2026-08-05 17:37:32 +08:00
commit 38be479cef
72 changed files with 15670 additions and 0 deletions
+317
View File
@@ -0,0 +1,317 @@
package utils
import (
"fmt"
"strconv"
"strings"
)
// PHPValue 定义 PHP 序列化值的类型(兼容字符串、整数、数组)
type PHPValue interface{}
// PHPDecode 原生解析 PHP 序列化字符串为 map[string]PHPValue
func PHPDecode(serialized string) (map[string]PHPValue, error) {
// 预处理:去除首尾空白
serialized = strings.TrimSpace(serialized)
// 验证是否为 PHP 数组格式(a:N:{...}
if !strings.HasPrefix(serialized, "a:") {
return nil, fmt.Errorf("不是 PHP 数组格式")
}
// 提取数组内容(去掉外层 a:N:{ 和 末尾的 })
colonIdx := strings.Index(serialized, ":")
if colonIdx == -1 {
return nil, fmt.Errorf("格式错误:缺少冒号")
}
braceOpenIdx := strings.Index(serialized, "{")
if braceOpenIdx == -1 {
return nil, fmt.Errorf("格式错误:缺少左大括号")
}
content := serialized[braceOpenIdx+1 : len(serialized)-1]
// 递归解析数组内容
result := make(map[string]PHPValue)
idx := 0
contentLen := len(content)
for idx < contentLen {
// 跳过空白字符
for idx < contentLen && (content[idx] == ' ' || content[idx] == '\t' || content[idx] == '\n') {
idx++
}
if idx >= contentLen {
break
}
// 解析 Key
key, keyEndIdx, err := parsePHPValueAt(content, idx)
if err != nil {
return nil, fmt.Errorf("解析 Key 失败:%v", err)
}
idx = keyEndIdx + 1 // 跳过 Key 后的分号
// 解析 Value
val, valEndIdx, err := parsePHPValueAt(content, idx)
if err != nil {
return nil, fmt.Errorf("解析 Value 失败:%v", err)
}
idx = valEndIdx + 1 // 跳过 Value 后的分号
// 将 Key 转为字符串并存入结果
var keyStr string
switch k := key.(type) {
case string:
keyStr = k
case int:
keyStr = strconv.Itoa(k)
default:
keyStr = fmt.Sprintf("%v", k)
}
result[keyStr] = val
}
return result, nil
}
// parsePHPValueAt 从指定索引解析单个 PHP 序列化值
func parsePHPValueAt(s string, start int) (PHPValue, int, error) {
if start >= len(s) {
return nil, -1, fmt.Errorf("索引越界")
}
// 根据类型前缀解析
switch s[start] {
case 's': // 字符串类型:s:长度:"内容";
return parsePHPString(s, start)
case 'i': // 整数类型:i:数值;
return parsePHPInt(s, start)
case 'a': // 数组类型:a:长度:{...};
return parsePHPArray(s, start)
default:
return nil, -1, fmt.Errorf("不支持的类型:%c", s[start])
}
}
// parsePHPString 解析 PHP 字符串类型(s:len:"value"
func parsePHPString(s string, start int) (string, int, error) {
// 格式:s:3:"abc";
// 1. 跳过 "s:"
if len(s) < start+2 || s[start:start+2] != "s:" {
return "", -1, fmt.Errorf("不是字符串类型")
}
idx := start + 2
// 2. 解析长度
lenStr := ""
for idx < len(s) && s[idx] != ':' {
lenStr += string(s[idx])
idx++
}
if idx >= len(s) || s[idx] != ':' {
return "", -1, fmt.Errorf("字符串长度解析失败")
}
strLen, err := strconv.Atoi(lenStr)
if err != nil {
return "", -1, fmt.Errorf("长度不是数字:%v", err)
}
idx++ // 跳过冒号
// 3. 跳过引号
if idx >= len(s) || s[idx] != '"' {
return "", -1, fmt.Errorf("缺少字符串起始引号")
}
idx++
// 4. 提取字符串内容
endIdx := idx + strLen
if endIdx > len(s) {
return "", -1, fmt.Errorf("字符串长度不足")
}
strVal := s[idx:endIdx]
idx = endIdx
// 5. 跳过结束引号和分号
if idx >= len(s) || s[idx] != '"' {
return "", -1, fmt.Errorf("缺少字符串结束引号")
}
idx++
if idx >= len(s) || s[idx] != ';' {
return "", -1, fmt.Errorf("缺少字符串结束分号")
}
return strVal, idx, nil
}
// parsePHPInt 解析 PHP 整数类型(i:123;
func parsePHPInt(s string, start int) (int, int, error) {
// 格式:i:123;
// 1. 跳过 "i:"
if len(s) < start+2 || s[start:start+2] != "i:" {
return 0, -1, fmt.Errorf("不是整数类型")
}
idx := start + 2
// 2. 解析数字
numStr := ""
for idx < len(s) && s[idx] != ';' {
numStr += string(s[idx])
idx++
}
if numStr == "" {
return 0, -1, fmt.Errorf("整数为空")
}
numVal, err := strconv.Atoi(numStr)
if err != nil {
return 0, -1, fmt.Errorf("整数解析失败:%v", err)
}
return numVal, idx, nil
}
// parsePHPArray 解析 PHP 数组类型(a:len:{...}
func parsePHPArray(s string, start int) (map[string]PHPValue, int, error) {
// 格式:a:2:{s:1:"k";i:123;s:1:"v";s:3:"abc";};
// 1. 跳过 "a:"
if len(s) < start+2 || s[start:start+2] != "a:" {
return nil, -1, fmt.Errorf("不是数组类型")
}
idx := start + 2
// 2. 解析数组长度(仅校验,实际按内容解析)
for idx < len(s) && s[idx] != ':' {
idx++
}
if idx >= len(s) || s[idx] != ':' {
return nil, -1, fmt.Errorf("数组长度解析失败")
}
idx++
// 3. 找到数组起始大括号
if idx >= len(s) || s[idx] != '{' {
return nil, -1, fmt.Errorf("缺少数组起始大括号")
}
idx++
// 4. 解析数组内容(递归调用 PHPDecode 的核心逻辑)
arrayContentStart := idx
depth := 1
arrayContentEnd := -1
// 找到匹配的结束大括号(处理嵌套数组)
for idx < len(s) && depth > 0 {
switch s[idx] {
case '{':
depth++
case '}':
depth--
if depth == 0 {
arrayContentEnd = idx
}
}
idx++
}
if arrayContentEnd == -1 {
return nil, -1, fmt.Errorf("数组缺少结束大括号")
}
// 5. 解析数组内容为 map
arrayContent := s[arrayContentStart:arrayContentEnd]
arrayResult := make(map[string]PHPValue)
innerIdx := 0
contentLen := len(arrayContent)
for innerIdx < contentLen {
// 跳过空白
for innerIdx < contentLen && (arrayContent[innerIdx] == ' ' || arrayContent[innerIdx] == '\t') {
innerIdx++
}
if innerIdx >= contentLen {
break
}
// 解析 Key
key, keyEnd, err := parsePHPValueAt(arrayContent, innerIdx)
if err != nil {
return nil, -1, fmt.Errorf("解析数组 Key 失败:%v", err)
}
innerIdx = keyEnd + 1 // 跳过分号
// 解析 Value
val, valEnd, err := parsePHPValueAt(arrayContent, innerIdx)
if err != nil {
return nil, -1, fmt.Errorf("解析数组 Value 失败:%v", err)
}
innerIdx = valEnd + 1 // 跳过分号
// 转换 Key 为字符串
var keyStr string
switch k := key.(type) {
case string:
keyStr = k
case int:
keyStr = strconv.Itoa(k)
default:
keyStr = fmt.Sprintf("%v", k)
}
arrayResult[keyStr] = val
}
// 6. 跳过数组结束后的分号
if idx < len(s) && s[idx] == ';' {
idx++
}
return arrayResult, idx - 1, nil // 返回数组结束的索引
}
// GetInt 从 map 中安全获取 int 类型值,失败返回默认值
func GetInt(m map[string]PHPValue, key string, defaultValue int) int {
val, ok := m[key]
if !ok {
return defaultValue
}
// 类型断言:将 interface{} 转为 int
num, ok := val.(int)
if !ok {
fmt.Printf("警告:%s 不是 int 类型,使用默认值 %d\n", key, defaultValue)
return defaultValue
}
return num
}
// GetString 从 map 中安全获取 string 类型值,失败返回默认值
func GetString(m map[string]PHPValue, key string, defaultValue string) string {
val, ok := m[key]
if !ok {
return defaultValue
}
// 类型断言:将 interface{} 转为 string
str, ok := val.(string)
if !ok {
fmt.Printf("警告:%s 不是 string 类型,使用默认值 %s\n", key, defaultValue)
return defaultValue
}
return str
}
// GetMap 从 map 中安全获取嵌套 map 类型值,失败返回空 map
func GetMap(m map[string]PHPValue, key string) map[string]interface{} {
val, ok := m[key]
if !ok {
return make(map[string]interface{})
}
// 类型断言:将 interface{} 转为 map[string]interface{}
nestedMap, ok := val.(map[string]PHPValue)
if !ok {
fmt.Printf("警告:%s 不是数组类型\n", key)
return make(map[string]interface{})
}
// 转换为通用 map[string]interface{}
result := make(map[string]interface{})
for k, v := range nestedMap {
result[k] = v
}
return result
}