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