Convert var_dump of array back to array variable
var_export
or serialize
is what you're looking for. var_export
will render a PHP parsable array syntax, and serialize
will render a non-human readable but reversible "array to string" conversion...
Edit Alright, for the challenge:
Basically, I convert the output into a serialized string (and then unserialize it). I don't claim this to be perfect, but it appears to work on some pretty complex structures that I've tried...
function unvar_dump($str) { if (strpos($str, "\n") === false) { //Add new lines: $regex = array( '#(\\[.*?\\]=>)#', '#(string\\(|int\\(|float\\(|array\\(|NULL|object\\(|})#', ); $str = preg_replace($regex, "\n\\1", $str); $str = trim($str); } $regex = array( '#^\\040*NULL\\040*$#m', '#^\\s*array\\((.*?)\\)\\s*{\\s*$#m', '#^\\s*string\\((.*?)\\)\\s*(.*?)$#m', '#^\\s*int\\((.*?)\\)\\s*$#m', '#^\\s*bool\\(true\\)\\s*$#m', '#^\\s*bool\\(false\\)\\s*$#m', '#^\\s*float\\((.*?)\\)\\s*$#m', '#^\\s*\[(\\d+)\\]\\s*=>\\s*$#m', '#\\s*?\\r?\\n\\s*#m', ); $replace = array( 'N', 'a:\\1:{', 's:\\1:\\2', 'i:\\1', 'b:1', 'b:0', 'd:\\1', 'i:\\1', ';' ); $serialized = preg_replace($regex, $replace, $str); $func = create_function( '$match', 'return "s:".strlen($match[1]).":\\"".$match[1]."\\"";' ); $serialized = preg_replace_callback( '#\\s*\\["(.*?)"\\]\\s*=>#', $func, $serialized ); $func = create_function( '$match', 'return "O:".strlen($match[1]).":\\"".$match[1]."\\":".$match[2].":{";' ); $serialized = preg_replace_callback( '#object\\((.*?)\\).*?\\((\\d+)\\)\\s*{\\s*;#', $func, $serialized ); $serialized = preg_replace( array('#};#', '#{;#'), array('}', '{'), $serialized ); return unserialize($serialized);}
I tested it on a complex structure such as:
array(4) { ["foo"]=> string(8) "Foo"bar"" [0]=> int(4) [5]=> float(43.2) ["af"]=> array(3) { [0]=> string(3) "123" [1]=> object(stdClass)#2 (2) { ["bar"]=> string(4) "bart" ["foo"]=> array(1) { [0]=> string(2) "re" } } [2]=> NULL }}
There's no other way than manual parsing depending on the type.I didn't add support for objects, but it's very similar to the arrays one; you just need to do some reflection magic to populate not only public properties and to not trigger the constructor.
EDIT: Added support for objects... Reflection magic...
function unserializeDump($str, &$i = 0) { $strtok = substr($str, $i); switch ($type = strtok($strtok, "(")) { // get type, before first parenthesis case "bool": return strtok(")") === "true"?(bool) $i += 10:!$i += 11; case "int": $int = (int)substr($str, $i + 4); $i += strlen($int) + 5; return $int; case "string": $i += 11 + ($len = (int)substr($str, $i + 7)) + strlen($len); return substr($str, $i - $len - 1, $len); case "float": return (float)($float = strtok(")")) + !$i += strlen($float) + 7; case "NULL": return NULL; case "array": $array = array(); $len = (int)substr($str, $i + 6); $i = strpos($str, "\n", $i) - 1; for ($entries = 0; $entries < $len; $entries++) { $i = strpos($str, "\n", $i); $indent = -1 - (int)$i + $i = strpos($str, "[", $i); // get key int/string if ($str[$i + 1] == '"') { // use longest possible sequence to avoid key and dump structure collisions $key = substr($str, $i + 2, - 2 - $i + $i = strpos($str, "\"]=>\n ", $i)); } else { $key = (int)substr($str, $i + 1); $i += strlen($key); } $i += $indent + 5; // jump line $array[$key] = unserializeDump($str, $i); } $i = strpos($str, "}", $i) + 1; return $array; case "object": $reflection = new ReflectionClass(strtok(")")); $object = $reflection->newInstanceWithoutConstructor(); $len = !strtok("(") + strtok(")"); $i = strpos($str, "\n", $i) - 1; for ($entries = 0; $entries < $len; $entries++) { $i = strpos($str, "\n", $i); $indent = -1 - (int)$i + $i = strpos($str, "[", $i); // use longest possible sequence to avoid key and dump structure collisions $key = substr($str, $i + 2, - 2 - $i + $i = min(strpos($str, "\"]=>\n ", $i)?:INF, strpos($str, "\":protected]=>\n ", $i)?:INF, $priv = strpos($str, "\":\"", $i)?:INF)); if ($priv == $i) { $ref = new ReflectionClass(substr($str, $i + 3, - 3 - $i + $i = strpos($str, "\":private]=>\n ", $i))); $i += $indent + 13; // jump line } else { $i += $indent + ($str[$i+1] == ":"?15:5); // jump line $ref = $reflection; } $prop = $ref->getProperty($key); $prop->setAccessible(true); $prop->setValue($object, unserializeDump($str, $i)); } $i = strpos($str, "}", $i) + 1; return $object; } throw new Exception("Type not recognized...: $type");}
(Here are a lot of "magic" numbers when incrementing string position counter $i
, mostly just string lengths of the keywords and some parenthesis etc.)
If you want to encode/decode an array like this, you should either use var_export()
, which generates output in PHP's array for, for instance:
array( 1 => 'foo', 2 => 'bar')
could be the result of it. You would have to use eval()
to get the array back, though, and that is a potentially dangerous way (especially since eval()
really executes PHP code, so a simple code injection could make hackers able to gain control over your PHP script).
Some even better solutions are serialize()
, which creates a serialized version of any array or object; and json_encode()
, which encodes any array or object with the JSON format (which is more preferred for data exchange between different languages).