Created
September 22, 2017 09:23
-
-
Save abhilashrathod/bb82b112718dd49d62b964ed5384ed53 to your computer and use it in GitHub Desktop.
this service helps convert php serialized string to json object for angular 2/4 projects.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export class DeserializeService { | |
idx = 0; | |
refStack = []; | |
ridx = 0; | |
parseNext; | |
phpstr: string = ''; | |
constructor() { | |
} | |
readLength(): any { | |
let del = this.phpstr.indexOf(':', this.idx); | |
let val = this.phpstr.substring(this.idx, del); | |
this.idx = del + 2; | |
return parseInt(val, 10); | |
} | |
readInt(): any { | |
let del = this.phpstr.indexOf(';', this.idx); | |
let val = this.phpstr.substring(this.idx, del); | |
this.idx = del + 1; | |
return parseInt(val, 10); | |
} | |
parseAsInt(): any { | |
let val = this.readInt(); | |
this.refStack[this.ridx++] = val; | |
return val; | |
} //end parseAsInt | |
parseAsFloat(): any { | |
let del = this.phpstr.indexOf(';', this.idx); | |
let val:any = this.phpstr.substring(this.idx, del); | |
this.idx = del + 1; | |
val = parseFloat(val); | |
this.refStack[this.ridx++] = val; | |
return val; | |
} //end parseAsFloat | |
parseAsBoolean(): any { | |
let del = this.phpstr.indexOf(';', this.idx); | |
let val:any = this.phpstr.substring(this.idx, del); | |
this.idx = del + 1; | |
val = ("1" === val) ? true : false; | |
this.refStack[this.ridx++] = val; | |
return val; | |
} | |
readString(): any { | |
let len = this.readLength() | |
, utfLen = 0 | |
, bytes = 0 | |
, ch | |
, val; | |
while (bytes < len) { | |
ch = this.phpstr.charCodeAt(this.idx + utfLen++); | |
if (ch <= 0x007F) { | |
bytes++; | |
} else if (ch > 0x07FF) { | |
bytes += 3; | |
} else { | |
bytes += 2; | |
} | |
} | |
val = this.phpstr.substring(this.idx, this.idx + utfLen); | |
this.idx += utfLen + 2; | |
return val; | |
} //end readString | |
parseAsString(): any { | |
let val = this.readString(); | |
this.refStack[this.ridx++] = val; | |
return val; | |
} //end parseAsString | |
readType(): any { | |
let type = this.phpstr.charAt(this.idx); | |
this.idx += 2; | |
return type; | |
} //end readType | |
readKey(): any { | |
let type = this.readType(); | |
switch (type) { | |
case 'i': | |
return this.readInt(); | |
case 's': | |
return this.readString(); | |
default: | |
throw { | |
name: "Parse Error", | |
message: "Unknown key type '" + type + "' at position " + | |
(this.idx - 2) | |
}; | |
} //end switch | |
} | |
parseAsArray(): any { | |
let len = this.readLength() | |
, resultArray = [] | |
, resultHash = {} | |
, keep:any = resultArray | |
, lref = this.ridx++ | |
, key | |
, val | |
, i | |
, j | |
, alen; | |
this.refStack[lref] = keep; | |
for (i = 0; i < len; i++) { | |
key = this.readKey(); | |
val = this.parseNext(); | |
if (keep === resultArray && parseInt(key, 10) === i) { | |
// store in array version | |
resultArray.push(val); | |
} else { | |
if (keep !== resultHash) { | |
// found first non-sequential numeric key | |
// convert existing data to hash | |
for (j = 0, alen = resultArray.length; j < alen; j++) { | |
resultHash[j] = resultArray[j]; | |
} | |
keep = resultHash; | |
this.refStack[lref] = keep; | |
} | |
resultHash[key] = val; | |
} //end if | |
} //end for | |
this.idx++; | |
return keep; | |
} //end parseAsArray | |
fixPropertyName = function (parsedName, baseClassName) { | |
let class_name | |
, prop_name | |
, pos; | |
if ("\u0000" === parsedName.charAt(0)) { | |
// "<NUL>*<NUL>property" | |
// "<NUL>class<NUL>property" | |
pos = parsedName.indexOf("\u0000", 1); | |
if (pos > 0) { | |
class_name = parsedName.substring(1, pos); | |
prop_name = parsedName.substr(pos + 1); | |
if ("*" === class_name) { | |
// protected | |
return prop_name; | |
} else if (baseClassName === class_name) { | |
// own private | |
return prop_name; | |
} else { | |
// private of a descendant | |
return class_name + "::" + prop_name; | |
// On the one hand, we need to prefix property name with | |
// class name, because parent and child classes both may | |
// have private property with same name. We don't want | |
// just to overwrite it and lose something. | |
// | |
// On the other hand, property name can be "foo::bar" | |
// | |
// $obj = new stdClass(); | |
// $obj->{"foo::bar"} = 42; | |
// // any user-defined class can do this by default | |
// | |
// and such property also can overwrite something. | |
// | |
// So, we can to lose something in any way. | |
} | |
} | |
} else { | |
// public "property" | |
return parsedName; | |
} | |
}; | |
parseAsObject(): any { | |
let len | |
, obj = {} | |
, lref = this.ridx++ | |
// HACK last char after closing quote is ':', | |
// but not ';' as for normal string | |
, clazzname = this.readString() | |
, key | |
, val | |
, i; | |
this.refStack[lref] = obj; | |
len = this.readLength(); | |
for (i = 0; i < len; i++) { | |
key = this.fixPropertyName(this.readKey(), clazzname); | |
val = this.parseNext(); | |
obj[key] = val; | |
} | |
this.idx++; | |
return obj; | |
} //end parseAsObject | |
parseAsCustom(): any { | |
let clazzname = this.readString() | |
, content = this.readString(); | |
return { | |
"__PHP_Incomplete_Class_Name": clazzname, | |
"serialized": content | |
}; | |
} //end parseAsCustom | |
parseAsRefValue(): any { | |
let ref = this.readInt() | |
// php's ref counter is 1-based; our stack is 0-based. | |
, val = this.refStack[ref - 1]; | |
this.refStack[this.ridx++] = val; | |
return val; | |
} //end parseAsRefValue | |
parseAsRef(): any { | |
let ref = this.readInt(); | |
// php's ref counter is 1-based; our stack is 0-based. | |
return this.refStack[ref - 1]; | |
} //end parseAsRef | |
parseAsNull(): any { | |
let val = null; | |
this.refStack[this.ridx++] = val; | |
return val; | |
}; //end parseAsNull | |
deserizlize(phpstr): string { | |
this.phpstr = phpstr; | |
this.parseNext = function () { | |
let type = this.readType(); | |
switch (type) { | |
case 'i': | |
return this.parseAsInt(); | |
case 'd': | |
return this.parseAsFloat(); | |
case 'b': | |
return this.parseAsBoolean(); | |
case 's': | |
return this.parseAsString(); | |
case 'a': | |
return this.parseAsArray(); | |
case 'O': | |
return this.parseAsObject(); | |
case 'C': | |
return this.parseAsCustom(); | |
// link to object, which is a value - affects refStack | |
case 'r': | |
return this.parseAsRefValue(); | |
// PHP's reference - DOES NOT affect refStack | |
case 'R': | |
return this.parseAsRef(); | |
case 'N': | |
return this.parseAsNull(); | |
default: | |
throw { | |
name: "Parse Error", | |
message: "Unknown type '" + type + "' at position " + (this.idx - 2) | |
}; | |
} //end switch | |
}; //end parseNext | |
return this.parseNext(); | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment