Created
October 8, 2017 16:10
-
-
Save thekoushik/d8a47a5df9b86bc0b281e09a46221619 to your computer and use it in GitHub Desktop.
Beautifier for php serialize()
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
<?php | |
/** | |
* @author Koushik Seal <thekoushik.universe@gmail.com> | |
* @version 1.0 | |
*/ | |
class SerializeBeautifier{ | |
/** | |
* input for beautify | |
* | |
* @var string | |
*/ | |
private $input; | |
/** | |
* current position in input | |
* | |
* @var int | |
*/ | |
private $pos; | |
/** | |
* converts serialized result into an assiciative array | |
* | |
* @param string $input output of serialize() | |
* @return array | |
*/ | |
public function beautify($input){ | |
$this->pos=0; | |
$this->input=$input; | |
return $this->do_beautify(); | |
} | |
/** | |
* converts array to string as serialized result | |
* | |
* @param array $array | |
* @return string | |
*/ | |
public function uglify($array){ | |
if(!is_array($array)) | |
throw new Exception("Array expected"); | |
$str=""; | |
switch ($array['type']) { | |
case 'int': | |
$str="i:".$array['value'].";"; | |
break; | |
case 'double': | |
$str="d:".$array['value'].";"; | |
break; | |
case 'string': | |
$str="s:".strlen($array['value']).":\"".$array['value']."\";"; | |
break; | |
case 'boolean': | |
$str="b:".($array['value']==1?'1':'0').";"; | |
break; | |
case 'array': | |
$str="a:".count($array['value']).":{"; | |
foreach ($array['value'] as $key => $value) { | |
if(is_string($key)) | |
$str.="s:".strlen($key).":\"".$key."\";"; | |
else | |
$str.="i:".$key.";"; | |
$str.=$this->uglify($value); | |
} | |
$str.="}"; | |
break; | |
case 'object': | |
$str.="O:".strlen($array['value']['class']).":\"".$array['value']['class']."\":"; | |
$array=$array['value']['value']; | |
$str.="".count($array).":{"; | |
foreach ($array as $key => $value) { | |
$str.="s:".strlen($key).":\"".$key."\";"; | |
$str.=$this->uglify($value); | |
} | |
$str.="}"; | |
break; | |
default: | |
throw new Exception("Invalid type \"".$array['type']."\""); | |
} | |
return $str; | |
} | |
/** | |
* check whether current character is ';' or '}' | |
* | |
* @return void | |
*/ | |
private function expectEnd(){ | |
if($this->input[$this->pos]==';' || $this->input[$this->pos]=='}') | |
$this->pos++; | |
else | |
throw new Exception('Syntax Error: ";" or "}" expected at '.$this->pos); | |
} | |
/** | |
* check whether current character is ':' | |
* | |
* @return void | |
*/ | |
private function expectColon(){ | |
if($this->input[$this->pos++]!=':') | |
throw new Exception('Syntax Error: ":" expected at '.$this->pos); | |
} | |
/** | |
* check whether current character is '{' | |
* | |
* @return void | |
*/ | |
private function expectStartObject(){ | |
if($this->input[$this->pos++]!='{') | |
throw new Exception('Syntax Error: "{" expected at '.$this->pos); | |
} | |
/** | |
* returns the next number from the input | |
* | |
* @return double | |
*/ | |
private function getNumber(){ | |
if(preg_match("/[:;]/",$this->input,$match,PREG_OFFSET_CAPTURE,$this->pos)){//^0-9. | |
$num=substr($this->input,$this->pos,$match[0][1]-$this->pos); | |
$this->pos=$match[0][1]; | |
return $num; | |
}else | |
throw new Exception('Syntax Error: at '.$this->pos); | |
} | |
/** | |
* returns the next character as type | |
* | |
* @return string | |
*/ | |
private function getType(){ | |
$type=$this->input[$this->pos++]; | |
$this->expectColon(); | |
return $type; | |
} | |
/** | |
* converts string to array recursively | |
* | |
* @return array | |
*/ | |
private function do_beautify(){ | |
$type=$this->getType(); | |
$size=$this->getNumber(); | |
switch ($type) { | |
case 'i': | |
$type='int'; | |
$val=$size; | |
break; | |
case 'b': | |
if($size<0 || $size>1) | |
throw new Exception('Syntax Error: boolean value can only be 0 or 1'); | |
$type='boolean'; | |
$val=$size; | |
break; | |
case 'd': | |
$type='double'; | |
$val=$size; | |
break; | |
case 's': | |
$type='string'; | |
$this->expectColon(); | |
$val=substr($this->input,$this->pos+1,$size); | |
$this->pos+=$size+2; | |
break; | |
case 'a': | |
$type='array'; | |
$this->expectColon(); | |
$this->expectStartObject(); | |
$array=[]; | |
for($i=0;$i<$size;$i++){ | |
$index=$this->do_beautify(); | |
$v=$this->do_beautify(); | |
$array[$index['value']]=$v; | |
} | |
$val=$array; | |
break; | |
case 'O': | |
$type='object'; | |
$this->expectColon(); | |
$clazz=substr($this->input,$this->pos+1,$size); | |
$this->pos+=$size+2; | |
$this->expectColon(); | |
$propertyCount=$this->getNumber(); | |
$this->expectColon(); | |
$this->expectStartObject(); | |
$array=[]; | |
for($i=0;$i<$propertyCount;$i++){ | |
$propertyName=$this->do_beautify(); | |
$v=$this->do_beautify(); | |
$array[$propertyName['value']]=$v; | |
} | |
$val=['class'=>$clazz,'value'=>$array]; | |
break; | |
default: | |
throw new Exception("Unexpected type \"".$type."\" at ".$this->pos); | |
} | |
$this->expectEnd(); | |
return ['type'=>$type,'value'=>$val]; | |
} | |
} | |
/////////////////////////////test | |
class Abc{ | |
private $name; | |
private $age; | |
public function __construct($name){ | |
$this->name=$name; | |
$this->age=10; | |
} | |
} | |
date_default_timezone_set('Asia/Kolkata'); | |
$testCases=['new Abc("xyz")'=>new Abc("xyz"),'new DateTime()'=>new DateTime(),'true'=>true,"100"=>100,"3.14159265"=>3.14159265,'simple'=>"simple",'[10,12]'=>[10,12],"['a'=>'assoc','b'=>'array']"=>['a'=>'assoc','b'=>'array']]; | |
foreach ($testCases as $key=>$value){ | |
$input=serialize($value); | |
$beautifier=new SerializeBeautifier(); | |
$array=$beautifier->beautify($input); | |
$output=$beautifier->uglify($array); | |
if($input==$output) | |
echo $key." (".gettype($value).") -> Success\n"; | |
else | |
echo $key." (".gettype($value).") -> Failure\n".$input."\n".$output."\n"; | |
} | |
/* Result: | |
new Abc("xyz") (object) -> Success | |
new DateTime() (object) -> Success | |
true (boolean) -> Success | |
100 (integer) -> Success | |
3.14159265 (double) -> Success | |
simple (string) -> Success | |
[10,12] (array) -> Success | |
['a'=>'assoc','b'=>'array'] (array) -> Success | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment