Skip to content

Instantly share code, notes, and snippets.

@thekoushik
Created October 8, 2017 16:10
Show Gist options
  • Save thekoushik/d8a47a5df9b86bc0b281e09a46221619 to your computer and use it in GitHub Desktop.
Save thekoushik/d8a47a5df9b86bc0b281e09a46221619 to your computer and use it in GitHub Desktop.
Beautifier for php serialize()
<?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