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 }