You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
316 lines
7.4 KiB
316 lines
7.4 KiB
2 years ago
|
package php_serialize
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"fmt"
|
||
|
"log"
|
||
|
"strconv"
|
||
|
"strings"
|
||
|
)
|
||
|
|
||
|
const UNSERIALIZABLE_OBJECT_MAX_LEN = 10 * 1024 * 1024 * 1024
|
||
|
|
||
|
func UnSerialize(s string) (PhpValue, error) {
|
||
|
decoder := NewUnSerializer(s)
|
||
|
decoder.SetSerializedDecodeFunc(SerializedDecodeFunc(UnSerialize))
|
||
|
return decoder.Decode()
|
||
|
}
|
||
|
|
||
|
type UnSerializer struct {
|
||
|
source string
|
||
|
r *strings.Reader
|
||
|
lastErr error
|
||
|
decodeFunc SerializedDecodeFunc
|
||
|
}
|
||
|
|
||
|
func NewUnSerializer(data string) *UnSerializer {
|
||
|
return &UnSerializer{
|
||
|
source: data,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (self *UnSerializer) SetReader(r *strings.Reader) {
|
||
|
self.r = r
|
||
|
}
|
||
|
|
||
|
func (self *UnSerializer) SetSerializedDecodeFunc(f SerializedDecodeFunc) {
|
||
|
self.decodeFunc = f
|
||
|
}
|
||
|
|
||
|
func (self *UnSerializer) Decode() (PhpValue, error) {
|
||
|
if self.r == nil {
|
||
|
self.r = strings.NewReader(self.source)
|
||
|
}
|
||
|
|
||
|
var value PhpValue
|
||
|
|
||
|
if token, _, err := self.r.ReadRune(); err == nil {
|
||
|
switch token {
|
||
|
default:
|
||
|
self.saveError(fmt.Errorf("php_serialize: Unknown token %#U", token))
|
||
|
case TOKEN_NULL:
|
||
|
value = self.decodeNull()
|
||
|
case TOKEN_BOOL:
|
||
|
value = self.decodeBool()
|
||
|
case TOKEN_INT:
|
||
|
value = self.decodeNumber(false)
|
||
|
case TOKEN_FLOAT:
|
||
|
value = self.decodeNumber(true)
|
||
|
case TOKEN_STRING:
|
||
|
value = self.decodeString(DELIMITER_STRING_LEFT, DELIMITER_STRING_RIGHT, true)
|
||
|
case TOKEN_ARRAY:
|
||
|
value = self.decodeArray()
|
||
|
case TOKEN_OBJECT:
|
||
|
value = self.decodeObject()
|
||
|
case TOKEN_OBJECT_SERIALIZED:
|
||
|
value = self.decodeSerialized()
|
||
|
case TOKEN_REFERENCE, TOKEN_REFERENCE_OBJECT:
|
||
|
value = self.decodeReference()
|
||
|
case TOKEN_SPL_ARRAY:
|
||
|
value = self.decodeSplArray()
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return value, self.lastErr
|
||
|
}
|
||
|
|
||
|
func (self *UnSerializer) decodeNull() PhpValue {
|
||
|
self.expect(SEPARATOR_VALUES)
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (self *UnSerializer) decodeBool() PhpValue {
|
||
|
var (
|
||
|
raw rune
|
||
|
err error
|
||
|
)
|
||
|
self.expect(SEPARATOR_VALUE_TYPE)
|
||
|
|
||
|
if raw, _, err = self.r.ReadRune(); err != nil {
|
||
|
self.saveError(fmt.Errorf("php_serialize: Error while reading bool value: %v", err))
|
||
|
}
|
||
|
|
||
|
self.expect(SEPARATOR_VALUES)
|
||
|
return raw == '1'
|
||
|
}
|
||
|
|
||
|
func (self *UnSerializer) decodeNumber(isFloat bool) PhpValue {
|
||
|
var (
|
||
|
raw string
|
||
|
err error
|
||
|
val PhpValue
|
||
|
)
|
||
|
self.expect(SEPARATOR_VALUE_TYPE)
|
||
|
|
||
|
if raw, err = self.readUntil(SEPARATOR_VALUES); err != nil {
|
||
|
self.saveError(fmt.Errorf("php_serialize: Error while reading number value: %v", err))
|
||
|
} else {
|
||
|
if isFloat {
|
||
|
if val, err = strconv.ParseFloat(raw, 64); err != nil {
|
||
|
self.saveError(fmt.Errorf("php_serialize: Unable to convert %s to float: %v", raw, err))
|
||
|
}
|
||
|
} else {
|
||
|
if val, err = strconv.Atoi(raw); err != nil {
|
||
|
self.saveError(fmt.Errorf("php_serialize: Unable to convert %s to int: %v", raw, err))
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return val
|
||
|
}
|
||
|
|
||
|
func (self *UnSerializer) decodeString(left, right rune, isFinal bool) PhpValue {
|
||
|
var (
|
||
|
err error
|
||
|
val PhpValue
|
||
|
strLen int
|
||
|
readLen int
|
||
|
)
|
||
|
|
||
|
strLen = self.readLen()
|
||
|
self.expect(left)
|
||
|
|
||
|
if strLen > 0 {
|
||
|
buf := make([]byte, strLen)
|
||
|
if readLen, err = self.r.Read(buf); err != nil {
|
||
|
self.saveError(fmt.Errorf("php_serialize: Error while reading string value: %v", err))
|
||
|
} else {
|
||
|
if readLen != strLen {
|
||
|
self.saveError(fmt.Errorf("php_serialize: Unable to read string. Expected %d but have got %d bytes", strLen, readLen))
|
||
|
} else {
|
||
|
val = string(buf)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
self.expect(right)
|
||
|
if isFinal {
|
||
|
self.expect(SEPARATOR_VALUES)
|
||
|
}
|
||
|
return val
|
||
|
}
|
||
|
|
||
|
func (self *UnSerializer) decodeArray() PhpValue {
|
||
|
var arrLen int
|
||
|
val := make(PhpArray)
|
||
|
|
||
|
arrLen = self.readLen()
|
||
|
self.expect(DELIMITER_OBJECT_LEFT)
|
||
|
|
||
|
for i := 0; i < arrLen; i++ {
|
||
|
k, errKey := self.Decode()
|
||
|
v, errVal := self.Decode()
|
||
|
|
||
|
if errKey == nil && errVal == nil {
|
||
|
val[k] = v
|
||
|
/*switch t := k.(type) {
|
||
|
default:
|
||
|
self.saveError(fmt.Errorf("php_serialize: Unexpected key type %T", t))
|
||
|
case string:
|
||
|
stringKey, _ := k.(string)
|
||
|
val[stringKey] = v
|
||
|
case int:
|
||
|
intKey, _ := k.(int)
|
||
|
val[strconv.Itoa(intKey)] = v
|
||
|
}*/
|
||
|
} else {
|
||
|
self.saveError(fmt.Errorf("php_serialize: Error while reading key or(and) value of array"))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
self.expect(DELIMITER_OBJECT_RIGHT)
|
||
|
return val
|
||
|
}
|
||
|
|
||
|
func (self *UnSerializer) decodeObject() PhpValue {
|
||
|
val := &PhpObject{
|
||
|
className: self.readClassName(),
|
||
|
}
|
||
|
|
||
|
rawMembers := self.decodeArray()
|
||
|
val.members, _ = rawMembers.(PhpArray)
|
||
|
|
||
|
return val
|
||
|
}
|
||
|
|
||
|
func (self *UnSerializer) decodeSerialized() PhpValue {
|
||
|
val := &PhpObjectSerialized{
|
||
|
className: self.readClassName(),
|
||
|
}
|
||
|
|
||
|
rawData := self.decodeString(DELIMITER_OBJECT_LEFT, DELIMITER_OBJECT_RIGHT, false)
|
||
|
val.data, _ = rawData.(string)
|
||
|
|
||
|
if self.decodeFunc != nil && val.data != "" {
|
||
|
var err error
|
||
|
if val.value, err = self.decodeFunc(val.data); err != nil {
|
||
|
self.saveError(err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return val
|
||
|
}
|
||
|
|
||
|
func (self *UnSerializer) decodeReference() PhpValue {
|
||
|
self.expect(SEPARATOR_VALUE_TYPE)
|
||
|
if _, err := self.readUntil(SEPARATOR_VALUES); err != nil {
|
||
|
self.saveError(fmt.Errorf("php_serialize: Error while reading reference value: %v", err))
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (self *UnSerializer) expect(expected rune) {
|
||
|
if token, _, err := self.r.ReadRune(); err != nil {
|
||
|
self.saveError(fmt.Errorf("php_serialize: Error while reading expected rune %#U: %v", expected, err))
|
||
|
} else if token != expected {
|
||
|
if debugMode {
|
||
|
log.Printf("php_serialize: source\n%s\n", self.source)
|
||
|
log.Printf("php_serialize: reader info\n%#v\n", self.r)
|
||
|
}
|
||
|
self.saveError(fmt.Errorf("php_serialize: Expected %#U but have got %#U", expected, token))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (self *UnSerializer) readUntil(stop rune) (string, error) {
|
||
|
var (
|
||
|
token rune
|
||
|
err error
|
||
|
)
|
||
|
buf := bytes.NewBuffer([]byte{})
|
||
|
|
||
|
for {
|
||
|
if token, _, err = self.r.ReadRune(); err != nil || token == stop {
|
||
|
break
|
||
|
} else {
|
||
|
buf.WriteRune(token)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return buf.String(), err
|
||
|
}
|
||
|
|
||
|
func (self *UnSerializer) readLen() int {
|
||
|
var (
|
||
|
raw string
|
||
|
err error
|
||
|
val int
|
||
|
)
|
||
|
self.expect(SEPARATOR_VALUE_TYPE)
|
||
|
|
||
|
if raw, err = self.readUntil(SEPARATOR_VALUE_TYPE); err != nil {
|
||
|
self.saveError(fmt.Errorf("php_serialize: Error while reading lenght of value: %v", err))
|
||
|
} else {
|
||
|
if val, err = strconv.Atoi(raw); err != nil {
|
||
|
self.saveError(fmt.Errorf("php_serialize: Unable to convert %s to int: %v", raw, err))
|
||
|
} else if val > UNSERIALIZABLE_OBJECT_MAX_LEN {
|
||
|
self.saveError(fmt.Errorf("php_serialize: Unserializable object length looks too big(%d). If you are sure you wanna unserialise it, please increase UNSERIALIZABLE_OBJECT_MAX_LEN const", val))
|
||
|
val = 0
|
||
|
}
|
||
|
}
|
||
|
return val
|
||
|
}
|
||
|
|
||
|
func (self *UnSerializer) readClassName() (res string) {
|
||
|
rawClass := self.decodeString(DELIMITER_STRING_LEFT, DELIMITER_STRING_RIGHT, false)
|
||
|
res, _ = rawClass.(string)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (self *UnSerializer) saveError(err error) {
|
||
|
if self.lastErr == nil {
|
||
|
self.lastErr = err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (self *UnSerializer) decodeSplArray() PhpValue {
|
||
|
var err error
|
||
|
val := &PhpSplArray{}
|
||
|
|
||
|
self.expect(SEPARATOR_VALUE_TYPE)
|
||
|
self.expect(TOKEN_INT)
|
||
|
|
||
|
flags := self.decodeNumber(false)
|
||
|
if flags == nil {
|
||
|
self.saveError(fmt.Errorf("php_serialize: Unable to read flags of SplArray"))
|
||
|
return nil
|
||
|
}
|
||
|
val.flags = PhpValueInt(flags)
|
||
|
|
||
|
if val.array, err = self.Decode(); err != nil {
|
||
|
self.saveError(fmt.Errorf("php_serialize: Can't parse SplArray: %v", err))
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
self.expect(SEPARATOR_VALUES)
|
||
|
self.expect(TOKEN_SPL_ARRAY_MEMBERS)
|
||
|
self.expect(SEPARATOR_VALUE_TYPE)
|
||
|
|
||
|
if val.properties, err = self.Decode(); err != nil {
|
||
|
self.saveError(fmt.Errorf("php_serialize: Can't parse properties of SplArray: %v", err))
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
return val
|
||
|
}
|