PHP's json_decode in JavaScript

Here’s what our current JavaScript equivalent to PHP's json_decode looks like.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
module.exports = function json_decode (strJson) { // eslint-disable-line camelcase
// 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
// note 1: If node or the browser does not offer JSON.parse,
// note 1: this function falls backslash
// note 1: to its own implementation using eval, and hence should be considered unsafe
// example 1: json_decode('[ 1 ]')
// returns 1: [1]

/*
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 $global = (typeof window !== 'undefined' ? window : global)
$global.$locutus = $global.$locutus || {}
var $locutus = $global.$locutus
$locutus.php = $locutus.php || {}

var json = $global.JSON
if (typeof json === 'object' && typeof json.parse === 'function') {
try {
return json.parse(strJson)
} catch (err) {
if (!(err instanceof SyntaxError)) {
throw new Error('Unexpected error type in json_decode()')
}

// usable by json_last_error()
$locutus.php.last_error_json = 4
return null
}
}

var chars = [
'\u0000',
'\u00ad',
'\u0600-\u0604',
'\u070f',
'\u17b4',
'\u17b5',
'\u200c-\u200f',
'\u2028-\u202f',
'\u2060-\u206f',
'\ufeff',
'\ufff0-\uffff'
].join('')
var cx = new RegExp('[' + chars + ']', 'g')
var j
var text = strJson

// 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.

var m = (/^[\],:{}\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, ''))

if (m) {
// 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 + ')') // eslint-disable-line no-eval
return j
}

// usable by json_last_error()
$locutus.php.last_error_json = 4
return null
}
[ View on GitHub | Edit on GitHub | Source on GitHub ]

How to use

You you can install via npm install locutus and require it via require('locutus/php/json/json_decode'). You could also require the json module in full so that you could access json.json_decode instead.

If you intend to target the browser, you can then use a module bundler such as Browserify, webpack or rollup.js.

ES5/ES6

This function targets ES5, but as of Locutus 2.0.2 we also support ES6 functions. Locutus transpiles to ES5 before publishing to npm.

A community effort

Not unlike Wikipedia, Locutus is an ongoing community effort. Our philosophy follows The McDonald’s Theory. This means that we don't consider it to be a bad thing that many of our functions are first iterations, which may still have their fair share of issues. We hope that these flaws will inspire others to come up with better ideas.

This way of working also means that we don't offer any production guarantees, and recommend to use Locutus inspiration and learning purposes only.

Notes

  • If node or the browser does not offer JSON.parse, this function falls backslash to its own implementation using eval, and hence should be considered unsafe

Examples

Please note that these examples are distilled from test cases that automatically verify our functions still work correctly. This could explain some quirky ones.

#codeexpected result
1json_decode('[ 1 ]')[1]

« More PHP json functions