Use PHP functions in JavaScript

JavaScript json_decode

Decodes the JSON representation into a PHP value

1
2
3
4
56
7
8
9
1011
12
13
14
1516
17
18
19
2021
22
23
24
2526
27
28
29
3031
32
33
34
3536
37
38
39
4041
42
43
44
4546
47
48
49
5051
52
53
54
5556
57
58
59
6061
62
63
64
6566
67
68
69
7071
72
73
74
7576
function json_decode (str_json) {
    // Decodes the JSON representation into a PHP value  
    // 
    // version: 1109.2015
    // discuss at: http://phpjs.org/functions/json_decode    // +      original by: Public Domain (http://www.json.org/json2.js)
    // + reimplemented by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +      improved by: T.J. Leahy
    // +      improved by: Michael White
    // *        example 1: json_decode('[\n    "e",\n    {\n    "pluribus": "unum"\n}\n]');    // *        returns 1: ['e', {pluribus: 'unum'}]
/*
        http://www.JSON.org/json2.js
        2008-11-19
        Public Domain.        NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
        See http://www.JSON.org/js.html
    */
 
    var json = this.window.JSON;    if (typeof json === 'object' && typeof json.parse === 'function') {
        try {
            return json.parse(str_json);
        } catch (err) {
            if (!(err instanceof SyntaxError)) {                throw new Error('Unexpected error type in json_decode()');
            }
            this.php_js = this.php_js || {};
            this.php_js.last_error_json = 4; // usable by json_last_error()
            return null;        }
    }
 
    var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
    var j;    var text = str_json;
 
    // Parsing happens in four stages. In the first stage, we replace certain
    // Unicode characters with escape sequences. JavaScript handles many characters
    // incorrectly, either silently deleting them, or treating them as line endings.    cx.lastIndex = 0;
    if (cx.test(text)) {
        text = text.replace(cx, function (a) {
            return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
        });    }
 
    // In the second stage, we run the text against regular expressions that look
    // for non-JSON patterns. We are especially concerned with '()' and 'new'
    // because they can cause invocation, and '=' because it can cause mutation.    // But just to be safe, we want to reject all unexpected forms.
    // We split the second stage into 4 regexp operations in order to work around
    // crippling inefficiencies in IE's and Safari's regexp engines. First we
    // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
    // replace all simple value tokens with ']' characters. Third, we delete all    // open brackets that follow a colon or comma or that begin the text. Finally,
    // we look to see that the remaining characters are only whitespace or ']' or
    // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
    if ((/^[\],:{}\s]*$/).
    test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').    replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
    replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
 
        // In the third stage we use the eval function to compile the text into a
        // JavaScript structure. The '{' operator is subject to a syntactic ambiguity        // in JavaScript: it can begin a block or an object literal. We wrap the text
        // in parens to eliminate the ambiguity.
        j = eval('(' + text + ')');
 
        return j;    }
 
    this.php_js = this.php_js || {};
    this.php_js.last_error_json = 4; // usable by json_last_error()
    return null;}
external links: original PHP docs | raw js source

Examples

Running

1
json_decode('[\n    "e",\n    {\n    "pluribus": "unum"\n}\n]');

Should return

1
['e', {pluribus: 'unum'}]

Dependencies

No dependencies, you can use this function standalone.

Open syntax issues

php.js uses JsLint to help us keep our code consistent and prevent some common bugs.

Eventually we want all code to pass or at least take into consideration most fixes suggested by JsLint, following this JsLint configuration we’ve decided on.


Authors

Thanks to the following developers, you get to have json_decode goodness in JavaScript.

Comments

Add Comment
Use:
[CODE]
your_stuff('here');
[/CODE]
for proper code formatting
By submitting code here you are allowing us to use it in php.js hence dual licensing it under the MIT and GPL licenses

Gravatar
Brett Zamir
Apr 6th Permalink

q  @Pavel: Ok, good point, but it still suffers from the ability to set globals. So while it may be a little safer, it still doesn't solve the root problem of complete encapsulation, though if the regex are working, eval() will be equally safe. I suggest this be refactored to use a real parser if we're going to do anything about it.

Gravatar
Pavel Kukov
Apr 5th Permalink

q   •eval() evaluates a string as a JavaScript expression within the current execution scope and can affect local variables.
•new Function() parses the JavaScript code stored in a string into a function object, which can then be called. It cannot affect local variables because the code runs in a separate scope.

Gravatar
Brett Zamir
Apr 5th Permalink

q  @Pavel:
1) Function() suffers from the same problem as eval(). So does the first argument to setTimeout or setInterval when set to a string.
2) The function comments mention that the regular expressions are already ensuring that the characters in the expression are safe for evaluation. We could use a genuine parser, as I believe exist at json.org , but I'm not sure that there is anything wrong as long as the regex we are using is fail-safe (except that a real parser should be able to give better reporting of errors).

Gravatar
Pavel Kukov
Apr 4th Permalink

q  On line: #68: eval is evil fix

j=new Function('return '+text); return j();

Gravatar
Brett Zamir
5 Jun '11 Permalink

q  @Miguel: Could you offer your code or a snippet thereof by any chance? I really understood our namespaced version was including this.window, and that in the non-namespaced version, window.window (this.window) was recursively self-referential.

Gravatar
Miguel Espinoza
5 Jun '11 Permalink

q  I ran into a situation today with Firefox 3.6.17 (didnt test with other browsers) and Firebug 1.7.1 where "this.window" was not recognized, it came from a pseudo pop up (div), I fixed this by editing line 20 from:

var json = this.window.JSON;


to:

var json = (typeof this.window != 'undefined' ? this.window.JSON : undefined);

Gravatar
Brett Zamir
15 Dec '10 Permalink

q  @Anes: First make sure you don't have line breaks when you make the string. When I tried pasting your string now, it was broken into separate lines which will not work in JS. If that is fixed, then you can just use it like this:
[CODE]
var obj = json_decode('{"user":"test"}');
alert(obj.user); // 'test'
[CODE]

Gravatar
Anes
15 Dec '10 Permalink

q  Hi pals ,
I am really stuck in parsing a JSON string and take it's values. I got the json string as
{"user":{"id":"1","firstname":"Freelogin","created":"0000-00-00
00:00:00","lastname":"Administrator","email":"fred@websecurify.com",
"usergroup_id":"1","status":"1","ip_enable":"N","priv":"0","expire":""},"data":{
"1":{"5":{"last_update":"2010-12-13
16:16:16","status":"0"},"3":{"last_update":"2010-12-13
16:41:48","status":"1"}},"2":{"6":{"last_update":"2010-12-13
16:41:48","status":"1"}}},"server_array":[{"id":"1","name":"anes.yyy.net"},{
"id":"2","name":"neseema.xxx.net"}],"service_array":[{"id":"5","name":"POP3"},
{"id":"6","name":"Cpanel"},{"id":"3","name":"SMTP"}],"sort_by":"servername",
"sort_order":"ASC","pagelinks":"","totrows":"2","offset":"0","limitvalue":"10",
"rows_monitor":2,"current":"monitor","uri":false}

Friends How to Parse this and take the Results for further
processing in javascript.... I am waiting to hear from you
Soon..

Regards
Anes P.A

Gravatar
Brett Zamir
26 Oct '09 Permalink

q  Have made a fix (NULL to null) and added support for json_last_error(); see commits at http://github.com/kvz/phpjs/commits/master/

Gravatar
Kevin van Zonneveld
25 Oct '09 Permalink

q  @ Michael White: Just now saw your comment on json_encode & implemented the fixes!

http://github.com/kvz/phpjs/commit/cae72555c08c11ec416f1c8ecfcd5e42509cb46d

Gravatar
Kevin van Zonneveld
25 Oct '09 Permalink

q  Yeah we need to look into this. Could be much better but I don't have enough time to work it myself right now. Maybe someone else reading this can have a go at it?
Would be much appreciated!

Gravatar
Michael White
20 Oct '09 Permalink

q  @kevin Hey - sorry. that's my fault. It should indeed return NULL if there's an error. My main point was that we should use the try/catch to prevent exceptions from causing the JS to just stop unexpectedly.

Gravatar
Brett Zamir
18 Oct '09 Permalink

q  @Michael: Thanks, but is that really how PHP handles it? the docs for json_decode say "NULL is returned if the json cannot be decoded or if the encoded data is deeper than the recursion limit." Would be nice if someone could check for all possible json.parse/json.stringify errors (and the rest of the function when these are not available) to check for the type of errors also recorded by json_last_error (and to add a property to the "this.php_js" global so that json_last_error() can retrieve this info). Ditto for json_encode().

Gravatar
Michael White
18 Oct '09 Permalink

q  The part that uses native browser JSON objects should be contained in a try/catch block and return the proper value in accordance with how PHP handles bad JSON data.

try {
    return json.parse(str_json);
}
catch(err) {
    return str_json;
}

Gravatar
Kevin van Zonneveld
18 Jun '09 Permalink

q  @ T.J. Leahy + Brett Zamir: Awesome!

Gravatar
Brett Zamir
18 Jun '09 Permalink

q  Fixed in SVN. Thanks for the report!

FYI, if you reference a variable like JSON and it doesn't exist, it will cause a failure in JS, so we have to either enclose such a reference in a try-catch block (ugly) or reference it as a property of the window object--since referencing an undefined property does not give an error in JS.

As far as why I used "this.window" ("window" would be fine for most environments), it is because this will both refer to:

1) the window object in the non-namespaced version (it resolves to "window.window" which, in JS, thankfully for our needs, happens to be a recursive reference to window), and
2) the window attached to the object itself in the namespaced version (our namespaced version allows for the window to be set to a value other than the global "window" object for environments like JavaScript modules in Firefox extensions where 'window' is not available as a global but is passed in during object construction, and should automatically set it to the window global otherwise).

Gravatar
T.J. Leahy
17 Jun '09 Permalink

q  This function should check to see if the browser has native JSON decoding first (IE8, FF 3.5) and use that when available. Would make it faster and safer then running the input against multiple regular expressions. See http://hacks.mozilla.org/2009/06/security-performance-native-json/

if (typeof JSON == "object" && typeof JSON.parse == "function") {
    return JSON.parse(str_json);
}


Contribute a New function

More functions

In this category

» json_decode
json_encode
json_last_error

Support us

spread the word:


Use any PHP function in JavaScript


These kind folks have already donated: AYHAN BARI*, Nikita Ekshiyan, Nikita Ekshiyan, Petr Pavel, @HalfWinter, Paulo Freitas, Andros Peña Romo, @andorosu, Raimund Szabo, Nitin Gupta, @nikosdion, Anonymous, Anonymous and Shawn Houser.
<your name here>

Click here to lend your support to: phpjs and make a donation at www.pledgie.com !