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