Skip to content

Instantly share code, notes, and snippets.

@jharlap
Created February 3, 2012 17:21
Show Gist options
  • Save jharlap/1731245 to your computer and use it in GitHub Desktop.
Save jharlap/1731245 to your computer and use it in GitHub Desktop.
PHP Serialized array/string/integer parser in Groovy
package ch.prodema.misc
class PhpSerializedParser {
private enum ObjectType {
ARRAY('a'), STRING('s'), INTEGER('i')
ObjectType(String typeChar) { this.typeChar = typeChar }
private final String typeChar
private static final Map<String,ObjectType> lookup
static {
lookup = new HashMap<String,ObjectType>()
for(ObjectType objType in EnumSet.allOf(ObjectType.class)) {
lookup.put(objType.value(), objType)
}
}
public String value() { return typeChar }
public static ObjectType typeForChar(String typeChar) {
return lookup.get(typeChar)
}
}
private String input
private int cursor = 0
PhpSerializedParser(String input) {
this.input = input
}
def parse() {
def type = ObjectType.typeForChar input[cursor]
cursor += 2 // skip the typeof and the subsequent colon
def result
switch(type) {
case ObjectType.STRING:
readToken() // to skip the string length
result = readString()
break
case ObjectType.INTEGER:
result = readInt()
break
case ObjectType.ARRAY:
result = readArray()
break
}
return result
}
private String readToken() {
int tokenEndIndex1 = input.indexOf ";", cursor
int tokenEndIndex2 = input.indexOf ":", cursor
int tokenEndIndex
if (tokenEndIndex2 < tokenEndIndex1 && tokenEndIndex2 != -1) {
tokenEndIndex = tokenEndIndex2
} else {
tokenEndIndex = tokenEndIndex1
}
String result = input.substring cursor, tokenEndIndex
cursor = tokenEndIndex + 1
return result
}
private String readChar() {
String c = this.input[cusor]
cursor++
return c
}
private void skipChar() { cursor++ }
private int readInt() {
String token = readToken()
return Integer.valueOf(token)
}
private String tokenToString(String token) {
return token.substring(1, token.size() - 1)
}
private String readString() {
String token = readToken()
return tokenToString(token)
}
private def readArray() {
int numElements = readInt()
skipChar() // open brace for array
List keys = []
List values = []
for(int i = 0; i < numElements; i++) {
keys.push parse()
values.push parse()
}
skipChar() // close brace for array
skipChar() // semicolon to end token
// check if array was a list or should be a map
def listKeys = 0..<numElements
boolean isList = true
for(int i = 0; i < numElements; i++) {
if(keys[i] != listKeys[i]) {
isList = false
break;
}
}
def result
if(isList) {
result = values
} else {
result = [:]
for(int i = 0; i < numElements; i++) {
result.put keys[i], values[i]
}
}
return result
}
}
import ch.prodema.misc.PhpSerializedParser
def input = /a:3:{s:4:"test";a:1:{i:3;i:5;};s:5:"field";s:19:"Geometric_intensity";s:6:"values";a:5:{i:0;s:0:"";i:1;s:4:"Good";i:2;s:4:"Fair";i:3;s:4:"Poor";i:4;s:12:"Unacceptable";}}/
def p = new PhpSerializedParser(input)
def x = p.parse()
// Result: x ==> {test={3=5}, field=Geometric_intensity, values=[, Good, Fair, Poor, Unacceptable]}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment