json_decode()'s handling of invalid JSON is very flaky, and it is very hard to reliably determine if the decoding succeeded or not. Observe the following examples, none of which contain valid JSON:
The following each returns NULL, as you might expect:
var_dump(json_decode('[')); // unmatched bracket
var_dump(json_decode('{')); // unmatched brace
var_dump(json_decode('{}}')); // unmatched brace
var_dump(json_decode('{error error}')); // invalid object key/value
notation
var_dump(json_decode('["\"]')); // unclosed string
var_dump(json_decode('[" \x "]')); // invalid escape code
Yet the following each returns the literal string you passed to it:
var_dump(json_decode(' [')); // unmatched bracket
var_dump(json_decode(' {')); // unmatched brace
var_dump(json_decode(' {}}')); // unmatched brace
var_dump(json_decode(' {error error}')); // invalid object key/value notation
var_dump(json_decode('"\"')); // unclosed string
var_dump(json_decode('" \x "')); // invalid escape code
(this is on PHP 5.2.6)
Reported as a bug, but oddly enough, it was closed as not a bug:
http://bugs.php.net/bug.php?id=45989
json_decode
(PHP 5 >= 5.2.0, PECL json:1.2.0-1.2.1)
json_decode — Decodes a JSON string
Описание
Takes a JSON encoded string and converts it into a PHP variable.
Список параметров
Возвращаемые значения
Returns an object or if the optional assoc parameter is TRUE, an associative array is instead returned.
Примеры
Пример #1 json_decode() examples
<?php
$json = '{"a":1,"b":2,"c":3,"d":4,"e":5}';
var_dump(json_decode($json));
var_dump(json_decode($json, true));
?>
Результат выполнения данного примера:
object(stdClass)#1 (5) { ["a"] => int(1) ["b"] => int(2) ["c"] => int(3) ["d"] => int(4) ["e"] => int(5) } array(5) { ["a"] => int(1) ["b"] => int(2) ["c"] => int(3) ["d"] => int(4) ["e"] => int(5) }
Пример #2 Another example
<?php
$json = '{"foo-bar": 12345}';
$obj = json_decode($json);
print $obj->{'foo-bar'}; // 12345
?>
Пример #3 common mistakes using json_decode()
<?php
// the following strings are valid JavaScript but not valid JSON
// the name and value must be enclosed in double quotes
// single quotes are not valid
$bad_json = "{ 'bar': 'baz' }";
json_decode($bad_json); // null
// the name must be enclosed in double quotes
$bad_json = '{ bar: "baz" }';
json_decode($bad_json); // null
// trailing commas are not allowed
$bad_json = '{ bar: "baz", }';
json_decode($bad_json); // null
?>
Примечания
Замечание: The JSON spec is not JavaScript, but a subset of JavaScript.
Предостережение
This function will return false if the JSON encoded data is deeper than 127 elements.
Список изменений
| Версия | Описание |
|---|---|
| 5.2.3 | The nesting limit was increased from 20 to 128 |
json_decode
steven at acko dot net
07-Oct-2008 09:49
07-Oct-2008 09:49
jrevillini
26-Sep-2008 09:01
26-Sep-2008 09:01
When decoding strings from the database, make sure the input was encoded with the correct charset when it was input to the database.
I was using a form to create records in the DB which had a content field that was valid JSON, but it included curly apostrophes. If the page with the form did not have
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
in the head, then the data was sent to the database with the wrong encoding. Then, when json_decode tried to convert the string to an object, it failed every time.
soapergem at gmail dot com
23-Aug-2008 08:59
23-Aug-2008 08:59
There have been a couple of comments now alerting us to the fact that certain expressions that are valid JavaScript code are not permitted within json_decode. However, keep in mind that JSON is ***not*** JavaScript, but instead just a subset of JavaScript. As far as I can tell, this function is only allowing whatever is explicitly outlined in RFC 4627, the JSON spec.
For instance, ganswijk, the reason you can't use single quotes to enclose strings is because the spec makes no mention of allowing single quotes (and therefore they are not allowed). And the issue of adding an extra comma at the end of an array is likewise not technically permitted in strict JSON, even though it will work in JavaScript.
And xris, while the example you provided with an unenclosed string key within an object is valid JavaScript, JavaScript != JSON. If you read it closely, you'll see that the JSON spec clearly does not allow this. All JSON object keys must be enclosed in double-quotes.
Basically, if there's ever any question for what is permitted, just read the JSON spec: http://tools.ietf.org/html/rfc4627
bizarr3_2006 at yahoo dot com
06-Aug-2008 04:47
06-Aug-2008 04:47
If json_decode() failes, returns null, or returns 1, you should check the data you are sending to decode...
Check this online JSON validator... It sure helped me a lot.
http://www.jsonlint.com/
ganswijk at xs4all dot nl
07-Jul-2008 04:42
07-Jul-2008 04:42
It was quite hard to figure out the allowed Javascript formats. Some extra remarks:
json_decode() doesn't seem to allow single quotes:
<?php
print_r(json_decode('[0,{"a":"a","b":"b"},2,3]')); //works
print_r(json_decode("[0,{'a':'a','b':'b'},2,3]")); //doesn't work
?>
json_decode() doesn't allow an extra comma in a list of entries:
<?php
print_r(json_decode('[0,1 ]')); //works
print_r(json_decode('[0,1,]')); //doesn't work
?>
(I like to write a comma behind every entry when the entries are spread over several lines.)
json_decode() does allow linefeeds in the data!
?>
xris / a t/ basilicom.de
27-Jun-2008 05:48
27-Jun-2008 05:48
Please note: in javascript, the following is a valid object:
<?php
{ bar: "baz" }
?>
While PHP needs double quotes:
<?php
{ "bar": "baz" }
?>
phpben
16-Apr-2008 09:18
16-Apr-2008 09:18
Re requiring to escape the forward slash:
I think PHP 5.2.1 had that problem, as I remember it occurring here when I posted that comment; but now I'm on 5.2.5 it doesn't, so it has obviously been fixed. The JSON one gets from all the browsers escape the forward slashes anyway.
Hayley Watson
08-Apr-2008 11:40
08-Apr-2008 11:40
@AMA3:
"It's strange that forward-slash is permitted to be escaped but not required to be, and that it has the same meaning either way, but that's how it's written, and so shall it be."
JavaScript ignores '\' characters that don't start any sort of escape sequence, so as far as it is concerned, "\/" is equivalent to "/" (ECMA-262, §7.8.4). So in that sense it's permitted but not required to be: so why do it?
json_encode("</script>") will produce "<\/script>" so that HTML parsers don't see a </script> end tag and choke on it (to play it safe and simplify the implementation, it escapes all '/'s); json_decode() therefore has to cope with that.
As for it being necessary, I agree: it isn't on MY machine :)
json_decode('{"a":"<p>test<\/p>"}'); ==> (object)array('a' => '<p>test</p>');
json_decode('{"a":"<p>test</p>"}'); ==> (object)array('a' => '<p>test</p>');
Hayley Watson
08-Apr-2008 11:04
08-Apr-2008 11:04
In relation to yasarbayar's comment:
Remember that JSON strings are JavaScript code and have JavaScript syntax. In PHP, arrays and associative arrays are the same thing but that's not true in JavaScript, where "associative arrays" are really objects. [] is an array initializer, {} creates objects:
{30:'13',31:'14',32:'15'}
Bad: JavaScript object initialiser, but object property names can't be integers.
{[30:'13',31:'14',32:'15']}
{["30":"13","31":"14","32":"15"]}
Bad: JavaScript object initializer, but a JavaScript array is not a valid property name. Also, JavaScript arrays are not
associative, and their initializers do not use object property syntax to specify their values.
[{"30":"13","31":"14","32":"15"}]
Good: An array initializer with a single element; that element is initialized as an object with properties named "30", "31", "32" and
values "13", "14", "15" (all strings).
"It took me a while to find the right JSON string format...."
You could have used json_encode() to do that :)
steve at weblite dot ca
25-Jan-2008 12:25
25-Jan-2008 12:25
For JSON support in older versions of PHP you can use the Services_JSON class, available at http://pear.php.net/pepr/pepr-proposal-show.php?id=198
<?php
if ( !function_exists('json_decode') ){
function json_decode($content, $assoc=false){
require_once 'Services/JSON.php';
if ( $assoc ){
$json = new Services_JSON(SERVICES_JSON_LOOSE_TYPE);
} else {
$json = new Services_JSON;
}
return $json->decode($content);
}
}
if ( !function_exists('json_encode') ){
function json_encode($content){
require_once 'Services/JSON.php';
$json = new Services_JSON;
return $json->encode($content);
}
}
?>
yasarbayar at gmail dot com
26-Jul-2007 11:13
26-Jul-2007 11:13
It took me a while to find the right JSON string format grabbed from mysql to be used in json_decode(). Here is what i came up with:
Bad(s) (return NULL):
{30:'13',31:'14',32:'15'}
{[30:'13',31:'14',32:'15']}
{["30":"13","31":"14","32":"15"]}
Good :
[{"30":"13","31":"14","32":"15"}]
returns:
array(1) { [0]=> array(3) { [30]=> string(2) "13" [31]=> string(2) "14" [32]=> string(2) "15" } }
hope this saves sometime..
AMA3
21-Jul-2007 03:02
21-Jul-2007 03:02
phpben at hood dot id dot au wrote:
> AFAICT. The JSON docs seem to say that '"','/' and '\' must be quoted with a '\'
At first glance, it seems that way, but if you read the RFC (4627) carefully, forward-slash (/) *may* be escaped but need not be. Specifically, Section 2.5 defines the following:
string = quotation-mark *char quotation-mark
char = unescaped / ...
unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
Forward slash falls in the second range of unescaped characters, at %x2F.
It's strange that forward-slash is permitted to be escaped but not required to be, and that it has the same meaning either way, but that's how it's written, and so shall it be.
FMI: http://www.ietf.org/rfc/rfc4627.txt
phpben at hood dot id dot au
25-May-2007 04:43
25-May-2007 04:43
whatifif at yahoo dot com said something about a bug:
"When I try to decode JSON string {"a":"<p>test</p>"} into array on server-side, it fails."
That is not a valid JSON string, AFAICT. The JSON docs seem to say that '"','/' and '\' must be quoted with a '\'
$ php -r 'echo json_encode("<p>test</p>");'
"<p>test<\/p>"
So it was your '/' character screwing it over.
You probably shouldn't blindly run stripslashes on your $input either! The only time you would is if magic_quotes_gpc is turned on and your string is coming from one of the GPC.
I inherited some PHP code which used Services_JSON. It stopped working when we upgraded PHP and started using this function. The problem was they ran html_entity_decode() over the input and was being turned into a character incompatible with UTF-8.
nospam (AT) hjcms (DOT) de
22-Apr-2007 06:15
22-Apr-2007 06:15
You can't transport Objects or serialize Classes, json_* replace it bei stdClass!
<?php
$dom = new DomDocument( '1.0', 'utf-8' );
$body = $dom->appendChild( $dom->createElement( "body" ) );
$body->appendChild( $dom->createElement( "forward", "Hallo" ) );
$JSON_STRING = json_encode(
array(
"aArray" => range( "a", "z" ),
"bArray" => range( 1, 50 ),
"cArray" => range( 1, 50, 5 ),
"String" => "Value",
"stdClass" => $dom,
"XML" => $dom->saveXML()
)
);
unset( $dom );
$Search = "XML";
$MyStdClass = json_decode( $JSON_STRING );
// var_dump( "<pre>" , $MyStdClass , "</pre>" );
try {
throw new Exception( "$Search isn't a Instance of 'stdClass' Class by json_decode()." );
if ( $MyStdClass->$Search instanceof $MyStdClass )
var_dump( "<pre>instanceof:" , $MyStdClass->$Search , "</pre>" );
} catch( Exception $ErrorHandle ) {
echo $ErrorHandle->getMessage();
if ( property_exists( $MyStdClass, $Search ) ) {
$dom = new DomDocument( "1.0", "utf-8" );
$dom->loadXML( $MyStdClass->$Search );
$body = $dom->getElementsByTagName( "body" )->item(0);
$body->appendChild( $dom->createElement( "rewind", "Nice" ) );
var_dump( htmlentities( $dom->saveXML(), ENT_QUOTES, 'utf-8' ) );
}
}
?>
paul at sfdio dot com
21-Jan-2007 04:08
21-Jan-2007 04:08
I've written a javascript function to get around this functions limitations and the limitations imposed by IE's lack of native support for json serialization. Rather than converting variables to a json formatted string to transfer them to the server this function converts any javascript variable to a string serialized for use as POST or GET data.
String js2php(Mixed);
js2php({foo:true, bar:false, baz: {a:1, b:2, c:[1, 2, 3]}}));
will return:
foo=true&bar=false&baz[a]=1&baz[b]=2&baz[c][0]=1&...etc
function js2php(obj,path,new_path) {
if (typeof(path) == 'undefined') var path=[];
if (typeof(new_path) != 'undefined') path.push(new_path);
var post_str = [];
if (typeof(obj) == 'array' || typeof(obj) == 'object') {
for (var n in obj) {
post_str.push(js2php(obj[n],path,n));
}
}
else if (typeof(obj) != 'function') {
var base = path.shift();
post_str.push(base + (path.length > 0 ? '[' + path.join('][') + ']' : '') + '=' + encodeURI(obj));
path.unshift(base);
}
path.pop();
return post_str.join('&');
}
Adrian Ziemkowski
13-Dec-2006 08:52
13-Dec-2006 08:52
Beware when decoding JSON from JavaScript. Almost nobody uses quotes for object property names and none of the major browsers require it, but this function does! {a:1} will decode as NULL, whereas the ugly {"a":1} will decode correctly. Luckily the browsers accept the specification-style quotes as well.
giunta dot gaetano at sea-aeroportimilano dot it
04-Sep-2006 05:16
04-Sep-2006 05:16
Take care that json_decode() returns UTF8 encoded strings, whereas PHP normally works with iso-8859-1 characters.
If you expect to receive json data comprising characters outside the ascii range, be sure to use utf8_decode to convert them:
$php_vlaues = utf8_decode(json_decode($somedata))
giunta dot gaetano at sea-aeroportimilano dot it
04-Sep-2006 12:20
04-Sep-2006 12:20
Please note that this function does NOT convert back to PHP values all strings resulting from a call to json-encode.
Since the json spec says that "A JSON text is a serialized object or array", this function will return NULL when decoding any json string that does not represent either an object or an array.
To successfully encode + decode single php values such as strings, booleans, integers or floats, you will have to wrap them in an array before converting them.
