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