note 113938 added to function.json-decode
| From: | kuroi dot neko at wanadoo dot fr | Date: | Wed, 18 Dec 2013 21:37:52 +0000 |
| Subject: | note 113938 added to function.json-decode | ||
| Groups: | php.notes | ||
| Request: | Send a blank email to php-notes+get-197980@lists.php.net to get a copy of this message | ||
My initial problem was to have PHP check a form in case JavaScript was disabled on the client.
I fiddled with json_decode for a while before realizing what I really wanted: to be able to
initialize the same object in PHP and JavaScript from a common source file.
I ended up writing a tiny parser for a JavaScript object initializer, which is close to - but not
the same thing as - a piece of JSON.
Among other things, it
- recognizes regexes (turning them into PHP strings),
- handles C/C++ comments
- accepts non-quoted field names.
This parser will accept a superset of real JS object initializer syntax (for instance non-quoted
string litterals or improperly formed regexes). Error report and sanity checks are close to
non-existent.
The whole idea is to share the code among JavaScript and PHP, so the syntactical checks are left to
the JS interpreter.
Here is the code for those who are interrested :
-----------------------------
class JSvarDecoderCtx {
public function __construct ($type)
{
$this->fields = ($type == '[') ? array() : new stdClass();
}
public function add_name (&$text)
{
$this->name = $text;
$text = '';
}
public function add_value (&$text)
{
// weird input like a mix of fields and array elements will cause warnings here
if (!isset ($this->name)) $this->fields[ ] = $text;
else $this->fields->{$this->name} = $text;
$text = '';
}
}
define ('JSVAL_TEXT' , 12001);
define ('JSVAL_STRING', 12002);
define ('JSVAL_REGEXP', 12003);
define ('JSVAL_COMMT1', 12004);
define ('JSVAL_COMMT2', 12005);
function jsinit_decode ($json)
{
// parse a JS initializer
$stack = array ();
$text = "";
$state = JSVAL_TEXT;
$len = strlen($json);
for ($i = 0 ; $i != $len; $i++)
{
$c = $json[$i];
switch ($state)
{
case JSVAL_TEXT:
switch ($c)
{
case '{' :
case '[' : array_unshift ($stack, new JSvarDecoderCtx ($c)); break;
case '}' :
case ']' : $stack[0]->add_value ($text); $text = array_shift ($stack)->fields;
break;
case ':' : $stack[0]->add_name ($text); break;
case ',' : $stack[0]->add_value ($text); break;
case '"' :
case "'" : $closer = $c; $state = JSVAL_STRING; break;
case '/' :
assert($i != ($len-1));
switch ($json[$i+1])
{
case '/': $state = JSVAL_COMMT1; break;
case '*': $state = JSVAL_COMMT2; break;
default : $state = JSVAL_REGEXP; $text .= $c;
}
break;
case "\r":
case "\n":
case "\t":
case ' ' : break;
default : $text .= $c;
}
break;
case JSVAL_STRING: if ($c != $closer) $text .= $c; else $state = JSVAL_TEXT; break;
case JSVAL_REGEXP: if (($c != ',') && ($c != '}')) $text .= $c; else
{ $i--; $state = JSVAL_TEXT; } break;
case JSVAL_COMMT1: if (($c == "\r") || ($c == "\n")) $state = JSVAL_TEXT;
break;
case JSVAL_COMMT2:
if ($c != '*') break;
assert($i != ($len-1));
if ($json[$i+1] == '/') { $i++; $state = JSVAL_TEXT; }
}
}
assert ($state == JSVAL_TEXT);
return $text;
}
-----------------------------
Test pattern :
{
errors: "form-errors", // CSS class for validation errors tooltip
i: /* integer */ /^[0-9]+$/,
err: {
'*': "mandatory field",
i: "must be an integer",
},
a:['ga','bu','zo','meuh'] // http://www.archimedes-lab.org/shadoks/shadoiku.html
}
-----------------------------
result :
stdClass Object
(
[errors] => form-errors
[i] => /^[0-9]+$/
[err] => stdClass Object
(
[*] => mandatory field
[i] => must be an integer
)
[a] => Array
(
[0] => ga
[1] => bu
[2] => zo
[3] => meuh
)
)
----
Server IP: 72.52.91.14
Probable Submitter: 72.52.91.14
----
Manual Page -- http://php.net/manual/en/function.json-decode.php
Edit -- https://master.php.net/note/edit/113938
Del: integrated -- https://master.php.net/note/delete/113938/integrated
Del: useless -- https://master.php.net/note/delete/113938/useless
Del: bad code -- https://master.php.net/note/delete/113938/bad+code
Del: spam -- https://master.php.net/note/delete/113938/spam
Del: non-english -- https://master.php.net/note/delete/113938/non-english
Del: in docs -- https://master.php.net/note/delete/113938/in+docs
Del: other reasons-- https://master.php.net/note/delete/113938
Reject -- https://master.php.net/note/reject/113938
Search -- https://master.php.net/manage/user-notes.php