xref: /PHP-8.4/ext/json/json.c (revision c44834d8)
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 "ext/standard/info.h"
24 #include "zend_smart_str.h"
25 #include "php_json.h"
26 #include "php_json_encoder.h"
27 #include "php_json_parser.h"
28 #include "json_arginfo.h"
29 #include <zend_exceptions.h>
30 
31 static PHP_MINFO_FUNCTION(json);
32 
33 PHP_JSON_API zend_class_entry *php_json_serializable_ce;
34 PHP_JSON_API zend_class_entry *php_json_exception_ce;
35 
ZEND_DECLARE_MODULE_GLOBALS(json)36 PHP_JSON_API ZEND_DECLARE_MODULE_GLOBALS(json)
37 
38 static int php_json_implement_json_serializable(zend_class_entry *interface, zend_class_entry *class_type)
39 {
40 	class_type->ce_flags |= ZEND_ACC_USE_GUARDS;
41 	return SUCCESS;
42 }
43 
44 /* {{{ MINIT */
PHP_MINIT_FUNCTION(json)45 static PHP_MINIT_FUNCTION(json)
46 {
47 	php_json_serializable_ce = register_class_JsonSerializable();
48 	php_json_serializable_ce->interface_gets_implemented = php_json_implement_json_serializable;
49 
50 	php_json_exception_ce = register_class_JsonException(zend_ce_exception);
51 
52 	register_json_symbols(module_number);
53 
54 	return SUCCESS;
55 }
56 /* }}} */
57 
58 /* {{{ PHP_GINIT_FUNCTION */
PHP_GINIT_FUNCTION(json)59 static PHP_GINIT_FUNCTION(json)
60 {
61 #if defined(COMPILE_DL_JSON) && defined(ZTS)
62 	ZEND_TSRMLS_CACHE_UPDATE();
63 #endif
64 	json_globals->encoder_depth = 0;
65 	json_globals->error_code = 0;
66 	json_globals->encode_max_depth = PHP_JSON_PARSER_DEFAULT_DEPTH;
67 }
68 /* }}} */
69 
PHP_RINIT_FUNCTION(json)70 static PHP_RINIT_FUNCTION(json)
71 {
72 	JSON_G(error_code) = 0;
73 	return SUCCESS;
74 }
75 
76 /* {{{ json_module_entry */
77 zend_module_entry json_module_entry = {
78 	STANDARD_MODULE_HEADER,
79 	"json",
80 	ext_functions,
81 	PHP_MINIT(json),
82 	NULL,
83 	PHP_RINIT(json),
84 	NULL,
85 	PHP_MINFO(json),
86 	PHP_JSON_VERSION,
87 	PHP_MODULE_GLOBALS(json),
88 	PHP_GINIT(json),
89 	NULL,
90 	NULL,
91 	STANDARD_MODULE_PROPERTIES_EX
92 };
93 /* }}} */
94 
95 #ifdef COMPILE_DL_JSON
96 #ifdef ZTS
97 ZEND_TSRMLS_CACHE_DEFINE()
98 #endif
ZEND_GET_MODULE(json)99 ZEND_GET_MODULE(json)
100 #endif
101 
102 /* {{{ PHP_MINFO_FUNCTION */
103 static PHP_MINFO_FUNCTION(json)
104 {
105 	php_info_print_table_start();
106 	php_info_print_table_row(2, "json support", "enabled");
107 	php_info_print_table_end();
108 }
109 /* }}} */
110 
php_json_encode_string(const char * s,size_t len,int options)111 PHP_JSON_API zend_string *php_json_encode_string(const char *s, size_t len, int options)
112 {
113 	smart_str buf = {0};
114 	php_json_encoder encoder;
115 
116 	php_json_encode_init(&encoder);
117 
118 	if (php_json_escape_string(&buf, s, len, options, &encoder) == FAILURE) {
119 		smart_str_free(&buf);
120 		return NULL;
121 	}
122 
123 	return smart_str_extract(&buf);
124 }
125 
php_json_encode_ex(smart_str * buf,zval * val,int options,zend_long depth)126 PHP_JSON_API zend_result php_json_encode_ex(smart_str *buf, zval *val, int options, zend_long depth) /* {{{ */
127 {
128 	php_json_encoder encoder;
129 	zend_result return_code;
130 
131 	php_json_encode_init(&encoder);
132 	encoder.max_depth = depth;
133 
134 	return_code = php_json_encode_zval(buf, val, options, &encoder);
135 	JSON_G(error_code) = encoder.error_code;
136 
137 	return return_code;
138 }
139 /* }}} */
140 
php_json_encode(smart_str * buf,zval * val,int options)141 PHP_JSON_API zend_result php_json_encode(smart_str *buf, zval *val, int options) /* {{{ */
142 {
143 	return php_json_encode_ex(buf, val, options, JSON_G(encode_max_depth));
144 }
145 /* }}} */
146 
php_json_get_error_msg(php_json_error_code error_code)147 static const char *php_json_get_error_msg(php_json_error_code error_code) /* {{{ */
148 {
149 	switch(error_code) {
150 		case PHP_JSON_ERROR_NONE:
151 			return "No error";
152 		case PHP_JSON_ERROR_DEPTH:
153 			return "Maximum stack depth exceeded";
154 		case PHP_JSON_ERROR_STATE_MISMATCH:
155 			return "State mismatch (invalid or malformed JSON)";
156 		case PHP_JSON_ERROR_CTRL_CHAR:
157 			return "Control character error, possibly incorrectly encoded";
158 		case PHP_JSON_ERROR_SYNTAX:
159 			return "Syntax error";
160 		case PHP_JSON_ERROR_UTF8:
161 			return "Malformed UTF-8 characters, possibly incorrectly encoded";
162 		case PHP_JSON_ERROR_RECURSION:
163 			return "Recursion detected";
164 		case PHP_JSON_ERROR_INF_OR_NAN:
165 			return "Inf and NaN cannot be JSON encoded";
166 		case PHP_JSON_ERROR_UNSUPPORTED_TYPE:
167 			return "Type is not supported";
168 		case PHP_JSON_ERROR_INVALID_PROPERTY_NAME:
169 			return "The decoded property name is invalid";
170 		case PHP_JSON_ERROR_UTF16:
171 			return "Single unpaired UTF-16 surrogate in unicode escape";
172 		case PHP_JSON_ERROR_NON_BACKED_ENUM:
173 			return "Non-backed enums have no default serialization";
174 		default:
175 			return "Unknown error";
176 	}
177 }
178 /* }}} */
179 
php_json_decode_ex(zval * return_value,const char * str,size_t str_len,zend_long options,zend_long depth)180 PHP_JSON_API zend_result php_json_decode_ex(zval *return_value, const char *str, size_t str_len, zend_long options, zend_long depth) /* {{{ */
181 {
182 	php_json_parser parser;
183 
184 	php_json_parser_init(&parser, return_value, str, str_len, (int)options, (int)depth);
185 
186 	if (php_json_yyparse(&parser)) {
187 		php_json_error_code error_code = php_json_parser_error_code(&parser);
188 		if (!(options & PHP_JSON_THROW_ON_ERROR)) {
189 			JSON_G(error_code) = error_code;
190 		} else {
191 			zend_throw_exception(php_json_exception_ce, php_json_get_error_msg(error_code), error_code);
192 		}
193 		RETVAL_NULL();
194 		return FAILURE;
195 	}
196 
197 	return SUCCESS;
198 }
199 /* }}} */
200 
201 /* {{{ */
php_json_validate_ex(const char * str,size_t str_len,zend_long options,zend_long depth)202 PHP_JSON_API bool php_json_validate_ex(const char *str, size_t str_len, zend_long options, zend_long depth)
203 {
204 	php_json_parser parser;
205 	zval tmp;
206 	const php_json_parser_methods* parser_validate_methods = php_json_get_validate_methods();
207 	php_json_parser_init_ex(&parser, &tmp, str, str_len, (int)options, (int)depth, parser_validate_methods);
208 
209 	if (php_json_yyparse(&parser)) {
210 		php_json_error_code error_code = php_json_parser_error_code(&parser);
211 		JSON_G(error_code) = error_code;
212 		return false;
213 	}
214 
215 	return true;
216 }
217 /* }}} */
218 
219 /* {{{ Returns the JSON representation of a value */
PHP_FUNCTION(json_encode)220 PHP_FUNCTION(json_encode)
221 {
222 	zval *parameter;
223 	php_json_encoder encoder;
224 	smart_str buf = {0};
225 	zend_long options = 0;
226 	zend_long depth = PHP_JSON_PARSER_DEFAULT_DEPTH;
227 
228 	ZEND_PARSE_PARAMETERS_START(1, 3)
229 		Z_PARAM_ZVAL(parameter)
230 		Z_PARAM_OPTIONAL
231 		Z_PARAM_LONG(options)
232 		Z_PARAM_LONG(depth)
233 	ZEND_PARSE_PARAMETERS_END();
234 
235 	php_json_encode_init(&encoder);
236 	encoder.max_depth = (int)depth;
237 	php_json_encode_zval(&buf, parameter, (int)options, &encoder);
238 
239 	if (!(options & PHP_JSON_THROW_ON_ERROR) || (options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR)) {
240 		JSON_G(error_code) = encoder.error_code;
241 		if (encoder.error_code != PHP_JSON_ERROR_NONE && !(options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR)) {
242 			smart_str_free(&buf);
243 			RETURN_FALSE;
244 		}
245 	} else {
246 		if (encoder.error_code != PHP_JSON_ERROR_NONE) {
247 			smart_str_free(&buf);
248 			zend_throw_exception(php_json_exception_ce, php_json_get_error_msg(encoder.error_code), encoder.error_code);
249 			RETURN_THROWS();
250 		}
251 	}
252 
253 	RETURN_STR(smart_str_extract(&buf));
254 }
255 /* }}} */
256 
257 /* {{{ Decodes the JSON representation into a PHP value */
PHP_FUNCTION(json_decode)258 PHP_FUNCTION(json_decode)
259 {
260 	char *str;
261 	size_t str_len;
262 	bool assoc = 0; /* return JS objects as PHP objects by default */
263 	bool assoc_null = 1;
264 	zend_long depth = PHP_JSON_PARSER_DEFAULT_DEPTH;
265 	zend_long options = 0;
266 
267 	ZEND_PARSE_PARAMETERS_START(1, 4)
268 		Z_PARAM_STRING(str, str_len)
269 		Z_PARAM_OPTIONAL
270 		Z_PARAM_BOOL_OR_NULL(assoc, assoc_null)
271 		Z_PARAM_LONG(depth)
272 		Z_PARAM_LONG(options)
273 	ZEND_PARSE_PARAMETERS_END();
274 
275 	if (!(options & PHP_JSON_THROW_ON_ERROR)) {
276 		JSON_G(error_code) = PHP_JSON_ERROR_NONE;
277 	}
278 
279 	if (!str_len) {
280 		if (!(options & PHP_JSON_THROW_ON_ERROR)) {
281 			JSON_G(error_code) = PHP_JSON_ERROR_SYNTAX;
282 		} else {
283 			zend_throw_exception(php_json_exception_ce, php_json_get_error_msg(PHP_JSON_ERROR_SYNTAX), PHP_JSON_ERROR_SYNTAX);
284 		}
285 		RETURN_NULL();
286 	}
287 
288 	if (depth <= 0) {
289 		zend_argument_value_error(3, "must be greater than 0");
290 		RETURN_THROWS();
291 	}
292 
293 	if (depth > INT_MAX) {
294 		zend_argument_value_error(3, "must be less than %d", INT_MAX);
295 		RETURN_THROWS();
296 	}
297 
298 	/* For BC reasons, the bool $assoc overrides the long $options bit for PHP_JSON_OBJECT_AS_ARRAY */
299 	if (!assoc_null) {
300 		if (assoc) {
301 			options |=  PHP_JSON_OBJECT_AS_ARRAY;
302 		} else {
303 			options &= ~PHP_JSON_OBJECT_AS_ARRAY;
304 		}
305 	}
306 
307 	php_json_decode_ex(return_value, str, str_len, options, depth);
308 }
309 /* }}} */
310 
311 /* {{{ Validates if a string contains a valid json */
PHP_FUNCTION(json_validate)312 PHP_FUNCTION(json_validate)
313 {
314 	char *str;
315 	size_t str_len;
316 	zend_long depth = PHP_JSON_PARSER_DEFAULT_DEPTH;
317 	zend_long options = 0;
318 
319 	ZEND_PARSE_PARAMETERS_START(1, 3)
320 		Z_PARAM_STRING(str, str_len)
321 		Z_PARAM_OPTIONAL
322 		Z_PARAM_LONG(depth)
323 		Z_PARAM_LONG(options)
324 	ZEND_PARSE_PARAMETERS_END();
325 
326 
327 	if ((options != 0) && (options != PHP_JSON_INVALID_UTF8_IGNORE)) {
328 		zend_argument_value_error(3, "must be a valid flag (allowed flags: JSON_INVALID_UTF8_IGNORE)");
329 		RETURN_THROWS();
330 	}
331 
332 	if (!str_len) {
333 		JSON_G(error_code) = PHP_JSON_ERROR_SYNTAX;
334 		RETURN_FALSE;
335 	}
336 
337 	JSON_G(error_code) = PHP_JSON_ERROR_NONE;
338 
339 	if (depth <= 0) {
340 		zend_argument_value_error(2, "must be greater than 0");
341 		RETURN_THROWS();
342 	}
343 
344 	if (depth > INT_MAX) {
345 		zend_argument_value_error(2, "must be less than %d", INT_MAX);
346 		RETURN_THROWS();
347 	}
348 
349 	RETURN_BOOL(php_json_validate_ex(str, str_len, options, depth));
350 }
351 /* }}} */
352 
353 /* {{{ Returns the error code of the last json_encode() or json_decode() call. */
PHP_FUNCTION(json_last_error)354 PHP_FUNCTION(json_last_error)
355 {
356 	ZEND_PARSE_PARAMETERS_NONE();
357 
358 	RETURN_LONG(JSON_G(error_code));
359 }
360 /* }}} */
361 
362 /* {{{ Returns the error string of the last json_encode() or json_decode() call. */
PHP_FUNCTION(json_last_error_msg)363 PHP_FUNCTION(json_last_error_msg)
364 {
365 	ZEND_PARSE_PARAMETERS_NONE();
366 
367 	RETURN_STRING(php_json_get_error_msg(JSON_G(error_code)));
368 }
369 /* }}} */
370