1 /*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | https://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Author: Omar Kilani <omar@php.net> |
14 | Jakub Zelenka <bukka@php.net> |
15 +----------------------------------------------------------------------+
16 */
17
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21
22 #include "php.h"
23 #include "php_ini.h"
24 #include "ext/standard/info.h"
25 #include "ext/standard/html.h"
26 #include "zend_smart_str.h"
27 #include "php_json.h"
28 #include "php_json_encoder.h"
29 #include "php_json_parser.h"
30 #include "json_arginfo.h"
31 #include <zend_exceptions.h>
32
33 static PHP_MINFO_FUNCTION(json);
34
35 PHP_JSON_API zend_class_entry *php_json_serializable_ce;
36 PHP_JSON_API zend_class_entry *php_json_exception_ce;
37
ZEND_DECLARE_MODULE_GLOBALS(json)38 PHP_JSON_API ZEND_DECLARE_MODULE_GLOBALS(json)
39
40 /* Register constant for options and errors */
41 #define PHP_JSON_REGISTER_CONSTANT(_name, _value) \
42 REGISTER_LONG_CONSTANT(_name, _value, CONST_CS | CONST_PERSISTENT);
43
44 /* {{{ MINIT */
45 static PHP_MINIT_FUNCTION(json)
46 {
47 php_json_serializable_ce = register_class_JsonSerializable();
48
49 php_json_exception_ce = register_class_JsonException(zend_ce_exception);
50
51 /* options for json_encode */
52 PHP_JSON_REGISTER_CONSTANT("JSON_HEX_TAG", PHP_JSON_HEX_TAG);
53 PHP_JSON_REGISTER_CONSTANT("JSON_HEX_AMP", PHP_JSON_HEX_AMP);
54 PHP_JSON_REGISTER_CONSTANT("JSON_HEX_APOS", PHP_JSON_HEX_APOS);
55 PHP_JSON_REGISTER_CONSTANT("JSON_HEX_QUOT", PHP_JSON_HEX_QUOT);
56 PHP_JSON_REGISTER_CONSTANT("JSON_FORCE_OBJECT", PHP_JSON_FORCE_OBJECT);
57 PHP_JSON_REGISTER_CONSTANT("JSON_NUMERIC_CHECK", PHP_JSON_NUMERIC_CHECK);
58 PHP_JSON_REGISTER_CONSTANT("JSON_UNESCAPED_SLASHES", PHP_JSON_UNESCAPED_SLASHES);
59 PHP_JSON_REGISTER_CONSTANT("JSON_PRETTY_PRINT", PHP_JSON_PRETTY_PRINT);
60 PHP_JSON_REGISTER_CONSTANT("JSON_UNESCAPED_UNICODE", PHP_JSON_UNESCAPED_UNICODE);
61 PHP_JSON_REGISTER_CONSTANT("JSON_PARTIAL_OUTPUT_ON_ERROR", PHP_JSON_PARTIAL_OUTPUT_ON_ERROR);
62 PHP_JSON_REGISTER_CONSTANT("JSON_PRESERVE_ZERO_FRACTION", PHP_JSON_PRESERVE_ZERO_FRACTION);
63 PHP_JSON_REGISTER_CONSTANT("JSON_UNESCAPED_LINE_TERMINATORS", PHP_JSON_UNESCAPED_LINE_TERMINATORS);
64
65 /* options for json_decode */
66 PHP_JSON_REGISTER_CONSTANT("JSON_OBJECT_AS_ARRAY", PHP_JSON_OBJECT_AS_ARRAY);
67 PHP_JSON_REGISTER_CONSTANT("JSON_BIGINT_AS_STRING", PHP_JSON_BIGINT_AS_STRING);
68
69 /* common options for json_decode and json_encode */
70 PHP_JSON_REGISTER_CONSTANT("JSON_INVALID_UTF8_IGNORE", PHP_JSON_INVALID_UTF8_IGNORE);
71 PHP_JSON_REGISTER_CONSTANT("JSON_INVALID_UTF8_SUBSTITUTE", PHP_JSON_INVALID_UTF8_SUBSTITUTE);
72 PHP_JSON_REGISTER_CONSTANT("JSON_THROW_ON_ERROR", PHP_JSON_THROW_ON_ERROR);
73
74 /* json error constants */
75 PHP_JSON_REGISTER_CONSTANT("JSON_ERROR_NONE", PHP_JSON_ERROR_NONE);
76 PHP_JSON_REGISTER_CONSTANT("JSON_ERROR_DEPTH", PHP_JSON_ERROR_DEPTH);
77 PHP_JSON_REGISTER_CONSTANT("JSON_ERROR_STATE_MISMATCH", PHP_JSON_ERROR_STATE_MISMATCH);
78 PHP_JSON_REGISTER_CONSTANT("JSON_ERROR_CTRL_CHAR", PHP_JSON_ERROR_CTRL_CHAR);
79 PHP_JSON_REGISTER_CONSTANT("JSON_ERROR_SYNTAX", PHP_JSON_ERROR_SYNTAX);
80 PHP_JSON_REGISTER_CONSTANT("JSON_ERROR_UTF8", PHP_JSON_ERROR_UTF8);
81 PHP_JSON_REGISTER_CONSTANT("JSON_ERROR_RECURSION", PHP_JSON_ERROR_RECURSION);
82 PHP_JSON_REGISTER_CONSTANT("JSON_ERROR_INF_OR_NAN", PHP_JSON_ERROR_INF_OR_NAN);
83 PHP_JSON_REGISTER_CONSTANT("JSON_ERROR_UNSUPPORTED_TYPE", PHP_JSON_ERROR_UNSUPPORTED_TYPE);
84 PHP_JSON_REGISTER_CONSTANT("JSON_ERROR_INVALID_PROPERTY_NAME", PHP_JSON_ERROR_INVALID_PROPERTY_NAME);
85 PHP_JSON_REGISTER_CONSTANT("JSON_ERROR_UTF16", PHP_JSON_ERROR_UTF16);
86 PHP_JSON_REGISTER_CONSTANT("JSON_ERROR_NON_BACKED_ENUM", PHP_JSON_ERROR_NON_BACKED_ENUM);
87
88 return SUCCESS;
89 }
90 /* }}} */
91
92 /* {{{ PHP_GINIT_FUNCTION */
PHP_GINIT_FUNCTION(json)93 static PHP_GINIT_FUNCTION(json)
94 {
95 #if defined(COMPILE_DL_JSON) && defined(ZTS)
96 ZEND_TSRMLS_CACHE_UPDATE();
97 #endif
98 json_globals->encoder_depth = 0;
99 json_globals->error_code = 0;
100 json_globals->encode_max_depth = PHP_JSON_PARSER_DEFAULT_DEPTH;
101 }
102 /* }}} */
103
PHP_RINIT_FUNCTION(json)104 static PHP_RINIT_FUNCTION(json)
105 {
106 JSON_G(error_code) = 0;
107 return SUCCESS;
108 }
109
110 /* {{{ json_module_entry */
111 zend_module_entry json_module_entry = {
112 STANDARD_MODULE_HEADER,
113 "json",
114 ext_functions,
115 PHP_MINIT(json),
116 NULL,
117 PHP_RINIT(json),
118 NULL,
119 PHP_MINFO(json),
120 PHP_JSON_VERSION,
121 PHP_MODULE_GLOBALS(json),
122 PHP_GINIT(json),
123 NULL,
124 NULL,
125 STANDARD_MODULE_PROPERTIES_EX
126 };
127 /* }}} */
128
129 #ifdef COMPILE_DL_JSON
130 #ifdef ZTS
131 ZEND_TSRMLS_CACHE_DEFINE()
132 #endif
ZEND_GET_MODULE(json)133 ZEND_GET_MODULE(json)
134 #endif
135
136 /* {{{ PHP_MINFO_FUNCTION */
137 static PHP_MINFO_FUNCTION(json)
138 {
139 php_info_print_table_start();
140 php_info_print_table_row(2, "json support", "enabled");
141 php_info_print_table_end();
142 }
143 /* }}} */
144
php_json_encode_string(const char * s,size_t len,int options)145 PHP_JSON_API zend_string *php_json_encode_string(const char *s, size_t len, int options)
146 {
147 smart_str buf = {0};
148 php_json_encoder encoder;
149
150 php_json_encode_init(&encoder);
151
152 if (php_json_escape_string(&buf, s, len, options, &encoder) == FAILURE) {
153 smart_str_free(&buf);
154 return NULL;
155 }
156
157 return smart_str_extract(&buf);
158 }
159
php_json_encode_ex(smart_str * buf,zval * val,int options,zend_long depth)160 PHP_JSON_API int php_json_encode_ex(smart_str *buf, zval *val, int options, zend_long depth) /* {{{ */
161 {
162 php_json_encoder encoder;
163 int return_code;
164
165 php_json_encode_init(&encoder);
166 encoder.max_depth = depth;
167
168 return_code = php_json_encode_zval(buf, val, options, &encoder);
169 JSON_G(error_code) = encoder.error_code;
170
171 return return_code;
172 }
173 /* }}} */
174
php_json_encode(smart_str * buf,zval * val,int options)175 PHP_JSON_API int php_json_encode(smart_str *buf, zval *val, int options) /* {{{ */
176 {
177 return php_json_encode_ex(buf, val, options, JSON_G(encode_max_depth));
178 }
179 /* }}} */
180
php_json_get_error_msg(php_json_error_code error_code)181 static const char *php_json_get_error_msg(php_json_error_code error_code) /* {{{ */
182 {
183 switch(error_code) {
184 case PHP_JSON_ERROR_NONE:
185 return "No error";
186 case PHP_JSON_ERROR_DEPTH:
187 return "Maximum stack depth exceeded";
188 case PHP_JSON_ERROR_STATE_MISMATCH:
189 return "State mismatch (invalid or malformed JSON)";
190 case PHP_JSON_ERROR_CTRL_CHAR:
191 return "Control character error, possibly incorrectly encoded";
192 case PHP_JSON_ERROR_SYNTAX:
193 return "Syntax error";
194 case PHP_JSON_ERROR_UTF8:
195 return "Malformed UTF-8 characters, possibly incorrectly encoded";
196 case PHP_JSON_ERROR_RECURSION:
197 return "Recursion detected";
198 case PHP_JSON_ERROR_INF_OR_NAN:
199 return "Inf and NaN cannot be JSON encoded";
200 case PHP_JSON_ERROR_UNSUPPORTED_TYPE:
201 return "Type is not supported";
202 case PHP_JSON_ERROR_INVALID_PROPERTY_NAME:
203 return "The decoded property name is invalid";
204 case PHP_JSON_ERROR_UTF16:
205 return "Single unpaired UTF-16 surrogate in unicode escape";
206 case PHP_JSON_ERROR_NON_BACKED_ENUM:
207 return "Non-backed enums have no default serialization";
208 default:
209 return "Unknown error";
210 }
211 }
212 /* }}} */
213
php_json_decode_ex(zval * return_value,const char * str,size_t str_len,zend_long options,zend_long depth)214 PHP_JSON_API int php_json_decode_ex(zval *return_value, const char *str, size_t str_len, zend_long options, zend_long depth) /* {{{ */
215 {
216 php_json_parser parser;
217
218 php_json_parser_init(&parser, return_value, str, str_len, (int)options, (int)depth);
219
220 if (php_json_yyparse(&parser)) {
221 php_json_error_code error_code = php_json_parser_error_code(&parser);
222 if (!(options & PHP_JSON_THROW_ON_ERROR)) {
223 JSON_G(error_code) = error_code;
224 } else {
225 zend_throw_exception(php_json_exception_ce, php_json_get_error_msg(error_code), error_code);
226 }
227 RETVAL_NULL();
228 return FAILURE;
229 }
230
231 return SUCCESS;
232 }
233 /* }}} */
234
235 /* {{{ Returns the JSON representation of a value */
PHP_FUNCTION(json_encode)236 PHP_FUNCTION(json_encode)
237 {
238 zval *parameter;
239 php_json_encoder encoder;
240 smart_str buf = {0};
241 zend_long options = 0;
242 zend_long depth = PHP_JSON_PARSER_DEFAULT_DEPTH;
243
244 ZEND_PARSE_PARAMETERS_START(1, 3)
245 Z_PARAM_ZVAL(parameter)
246 Z_PARAM_OPTIONAL
247 Z_PARAM_LONG(options)
248 Z_PARAM_LONG(depth)
249 ZEND_PARSE_PARAMETERS_END();
250
251 php_json_encode_init(&encoder);
252 encoder.max_depth = (int)depth;
253 php_json_encode_zval(&buf, parameter, (int)options, &encoder);
254
255 if (!(options & PHP_JSON_THROW_ON_ERROR) || (options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR)) {
256 JSON_G(error_code) = encoder.error_code;
257 if (encoder.error_code != PHP_JSON_ERROR_NONE && !(options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR)) {
258 smart_str_free(&buf);
259 RETURN_FALSE;
260 }
261 } else {
262 if (encoder.error_code != PHP_JSON_ERROR_NONE) {
263 smart_str_free(&buf);
264 zend_throw_exception(php_json_exception_ce, php_json_get_error_msg(encoder.error_code), encoder.error_code);
265 RETURN_THROWS();
266 }
267 }
268
269 smart_str_0(&buf); /* copy? */
270 if (buf.s) {
271 RETURN_NEW_STR(buf.s);
272 }
273 RETURN_EMPTY_STRING();
274 }
275 /* }}} */
276
277 /* {{{ Decodes the JSON representation into a PHP value */
PHP_FUNCTION(json_decode)278 PHP_FUNCTION(json_decode)
279 {
280 char *str;
281 size_t str_len;
282 bool assoc = 0; /* return JS objects as PHP objects by default */
283 bool assoc_null = 1;
284 zend_long depth = PHP_JSON_PARSER_DEFAULT_DEPTH;
285 zend_long options = 0;
286
287 ZEND_PARSE_PARAMETERS_START(1, 4)
288 Z_PARAM_STRING(str, str_len)
289 Z_PARAM_OPTIONAL
290 Z_PARAM_BOOL_OR_NULL(assoc, assoc_null)
291 Z_PARAM_LONG(depth)
292 Z_PARAM_LONG(options)
293 ZEND_PARSE_PARAMETERS_END();
294
295 if (!(options & PHP_JSON_THROW_ON_ERROR)) {
296 JSON_G(error_code) = PHP_JSON_ERROR_NONE;
297 }
298
299 if (!str_len) {
300 if (!(options & PHP_JSON_THROW_ON_ERROR)) {
301 JSON_G(error_code) = PHP_JSON_ERROR_SYNTAX;
302 } else {
303 zend_throw_exception(php_json_exception_ce, php_json_get_error_msg(PHP_JSON_ERROR_SYNTAX), PHP_JSON_ERROR_SYNTAX);
304 }
305 RETURN_NULL();
306 }
307
308 if (depth <= 0) {
309 zend_argument_value_error(3, "must be greater than 0");
310 RETURN_THROWS();
311 }
312
313 if (depth > INT_MAX) {
314 zend_argument_value_error(3, "must be less than %d", INT_MAX);
315 RETURN_THROWS();
316 }
317
318 /* For BC reasons, the bool $assoc overrides the long $options bit for PHP_JSON_OBJECT_AS_ARRAY */
319 if (!assoc_null) {
320 if (assoc) {
321 options |= PHP_JSON_OBJECT_AS_ARRAY;
322 } else {
323 options &= ~PHP_JSON_OBJECT_AS_ARRAY;
324 }
325 }
326
327 php_json_decode_ex(return_value, str, str_len, options, depth);
328 }
329 /* }}} */
330
331 /* {{{ Returns the error code of the last json_encode() or json_decode() call. */
PHP_FUNCTION(json_last_error)332 PHP_FUNCTION(json_last_error)
333 {
334 ZEND_PARSE_PARAMETERS_NONE();
335
336 RETURN_LONG(JSON_G(error_code));
337 }
338 /* }}} */
339
340 /* {{{ Returns the error string of the last json_encode() or json_decode() call. */
PHP_FUNCTION(json_last_error_msg)341 PHP_FUNCTION(json_last_error_msg)
342 {
343 ZEND_PARSE_PARAMETERS_NONE();
344
345 RETURN_STRING(php_json_get_error_msg(JSON_G(error_code)));
346 }
347 /* }}} */
348