├── README.md └── phpserialize ├── common.go ├── decoder.go ├── decoder_test.go ├── encoder.go └── encoder_test.go /README.md: -------------------------------------------------------------------------------- 1 | go-php-serialize 2 | ================ 3 | 4 | Golang implementation for PHP's function serialize() and unserialize() 5 | 6 | 用Go语言实现PHP的serialize()和unserialize()函数 7 | 8 | thanks to https://github.com/yvasiyarov/php_session_decoder 9 | -------------------------------------------------------------------------------- /phpserialize/common.go: -------------------------------------------------------------------------------- 1 | package phpserialize 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | const TYPE_VALUE_SEPARATOR = ':' 8 | const VALUES_SEPARATOR = ';' 9 | 10 | type PhpObject struct { 11 | members map[interface{}]interface{} 12 | className string 13 | } 14 | 15 | func NewPhpObject() *PhpObject { 16 | d := &PhpObject{ 17 | members: make(map[interface{}]interface{}), 18 | } 19 | return d 20 | } 21 | 22 | func (obj *PhpObject) GetClassName() string { 23 | return obj.className 24 | } 25 | 26 | func (obj *PhpObject) SetClassName(cName string) { 27 | obj.className = cName 28 | } 29 | 30 | func (obj *PhpObject) GetMembers() map[interface{}]interface{} { 31 | return obj.members 32 | } 33 | 34 | func (obj *PhpObject) GetPrivateMemberValue(memberName string) (interface{}, bool) { 35 | key := fmt.Sprintf("\x00%s\x00%s", obj.className, memberName) 36 | v, ok := obj.members[key] 37 | return v, ok 38 | } 39 | 40 | func (obj *PhpObject) SetPrivateMemberValue(memberName string, value interface{}) { 41 | key := fmt.Sprintf("\x00%s\x00%s", obj.className, memberName) 42 | obj.members[key] = value 43 | } 44 | 45 | func (obj *PhpObject) GetProtectedMemberValue(memberName string) (interface{}, bool) { 46 | key := "\x00*\x00" + memberName 47 | v, ok := obj.members[key] 48 | return v, ok 49 | } 50 | 51 | func (obj *PhpObject) SetProtectedMemberValue(memberName string, value interface{}) { 52 | key := "\x00*\x00" + memberName 53 | obj.members[key] = value 54 | } 55 | 56 | func (obj *PhpObject) GetPublicMemberValue(memberName string) (interface{}, bool) { 57 | v, ok := obj.members[memberName] 58 | return v, ok 59 | } 60 | 61 | func (obj *PhpObject) SetPublicMemberValue(memberName string, value interface{}) { 62 | obj.members[memberName] = value 63 | } 64 | -------------------------------------------------------------------------------- /phpserialize/decoder.go: -------------------------------------------------------------------------------- 1 | package phpserialize 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "fmt" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | type PhpDecoder struct { 12 | source *strings.Reader 13 | } 14 | 15 | func Decode(value string) (result interface{}, err error) { 16 | decoder := &PhpDecoder{ 17 | source: strings.NewReader(value), 18 | } 19 | result, err = decoder.DecodeValue() 20 | return 21 | } 22 | 23 | //all integer is int64,float number is float64 24 | func (decoder *PhpDecoder) DecodeValue() (value interface{}, err error) { 25 | if token, _, err := decoder.source.ReadRune(); err == nil { 26 | if token == 'N' { 27 | err = decoder.expect(VALUES_SEPARATOR) 28 | return nil, err 29 | } 30 | decoder.expect(TYPE_VALUE_SEPARATOR) 31 | switch token { 32 | case 'b': 33 | if rawValue, _, _err := decoder.source.ReadRune(); _err == nil { 34 | value = rawValue == '1' 35 | } else { 36 | err = errors.New("Can not read boolean value") 37 | } 38 | if err != nil { 39 | return nil, err 40 | } 41 | err = decoder.expect(VALUES_SEPARATOR) 42 | case 'i': 43 | if rawValue, _err := decoder.readUntil(VALUES_SEPARATOR); _err == nil { 44 | if tmpv, _err := strconv.Atoi(rawValue); _err != nil { 45 | err = fmt.Errorf("Can not convert %v to Int:%v", rawValue, _err) 46 | } else { 47 | value = int64(tmpv) 48 | } 49 | } else { 50 | err = errors.New("Can not read int value") 51 | } 52 | case 'd': 53 | if rawValue, _err := decoder.readUntil(VALUES_SEPARATOR); _err == nil { 54 | if value, _err = strconv.ParseFloat(rawValue, 64); _err != nil { 55 | err = fmt.Errorf("Can not convert %v to Float:%v", rawValue, _err) 56 | } 57 | } else { 58 | err = errors.New("Can not read float value") 59 | } 60 | case 's': 61 | value, err = decoder.decodeString() 62 | if err != nil { 63 | return nil, err 64 | } 65 | err = decoder.expect(VALUES_SEPARATOR) 66 | case 'a': 67 | value, err = decoder.decodeArray() 68 | case 'O': 69 | value, err = decoder.decodeObject() 70 | } 71 | } 72 | return value, err 73 | } 74 | 75 | func (decoder *PhpDecoder) decodeObject() (*PhpObject, error) { 76 | value := &PhpObject{} 77 | var err error 78 | 79 | if value.className, err = decoder.decodeString(); err != nil { 80 | return nil, err 81 | } 82 | if err = decoder.expect(TYPE_VALUE_SEPARATOR); err != nil { 83 | return nil, err 84 | } 85 | if value.members, err = decoder.decodeArray(); err != nil { 86 | return nil, err 87 | } 88 | 89 | return value, err 90 | } 91 | 92 | func (decoder *PhpDecoder) decodeArray() (value map[interface{}]interface{}, err error) { 93 | value = make(map[interface{}]interface{}) 94 | if rawArrlen, _err := decoder.readUntil(TYPE_VALUE_SEPARATOR); _err == nil { 95 | if arrLen, _err := strconv.Atoi(rawArrlen); _err != nil { 96 | err = fmt.Errorf("Can not convert array length %v to int:%v", rawArrlen, _err) 97 | } else { 98 | decoder.expect('{') 99 | for i := 0; i < arrLen; i++ { 100 | if k, _err := decoder.DecodeValue(); _err != nil { 101 | err = fmt.Errorf("Can not read array key %v", _err) 102 | } else if v, _err := decoder.DecodeValue(); _err != nil { 103 | err = fmt.Errorf("Can not read array value %v", _err) 104 | } else { 105 | switch t := k.(type) { 106 | default: 107 | err = fmt.Errorf("Unexpected key type %T", t) 108 | case string, int64, float64: 109 | value[k] = v 110 | } 111 | } 112 | } 113 | decoder.expect('}') 114 | } 115 | } else { 116 | err = errors.New("Can not read array length") 117 | } 118 | return value, err 119 | } 120 | 121 | func (decoder *PhpDecoder) decodeString() (value string, err error) { 122 | if rawStrlen, _err := decoder.readUntil(TYPE_VALUE_SEPARATOR); _err == nil { 123 | if strLen, _err := strconv.Atoi(rawStrlen); _err != nil { 124 | err = errors.New(fmt.Sprintf("Can not convert string length %v to int:%v", rawStrlen, _err)) 125 | } else { 126 | if err = decoder.expect('"'); err != nil { 127 | return 128 | } 129 | tmpValue := make([]byte, strLen, strLen) 130 | if nRead, _err := decoder.source.Read(tmpValue); _err != nil || nRead != strLen { 131 | err = errors.New(fmt.Sprintf("Can not read string content %v. Read only: %v from %v", _err, nRead, strLen)) 132 | } else { 133 | value = string(tmpValue) 134 | err = decoder.expect('"') 135 | } 136 | } 137 | } else { 138 | err = errors.New("Can not read string length") 139 | } 140 | return value, err 141 | } 142 | 143 | func (decoder *PhpDecoder) readUntil(stopByte byte) (string, error) { 144 | result := new(bytes.Buffer) 145 | var ( 146 | token byte 147 | err error 148 | ) 149 | for { 150 | if token, err = decoder.source.ReadByte(); err != nil || token == stopByte { 151 | break 152 | } else { 153 | result.WriteByte(token) 154 | } 155 | } 156 | return result.String(), err 157 | } 158 | 159 | func (decoder *PhpDecoder) expect(expectRune rune) error { 160 | token, _, err := decoder.source.ReadRune() 161 | if err != nil { 162 | err = fmt.Errorf("Can not read expected: %v", expectRune) 163 | } else if token != expectRune { 164 | err = fmt.Errorf("Read %v, but expected: %v", token, expectRune) 165 | } 166 | return err 167 | } 168 | -------------------------------------------------------------------------------- /phpserialize/decoder_test.go: -------------------------------------------------------------------------------- 1 | package phpserialize 2 | 3 | import ( 4 | "math" 5 | "testing" 6 | ) 7 | 8 | func TestDecodeArrayValue2(t *testing.T) { 9 | data := make(map[interface{}]interface{}) 10 | data2 := make(map[interface{}]interface{}) 11 | data2["test"] = true 12 | data2[int64(0)] = int64(5) 13 | data2["flt32"] = float32(2.3) 14 | data2["int64"] = int64(45) 15 | data3 := NewPhpObject() 16 | data3.SetClassName("A") 17 | data3.SetPrivateMemberValue("a", 1) 18 | data3.SetProtectedMemberValue("b", 3.14) 19 | data3.SetPublicMemberValue("c", data2) 20 | data["arr"] = data2 21 | data["3"] = "s\"tr'}e" 22 | data["g"] = nil 23 | data["object"] = data3 24 | 25 | var ( 26 | result string 27 | decodeRes interface{} 28 | err error 29 | ) 30 | if result, err = Encode(data); err != nil { 31 | t.Errorf("encode data fail %v, %v", err, data) 32 | return 33 | } 34 | if decodeRes, err = Decode(result); err != nil { 35 | t.Errorf("decode data fail %v, %v", err, result) 36 | return 37 | } 38 | decodeData, ok := decodeRes.(map[interface{}]interface{}) 39 | if !ok { 40 | t.Errorf("decode data type error, expected: map[interface{}]interface{}, get: %T", decodeRes) 41 | return 42 | } 43 | obj, _ := decodeData["object"].(*PhpObject) 44 | if v, _ := obj.GetPrivateMemberValue("a"); v != int64(1) { 45 | t.Errorf("object private value expected 1, get %v, %T", v, v) 46 | } 47 | if v := obj.GetClassName(); v != "A" { 48 | t.Errorf("object class name expected A, get %v", v) 49 | } 50 | if decodeData["g"] != nil { 51 | t.Errorf("key g value expeted nil, get %v", decodeData["g"]) 52 | } 53 | 54 | decodeData2, ok := decodeData["arr"].(map[interface{}]interface{}) 55 | if !ok { 56 | t.Errorf("key arr value type expeted map, get %T", decodeData["arr"]) 57 | } 58 | for k, v := range decodeData2 { 59 | if k == "flt32" { 60 | if math.Abs(v.(float64)-float64(data2["flt32"].(float32))) > 0.001 { 61 | t.Errorf("key arr[%v] value expeted %v, get %v", k, v, data2[k]) 62 | } 63 | } else if v != data2[k] { 64 | t.Errorf("key arr[%v] value expeted %v, get %v", k, v, data2[k]) 65 | } 66 | } 67 | /* 68 | var ( 69 | stringKey string 70 | //normalKey interface{} 71 | ) 72 | stringKey = "flt32" 73 | //normalKey = stringKey 74 | t.Errorf("%T key %v %v", decodeData2, decodeData2[stringKey], decodeData2["int64"]) 75 | result = "a:33:{s:4:\"cost\";d:457.00000000000011;s:3:\"uid\";s:9:\"119983495\";i:2332002;d:15;i:2735232;d:15;i:66324;d:14.999999999999998;i:55107;d:14;i:84875;d:14;i:65145;d:15;i:437688;d:15;i:40022;d:14;i:2538364;d:15;i:34701;d:15.000000000000002;i:33490;d:15;i:2813734;d:14;i:1878927;d:15;i:1837284;d:15;i:2735238;d:15;i:437385;d:15;i:44723;d:14;i:2538367;d:15;i:84014;d:15;i:427239;d:15.000000000000002;i:76055;d:15;i:67652;d:14.000000000000002;i:33482;d:15;i:45859;d:14;i:44248;d:14;i:44724;d:15;i:45861;d:15;i:37995;d:15;i:39985;d:15;i:40994;d:15;i:42360;d:15;}" 76 | decodeRes, _ = Decode(result) 77 | decodeData, _ = decodeRes.(map[interface{}]interface{}) 78 | for k, v := range decodeData { 79 | t.Errorf("%T %v => %T %v", k, k, v, v) 80 | } 81 | 82 | result = "a:34:{i:66324;d:15;i:67652;d:15;i:427239;d:15;i:437688;d:15;i:1837284;d:15;s:7:\"balance\";d:1617.05;s:5:\"quota\";d:0;i:55107;d:15;i:65145;d:15;i:1878927;d:15;i:2332002;d:15;i:33490;d:15;i:34701;d:15;i:37995;d:15;i:39985;d:15;i:40022;d:15;i:40994;d:15;i:42360;d:15;i:44248;d:15;i:44723;d:15;i:44724;d:15;i:45859;d:15;i:45861;d:15;i:2439794;d:10;i:33482;d:15;i:76055;d:15;i:84014;d:15;i:84875;d:15;i:437385;d:15;i:2538364;d:15;i:2538367;d:15;i:2735232;d:15;i:2735238;d:15;i:2813734;d:15;}" 83 | decodeRes, _ = Decode(result) 84 | decodeData, _ = decodeRes.(map[interface{}]interface{}) 85 | for k, v := range decodeData { 86 | t.Errorf("%T %v => %T %v", k, k, v, v) 87 | } 88 | 89 | t.Errorf("66324 => %v %v balance => %v", decodeData[66324], decodeData[int64(66324)], decodeData["balance"]) 90 | //output 66324 => 15 balance => 1617.05 91 | 92 | t.Errorf("decode %v %v %v %v", err, decodeRes, obj.GetClassName(), privateMemberValue) 93 | 94 | result, err = Encode(data3) 95 | t.Errorf("data %v => %v\n", err, result) 96 | decodeRes, err = Decode(result) 97 | t.Errorf("decode %v %v", err, decodeRes) 98 | 99 | result, err = Encode(nil) 100 | t.Errorf("data %v => %v\n", err, result) 101 | decodeRes, err = Decode(result) 102 | t.Errorf("decode %v %v", err, decodeRes) 103 | 104 | result, err = Encode("s\"tr'}e") 105 | t.Errorf("data %v => %v\n", err, result) 106 | decodeRes, err = Decode(result) 107 | t.Errorf("decode %v %v", err, decodeRes) 108 | */ 109 | } 110 | -------------------------------------------------------------------------------- /phpserialize/encoder.go: -------------------------------------------------------------------------------- 1 | package phpserialize 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "strconv" 7 | ) 8 | 9 | func Encode(value interface{}) (result string, err error) { 10 | buf := new(bytes.Buffer) 11 | err = encodeValue(buf, value) 12 | if err == nil { 13 | result = buf.String() 14 | } 15 | return 16 | } 17 | 18 | func encodeValue(buf *bytes.Buffer, value interface{}) (err error) { 19 | switch t := value.(type) { 20 | default: 21 | err = fmt.Errorf("Unexpected type %T", t) 22 | case bool: 23 | buf.WriteString("b") 24 | buf.WriteRune(TYPE_VALUE_SEPARATOR) 25 | if t { 26 | buf.WriteString("1") 27 | } else { 28 | buf.WriteString("0") 29 | } 30 | buf.WriteRune(VALUES_SEPARATOR) 31 | case nil: 32 | buf.WriteString("N") 33 | buf.WriteRune(VALUES_SEPARATOR) 34 | case int, int64, int32, int16, int8: 35 | buf.WriteString("i") 36 | buf.WriteRune(TYPE_VALUE_SEPARATOR) 37 | strValue := fmt.Sprintf("%v", t) 38 | buf.WriteString(strValue) 39 | buf.WriteRune(VALUES_SEPARATOR) 40 | case float32: 41 | buf.WriteString("d") 42 | buf.WriteRune(TYPE_VALUE_SEPARATOR) 43 | strValue := strconv.FormatFloat(float64(t), 'f', -1, 64) 44 | buf.WriteString(strValue) 45 | buf.WriteRune(VALUES_SEPARATOR) 46 | case float64: 47 | buf.WriteString("d") 48 | buf.WriteRune(TYPE_VALUE_SEPARATOR) 49 | strValue := strconv.FormatFloat(float64(t), 'f', -1, 64) 50 | buf.WriteString(strValue) 51 | buf.WriteRune(VALUES_SEPARATOR) 52 | case string: 53 | buf.WriteString("s") 54 | buf.WriteRune(TYPE_VALUE_SEPARATOR) 55 | encodeString(buf, t) 56 | buf.WriteRune(VALUES_SEPARATOR) 57 | case map[interface{}]interface{}: 58 | buf.WriteString("a") 59 | buf.WriteRune(TYPE_VALUE_SEPARATOR) 60 | err = encodeArrayCore(buf, t) 61 | case *PhpObject: 62 | buf.WriteString("O") 63 | buf.WriteRune(TYPE_VALUE_SEPARATOR) 64 | encodeString(buf, t.GetClassName()) 65 | buf.WriteRune(TYPE_VALUE_SEPARATOR) 66 | err = encodeArrayCore(buf, t.GetMembers()) 67 | } 68 | return 69 | } 70 | 71 | func encodeString(buf *bytes.Buffer, strValue string) { 72 | valLen := strconv.Itoa(len(strValue)) 73 | buf.WriteString(valLen) 74 | buf.WriteRune(TYPE_VALUE_SEPARATOR) 75 | buf.WriteRune('"') 76 | buf.WriteString(strValue) 77 | buf.WriteRune('"') 78 | } 79 | 80 | func encodeArrayCore(buf *bytes.Buffer, arrValue map[interface{}]interface{}) (err error) { 81 | valLen := strconv.Itoa(len(arrValue)) 82 | buf.WriteString(valLen) 83 | buf.WriteRune(TYPE_VALUE_SEPARATOR) 84 | 85 | buf.WriteRune('{') 86 | for k, v := range arrValue { 87 | if intKey, _err := strconv.Atoi(fmt.Sprintf("%v", k)); _err == nil { 88 | if err = encodeValue(buf, intKey); err != nil { 89 | break 90 | } 91 | } else { 92 | if err = encodeValue(buf, k); err != nil { 93 | break 94 | } 95 | } 96 | if err = encodeValue(buf, v); err != nil { 97 | break 98 | } 99 | } 100 | buf.WriteRune('}') 101 | return err 102 | } 103 | -------------------------------------------------------------------------------- /phpserialize/encoder_test.go: -------------------------------------------------------------------------------- 1 | package phpserialize 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestEncodeArrayValue2(t *testing.T) { 8 | data := make(map[interface{}]interface{}) 9 | data2 := make(map[interface{}]interface{}) 10 | data2["test"] = true 11 | data2["0"] = 5 12 | data2["flt32"] = float32(2.3) 13 | data2["int64"] = int64(45) 14 | data3 := NewPhpObject() 15 | data3.SetClassName("A") 16 | data3.SetPrivateMemberValue("a", 1) 17 | data3.SetProtectedMemberValue("b", 3.14) 18 | data3.SetPublicMemberValue("c", data2) 19 | data["arr"] = data2 20 | data["3"] = "s\"tr'}e" 21 | data["g"] = nil 22 | data["object"] = data3 23 | /* 24 | result, err := Encode(data) 25 | t.Errorf("data %v => %v\n", err, result) 26 | result, err = Encode(data3) 27 | t.Errorf("data %v => %v\n", err, result) 28 | result, err = Encode(nil) 29 | t.Errorf("data %v => %v\n", err, result) 30 | result, err = Encode("s\"tr'}e") 31 | t.Errorf("data %v => %v\n", err, result)*/ 32 | } 33 | --------------------------------------------------------------------------------