1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 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_end();
190 }
191 /* }}} */
192
php_json_encode_ex(smart_str * buf,zval * val,int options,zend_long depth)193 PHP_JSON_API int php_json_encode_ex(smart_str *buf, zval *val, int options, zend_long depth) /* {{{ */
194 {
195 php_json_encoder encoder;
196 int return_code;
197
198 php_json_encode_init(&encoder);
199 encoder.max_depth = depth;
200
201 return_code = php_json_encode_zval(buf, val, options, &encoder);
202 JSON_G(error_code) = encoder.error_code;
203
204 return return_code;
205 }
206 /* }}} */
207
php_json_encode(smart_str * buf,zval * val,int options)208 PHP_JSON_API int php_json_encode(smart_str *buf, zval *val, int options) /* {{{ */
209 {
210 return php_json_encode_ex(buf, val, options, JSON_G(encode_max_depth));
211 }
212 /* }}} */
213
php_json_get_error_msg(php_json_error_code error_code)214 static const char *php_json_get_error_msg(php_json_error_code error_code) /* {{{ */
215 {
216 switch(error_code) {
217 case PHP_JSON_ERROR_NONE:
218 return "No error";
219 case PHP_JSON_ERROR_DEPTH:
220 return "Maximum stack depth exceeded";
221 case PHP_JSON_ERROR_STATE_MISMATCH:
222 return "State mismatch (invalid or malformed JSON)";
223 case PHP_JSON_ERROR_CTRL_CHAR:
224 return "Control character error, possibly incorrectly encoded";
225 case PHP_JSON_ERROR_SYNTAX:
226 return "Syntax error";
227 case PHP_JSON_ERROR_UTF8:
228 return "Malformed UTF-8 characters, possibly incorrectly encoded";
229 case PHP_JSON_ERROR_RECURSION:
230 return "Recursion detected";
231 case PHP_JSON_ERROR_INF_OR_NAN:
232 return "Inf and NaN cannot be JSON encoded";
233 case PHP_JSON_ERROR_UNSUPPORTED_TYPE:
234 return "Type is not supported";
235 case PHP_JSON_ERROR_INVALID_PROPERTY_NAME:
236 return "The decoded property name is invalid";
237 case PHP_JSON_ERROR_UTF16:
238 return "Single unpaired UTF-16 surrogate in unicode escape";
239 default:
240 return "Unknown error";
241 }
242 }
243 /* }}} */
244
php_json_decode_ex(zval * return_value,char * str,size_t str_len,zend_long options,zend_long depth)245 PHP_JSON_API int php_json_decode_ex(zval *return_value, char *str, size_t str_len, zend_long options, zend_long depth) /* {{{ */
246 {
247 php_json_parser parser;
248
249 php_json_parser_init(&parser, return_value, str, str_len, (int)options, (int)depth);
250
251 if (php_json_yyparse(&parser)) {
252 php_json_error_code error_code = php_json_parser_error_code(&parser);
253 if (!(options & PHP_JSON_THROW_ON_ERROR)) {
254 JSON_G(error_code) = error_code;
255 } else {
256 zend_throw_exception(php_json_exception_ce, php_json_get_error_msg(error_code), error_code);
257 }
258 RETVAL_NULL();
259 return FAILURE;
260 }
261
262 return SUCCESS;
263 }
264 /* }}} */
265
266 /* {{{ proto string json_encode(mixed data [, int options[, int depth]])
267 Returns the JSON representation of a value */
PHP_FUNCTION(json_encode)268 static PHP_FUNCTION(json_encode)
269 {
270 zval *parameter;
271 php_json_encoder encoder;
272 smart_str buf = {0};
273 zend_long options = 0;
274 zend_long depth = PHP_JSON_PARSER_DEFAULT_DEPTH;
275
276 ZEND_PARSE_PARAMETERS_START(1, 3)
277 Z_PARAM_ZVAL(parameter)
278 Z_PARAM_OPTIONAL
279 Z_PARAM_LONG(options)
280 Z_PARAM_LONG(depth)
281 ZEND_PARSE_PARAMETERS_END();
282
283 php_json_encode_init(&encoder);
284 encoder.max_depth = (int)depth;
285 php_json_encode_zval(&buf, parameter, (int)options, &encoder);
286
287 if (!(options & PHP_JSON_THROW_ON_ERROR) || (options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR)) {
288 JSON_G(error_code) = encoder.error_code;
289 if (encoder.error_code != PHP_JSON_ERROR_NONE && !(options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR)) {
290 smart_str_free(&buf);
291 RETURN_FALSE;
292 }
293 } else {
294 if (encoder.error_code != PHP_JSON_ERROR_NONE) {
295 smart_str_free(&buf);
296 zend_throw_exception(php_json_exception_ce, php_json_get_error_msg(encoder.error_code), encoder.error_code);
297 RETURN_FALSE;
298 }
299 }
300
301 smart_str_0(&buf); /* copy? */
302 if (buf.s) {
303 RETURN_NEW_STR(buf.s);
304 }
305 RETURN_EMPTY_STRING();
306 }
307 /* }}} */
308
309 /* {{{ proto mixed json_decode(string json [, bool assoc [, int depth]])
310 Decodes the JSON representation into a PHP value */
PHP_FUNCTION(json_decode)311 static PHP_FUNCTION(json_decode)
312 {
313 char *str;
314 size_t str_len;
315 zend_bool assoc = 0; /* return JS objects as PHP objects by default */
316 zend_bool assoc_null = 1;
317 zend_long depth = PHP_JSON_PARSER_DEFAULT_DEPTH;
318 zend_long options = 0;
319
320 ZEND_PARSE_PARAMETERS_START(1, 4)
321 Z_PARAM_STRING(str, str_len)
322 Z_PARAM_OPTIONAL
323 Z_PARAM_BOOL_EX(assoc, assoc_null, 1, 0)
324 Z_PARAM_LONG(depth)
325 Z_PARAM_LONG(options)
326 ZEND_PARSE_PARAMETERS_END();
327
328 if (!(options & PHP_JSON_THROW_ON_ERROR)) {
329 JSON_G(error_code) = PHP_JSON_ERROR_NONE;
330 }
331
332 if (!str_len) {
333 if (!(options & PHP_JSON_THROW_ON_ERROR)) {
334 JSON_G(error_code) = PHP_JSON_ERROR_SYNTAX;
335 } else {
336 zend_throw_exception(php_json_exception_ce, php_json_get_error_msg(PHP_JSON_ERROR_SYNTAX), PHP_JSON_ERROR_SYNTAX);
337 }
338 RETURN_NULL();
339 }
340
341 if (depth <= 0) {
342 php_error_docref(NULL, E_WARNING, "Depth must be greater than zero");
343 RETURN_NULL();
344 }
345
346 if (depth > INT_MAX) {
347 php_error_docref(NULL, E_WARNING, "Depth must be lower than %d", INT_MAX);
348 RETURN_NULL();
349 }
350
351 /* For BC reasons, the bool $assoc overrides the long $options bit for PHP_JSON_OBJECT_AS_ARRAY */
352 if (!assoc_null) {
353 if (assoc) {
354 options |= PHP_JSON_OBJECT_AS_ARRAY;
355 } else {
356 options &= ~PHP_JSON_OBJECT_AS_ARRAY;
357 }
358 }
359
360 php_json_decode_ex(return_value, str, str_len, options, depth);
361 }
362 /* }}} */
363
364 /* {{{ proto int json_last_error()
365 Returns the error code of the last json_encode() or json_decode() call. */
PHP_FUNCTION(json_last_error)366 static PHP_FUNCTION(json_last_error)
367 {
368 if (zend_parse_parameters_none() == FAILURE) {
369 return;
370 }
371
372 RETURN_LONG(JSON_G(error_code));
373 }
374 /* }}} */
375
376 /* {{{ proto string json_last_error_msg()
377 Returns the error string of the last json_encode() or json_decode() call. */
PHP_FUNCTION(json_last_error_msg)378 static PHP_FUNCTION(json_last_error_msg)
379 {
380 if (zend_parse_parameters_none() == FAILURE) {
381 return;
382 }
383
384 RETURN_STRING(php_json_get_error_msg(JSON_G(error_code)));
385 }
386 /* }}} */
387