xref: /php-src/ext/json/json.c (revision 3fe49d81)
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   | http://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 	zend_class_entry ce;
48 
49 	INIT_CLASS_ENTRY(ce, "JsonSerializable", class_JsonSerializable_methods);
50 	php_json_serializable_ce = zend_register_internal_interface(&ce);
51 
52 	INIT_CLASS_ENTRY(ce, "JsonException", NULL);
53 	php_json_exception_ce = zend_register_internal_class_ex(&ce, zend_ce_exception);
54 
55 	/* options for json_encode */
56 	PHP_JSON_REGISTER_CONSTANT("JSON_HEX_TAG",  PHP_JSON_HEX_TAG);
57 	PHP_JSON_REGISTER_CONSTANT("JSON_HEX_AMP",  PHP_JSON_HEX_AMP);
58 	PHP_JSON_REGISTER_CONSTANT("JSON_HEX_APOS", PHP_JSON_HEX_APOS);
59 	PHP_JSON_REGISTER_CONSTANT("JSON_HEX_QUOT", PHP_JSON_HEX_QUOT);
60 	PHP_JSON_REGISTER_CONSTANT("JSON_FORCE_OBJECT", PHP_JSON_FORCE_OBJECT);
61 	PHP_JSON_REGISTER_CONSTANT("JSON_NUMERIC_CHECK", PHP_JSON_NUMERIC_CHECK);
62 	PHP_JSON_REGISTER_CONSTANT("JSON_UNESCAPED_SLASHES", PHP_JSON_UNESCAPED_SLASHES);
63 	PHP_JSON_REGISTER_CONSTANT("JSON_PRETTY_PRINT", PHP_JSON_PRETTY_PRINT);
64 	PHP_JSON_REGISTER_CONSTANT("JSON_UNESCAPED_UNICODE", PHP_JSON_UNESCAPED_UNICODE);
65 	PHP_JSON_REGISTER_CONSTANT("JSON_PARTIAL_OUTPUT_ON_ERROR", PHP_JSON_PARTIAL_OUTPUT_ON_ERROR);
66 	PHP_JSON_REGISTER_CONSTANT("JSON_PRESERVE_ZERO_FRACTION", PHP_JSON_PRESERVE_ZERO_FRACTION);
67 	PHP_JSON_REGISTER_CONSTANT("JSON_UNESCAPED_LINE_TERMINATORS", PHP_JSON_UNESCAPED_LINE_TERMINATORS);
68 
69 	/* options for json_decode */
70 	PHP_JSON_REGISTER_CONSTANT("JSON_OBJECT_AS_ARRAY", PHP_JSON_OBJECT_AS_ARRAY);
71 	PHP_JSON_REGISTER_CONSTANT("JSON_BIGINT_AS_STRING", PHP_JSON_BIGINT_AS_STRING);
72 
73 	/* common options for json_decode and json_encode */
74 	PHP_JSON_REGISTER_CONSTANT("JSON_INVALID_UTF8_IGNORE", PHP_JSON_INVALID_UTF8_IGNORE);
75 	PHP_JSON_REGISTER_CONSTANT("JSON_INVALID_UTF8_SUBSTITUTE", PHP_JSON_INVALID_UTF8_SUBSTITUTE);
76 	PHP_JSON_REGISTER_CONSTANT("JSON_THROW_ON_ERROR", PHP_JSON_THROW_ON_ERROR);
77 
78 	/* json error constants */
79 	PHP_JSON_REGISTER_CONSTANT("JSON_ERROR_NONE", PHP_JSON_ERROR_NONE);
80 	PHP_JSON_REGISTER_CONSTANT("JSON_ERROR_DEPTH", PHP_JSON_ERROR_DEPTH);
81 	PHP_JSON_REGISTER_CONSTANT("JSON_ERROR_STATE_MISMATCH", PHP_JSON_ERROR_STATE_MISMATCH);
82 	PHP_JSON_REGISTER_CONSTANT("JSON_ERROR_CTRL_CHAR", PHP_JSON_ERROR_CTRL_CHAR);
83 	PHP_JSON_REGISTER_CONSTANT("JSON_ERROR_SYNTAX", PHP_JSON_ERROR_SYNTAX);
84 	PHP_JSON_REGISTER_CONSTANT("JSON_ERROR_UTF8", PHP_JSON_ERROR_UTF8);
85 	PHP_JSON_REGISTER_CONSTANT("JSON_ERROR_RECURSION", PHP_JSON_ERROR_RECURSION);
86 	PHP_JSON_REGISTER_CONSTANT("JSON_ERROR_INF_OR_NAN", PHP_JSON_ERROR_INF_OR_NAN);
87 	PHP_JSON_REGISTER_CONSTANT("JSON_ERROR_UNSUPPORTED_TYPE", PHP_JSON_ERROR_UNSUPPORTED_TYPE);
88 	PHP_JSON_REGISTER_CONSTANT("JSON_ERROR_INVALID_PROPERTY_NAME", PHP_JSON_ERROR_INVALID_PROPERTY_NAME);
89 	PHP_JSON_REGISTER_CONSTANT("JSON_ERROR_UTF16", PHP_JSON_ERROR_UTF16);
90 
91 	return SUCCESS;
92 }
93 /* }}} */
94 
95 /* {{{ PHP_GINIT_FUNCTION
96 */
PHP_GINIT_FUNCTION(json)97 static PHP_GINIT_FUNCTION(json)
98 {
99 #if defined(COMPILE_DL_JSON) && defined(ZTS)
100 	ZEND_TSRMLS_CACHE_UPDATE();
101 #endif
102 	json_globals->encoder_depth = 0;
103 	json_globals->error_code = 0;
104 	json_globals->encode_max_depth = PHP_JSON_PARSER_DEFAULT_DEPTH;
105 }
106 /* }}} */
107 
108 
109 /* {{{ json_module_entry
110  */
111 zend_module_entry json_module_entry = {
112 	STANDARD_MODULE_HEADER,
113 	"json",
114 	ext_functions,
115 	PHP_MINIT(json),
116 	NULL,
117 	NULL,
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  */
138 static PHP_MINFO_FUNCTION(json)
139 {
140 	php_info_print_table_start();
141 	php_info_print_table_row(2, "json support", "enabled");
142 	php_info_print_table_end();
143 }
144 /* }}} */
145 
php_json_encode_ex(smart_str * buf,zval * val,int options,zend_long depth)146 PHP_JSON_API int php_json_encode_ex(smart_str *buf, zval *val, int options, zend_long depth) /* {{{ */
147 {
148 	php_json_encoder encoder;
149 	int return_code;
150 
151 	php_json_encode_init(&encoder);
152 	encoder.max_depth = depth;
153 
154 	return_code = php_json_encode_zval(buf, val, options, &encoder);
155 	JSON_G(error_code) = encoder.error_code;
156 
157 	return return_code;
158 }
159 /* }}} */
160 
php_json_encode(smart_str * buf,zval * val,int options)161 PHP_JSON_API int php_json_encode(smart_str *buf, zval *val, int options) /* {{{ */
162 {
163 	return php_json_encode_ex(buf, val, options, JSON_G(encode_max_depth));
164 }
165 /* }}} */
166 
php_json_get_error_msg(php_json_error_code error_code)167 static const char *php_json_get_error_msg(php_json_error_code error_code) /* {{{ */
168 {
169 	switch(error_code) {
170 		case PHP_JSON_ERROR_NONE:
171 			return "No error";
172 		case PHP_JSON_ERROR_DEPTH:
173 			return "Maximum stack depth exceeded";
174 		case PHP_JSON_ERROR_STATE_MISMATCH:
175 			return "State mismatch (invalid or malformed JSON)";
176 		case PHP_JSON_ERROR_CTRL_CHAR:
177 			return "Control character error, possibly incorrectly encoded";
178 		case PHP_JSON_ERROR_SYNTAX:
179 			return "Syntax error";
180 		case PHP_JSON_ERROR_UTF8:
181 			return "Malformed UTF-8 characters, possibly incorrectly encoded";
182 		case PHP_JSON_ERROR_RECURSION:
183 			return "Recursion detected";
184 		case PHP_JSON_ERROR_INF_OR_NAN:
185 			return "Inf and NaN cannot be JSON encoded";
186 		case PHP_JSON_ERROR_UNSUPPORTED_TYPE:
187 			return "Type is not supported";
188 		case PHP_JSON_ERROR_INVALID_PROPERTY_NAME:
189 			return "The decoded property name is invalid";
190 		case PHP_JSON_ERROR_UTF16:
191 			return "Single unpaired UTF-16 surrogate in unicode escape";
192 		default:
193 			return "Unknown error";
194 	}
195 }
196 /* }}} */
197 
php_json_decode_ex(zval * return_value,char * str,size_t str_len,zend_long options,zend_long depth)198 PHP_JSON_API int php_json_decode_ex(zval *return_value, char *str, size_t str_len, zend_long options, zend_long depth) /* {{{ */
199 {
200 	php_json_parser parser;
201 
202 	php_json_parser_init(&parser, return_value, str, str_len, (int)options, (int)depth);
203 
204 	if (php_json_yyparse(&parser)) {
205 		php_json_error_code error_code = php_json_parser_error_code(&parser);
206 		if (!(options & PHP_JSON_THROW_ON_ERROR)) {
207 			JSON_G(error_code) = error_code;
208 		} else {
209 			zend_throw_exception(php_json_exception_ce, php_json_get_error_msg(error_code), error_code);
210 		}
211 		RETVAL_NULL();
212 		return FAILURE;
213 	}
214 
215 	return SUCCESS;
216 }
217 /* }}} */
218 
219 /* {{{ proto string json_encode(mixed data [, int options[, int depth]])
220    Returns the JSON representation of a value */
PHP_FUNCTION(json_encode)221 PHP_FUNCTION(json_encode)
222 {
223 	zval *parameter;
224 	php_json_encoder encoder;
225 	smart_str buf = {0};
226 	zend_long options = 0;
227 	zend_long depth = PHP_JSON_PARSER_DEFAULT_DEPTH;
228 
229 	ZEND_PARSE_PARAMETERS_START(1, 3)
230 		Z_PARAM_ZVAL(parameter)
231 		Z_PARAM_OPTIONAL
232 		Z_PARAM_LONG(options)
233 		Z_PARAM_LONG(depth)
234 	ZEND_PARSE_PARAMETERS_END();
235 
236 	php_json_encode_init(&encoder);
237 	encoder.max_depth = (int)depth;
238 	php_json_encode_zval(&buf, parameter, (int)options, &encoder);
239 
240 	if (!(options & PHP_JSON_THROW_ON_ERROR) || (options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR)) {
241 		JSON_G(error_code) = encoder.error_code;
242 		if (encoder.error_code != PHP_JSON_ERROR_NONE && !(options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR)) {
243 			smart_str_free(&buf);
244 			RETURN_FALSE;
245 		}
246 	} else {
247 		if (encoder.error_code != PHP_JSON_ERROR_NONE) {
248 			smart_str_free(&buf);
249 			zend_throw_exception(php_json_exception_ce, php_json_get_error_msg(encoder.error_code), encoder.error_code);
250 			RETURN_THROWS();
251 		}
252 	}
253 
254 	smart_str_0(&buf); /* copy? */
255 	if (buf.s) {
256 		RETURN_NEW_STR(buf.s);
257 	}
258 	RETURN_EMPTY_STRING();
259 }
260 /* }}} */
261 
262 /* {{{ proto mixed json_decode(string json [, bool assoc [, int depth]])
263    Decodes the JSON representation into a PHP value */
PHP_FUNCTION(json_decode)264 PHP_FUNCTION(json_decode)
265 {
266 	char *str;
267 	size_t str_len;
268 	zend_bool assoc = 0; /* return JS objects as PHP objects by default */
269 	zend_bool assoc_null = 1;
270 	zend_long depth = PHP_JSON_PARSER_DEFAULT_DEPTH;
271 	zend_long options = 0;
272 
273 	ZEND_PARSE_PARAMETERS_START(1, 4)
274 		Z_PARAM_STRING(str, str_len)
275 		Z_PARAM_OPTIONAL
276 		Z_PARAM_BOOL_EX(assoc, assoc_null, 1, 0)
277 		Z_PARAM_LONG(depth)
278 		Z_PARAM_LONG(options)
279 	ZEND_PARSE_PARAMETERS_END();
280 
281 	if (!(options & PHP_JSON_THROW_ON_ERROR)) {
282 		JSON_G(error_code) = PHP_JSON_ERROR_NONE;
283 	}
284 
285 	if (!str_len) {
286 		if (!(options & PHP_JSON_THROW_ON_ERROR)) {
287 			JSON_G(error_code) = PHP_JSON_ERROR_SYNTAX;
288 		} else {
289 			zend_throw_exception(php_json_exception_ce, php_json_get_error_msg(PHP_JSON_ERROR_SYNTAX), PHP_JSON_ERROR_SYNTAX);
290 		}
291 		RETURN_NULL();
292 	}
293 
294 	if (depth <= 0) {
295 		zend_argument_value_error(3, "must be greater than 0");
296 		RETURN_THROWS();
297 	}
298 
299 	if (depth > INT_MAX) {
300 		zend_argument_value_error(3, "must be less than %d", INT_MAX);
301 		RETURN_THROWS();
302 	}
303 
304 	/* For BC reasons, the bool $assoc overrides the long $options bit for PHP_JSON_OBJECT_AS_ARRAY */
305 	if (!assoc_null) {
306 		if (assoc) {
307 			options |=  PHP_JSON_OBJECT_AS_ARRAY;
308 		} else {
309 			options &= ~PHP_JSON_OBJECT_AS_ARRAY;
310 		}
311 	}
312 
313 	php_json_decode_ex(return_value, str, str_len, options, depth);
314 }
315 /* }}} */
316 
317 /* {{{ proto int json_last_error()
318    Returns the error code of the last json_encode() or json_decode() call. */
PHP_FUNCTION(json_last_error)319 PHP_FUNCTION(json_last_error)
320 {
321 	ZEND_PARSE_PARAMETERS_NONE();
322 
323 	RETURN_LONG(JSON_G(error_code));
324 }
325 /* }}} */
326 
327 /* {{{ proto string json_last_error_msg()
328    Returns the error string of the last json_encode() or json_decode() call. */
PHP_FUNCTION(json_last_error_msg)329 PHP_FUNCTION(json_last_error_msg)
330 {
331 	ZEND_PARSE_PARAMETERS_NONE();
332 
333 	RETURN_STRING(php_json_get_error_msg(JSON_G(error_code)));
334 }
335 /* }}} */
336