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_string(const char * s,size_t len,int options)106 PHP_JSON_API zend_string *php_json_encode_string(const char *s, size_t len, int options)
107 {
108 smart_str buf = {0};
109 php_json_encoder encoder;
110
111 php_json_encode_init(&encoder);
112
113 if (php_json_escape_string(&buf, s, len, options, &encoder) == FAILURE) {
114 smart_str_free(&buf);
115 return NULL;
116 }
117
118 return smart_str_extract(&buf);
119 }
120
php_json_encode_ex(smart_str * buf,zval * val,int options,zend_long depth)121 PHP_JSON_API zend_result php_json_encode_ex(smart_str *buf, zval *val, int options, zend_long depth) /* {{{ */
122 {
123 php_json_encoder encoder;
124 zend_result return_code;
125
126 php_json_encode_init(&encoder);
127 encoder.max_depth = depth;
128
129 return_code = php_json_encode_zval(buf, val, options, &encoder);
130 JSON_G(error_code) = encoder.error_code;
131
132 return return_code;
133 }
134 /* }}} */
135
php_json_encode(smart_str * buf,zval * val,int options)136 PHP_JSON_API zend_result php_json_encode(smart_str *buf, zval *val, int options) /* {{{ */
137 {
138 return php_json_encode_ex(buf, val, options, JSON_G(encode_max_depth));
139 }
140 /* }}} */
141
php_json_get_error_msg(php_json_error_code error_code)142 static const char *php_json_get_error_msg(php_json_error_code error_code) /* {{{ */
143 {
144 switch(error_code) {
145 case PHP_JSON_ERROR_NONE:
146 return "No error";
147 case PHP_JSON_ERROR_DEPTH:
148 return "Maximum stack depth exceeded";
149 case PHP_JSON_ERROR_STATE_MISMATCH:
150 return "State mismatch (invalid or malformed JSON)";
151 case PHP_JSON_ERROR_CTRL_CHAR:
152 return "Control character error, possibly incorrectly encoded";
153 case PHP_JSON_ERROR_SYNTAX:
154 return "Syntax error";
155 case PHP_JSON_ERROR_UTF8:
156 return "Malformed UTF-8 characters, possibly incorrectly encoded";
157 case PHP_JSON_ERROR_RECURSION:
158 return "Recursion detected";
159 case PHP_JSON_ERROR_INF_OR_NAN:
160 return "Inf and NaN cannot be JSON encoded";
161 case PHP_JSON_ERROR_UNSUPPORTED_TYPE:
162 return "Type is not supported";
163 case PHP_JSON_ERROR_INVALID_PROPERTY_NAME:
164 return "The decoded property name is invalid";
165 case PHP_JSON_ERROR_UTF16:
166 return "Single unpaired UTF-16 surrogate in unicode escape";
167 case PHP_JSON_ERROR_NON_BACKED_ENUM:
168 return "Non-backed enums have no default serialization";
169 default:
170 return "Unknown error";
171 }
172 }
173 /* }}} */
174
php_json_decode_ex(zval * return_value,const char * str,size_t str_len,zend_long options,zend_long depth)175 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) /* {{{ */
176 {
177 php_json_parser parser;
178
179 php_json_parser_init(&parser, return_value, str, str_len, (int)options, (int)depth);
180
181 if (php_json_yyparse(&parser)) {
182 php_json_error_code error_code = php_json_parser_error_code(&parser);
183 if (!(options & PHP_JSON_THROW_ON_ERROR)) {
184 JSON_G(error_code) = error_code;
185 } else {
186 zend_throw_exception(php_json_exception_ce, php_json_get_error_msg(error_code), error_code);
187 }
188 RETVAL_NULL();
189 return FAILURE;
190 }
191
192 return SUCCESS;
193 }
194 /* }}} */
195
196 /* {{{ Returns the JSON representation of a value */
PHP_FUNCTION(json_encode)197 PHP_FUNCTION(json_encode)
198 {
199 zval *parameter;
200 php_json_encoder encoder;
201 smart_str buf = {0};
202 zend_long options = 0;
203 zend_long depth = PHP_JSON_PARSER_DEFAULT_DEPTH;
204
205 ZEND_PARSE_PARAMETERS_START(1, 3)
206 Z_PARAM_ZVAL(parameter)
207 Z_PARAM_OPTIONAL
208 Z_PARAM_LONG(options)
209 Z_PARAM_LONG(depth)
210 ZEND_PARSE_PARAMETERS_END();
211
212 php_json_encode_init(&encoder);
213 encoder.max_depth = (int)depth;
214 php_json_encode_zval(&buf, parameter, (int)options, &encoder);
215
216 if (!(options & PHP_JSON_THROW_ON_ERROR) || (options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR)) {
217 JSON_G(error_code) = encoder.error_code;
218 if (encoder.error_code != PHP_JSON_ERROR_NONE && !(options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR)) {
219 smart_str_free(&buf);
220 RETURN_FALSE;
221 }
222 } else {
223 if (encoder.error_code != PHP_JSON_ERROR_NONE) {
224 smart_str_free(&buf);
225 zend_throw_exception(php_json_exception_ce, php_json_get_error_msg(encoder.error_code), encoder.error_code);
226 RETURN_THROWS();
227 }
228 }
229
230 RETURN_STR(smart_str_extract(&buf));
231 }
232 /* }}} */
233
234 /* {{{ Decodes the JSON representation into a PHP value */
PHP_FUNCTION(json_decode)235 PHP_FUNCTION(json_decode)
236 {
237 char *str;
238 size_t str_len;
239 bool assoc = 0; /* return JS objects as PHP objects by default */
240 bool assoc_null = 1;
241 zend_long depth = PHP_JSON_PARSER_DEFAULT_DEPTH;
242 zend_long options = 0;
243
244 ZEND_PARSE_PARAMETERS_START(1, 4)
245 Z_PARAM_STRING(str, str_len)
246 Z_PARAM_OPTIONAL
247 Z_PARAM_BOOL_OR_NULL(assoc, assoc_null)
248 Z_PARAM_LONG(depth)
249 Z_PARAM_LONG(options)
250 ZEND_PARSE_PARAMETERS_END();
251
252 if (!(options & PHP_JSON_THROW_ON_ERROR)) {
253 JSON_G(error_code) = PHP_JSON_ERROR_NONE;
254 }
255
256 if (!str_len) {
257 if (!(options & PHP_JSON_THROW_ON_ERROR)) {
258 JSON_G(error_code) = PHP_JSON_ERROR_SYNTAX;
259 } else {
260 zend_throw_exception(php_json_exception_ce, php_json_get_error_msg(PHP_JSON_ERROR_SYNTAX), PHP_JSON_ERROR_SYNTAX);
261 }
262 RETURN_NULL();
263 }
264
265 if (depth <= 0) {
266 zend_argument_value_error(3, "must be greater than 0");
267 RETURN_THROWS();
268 }
269
270 if (depth > INT_MAX) {
271 zend_argument_value_error(3, "must be less than %d", INT_MAX);
272 RETURN_THROWS();
273 }
274
275 /* For BC reasons, the bool $assoc overrides the long $options bit for PHP_JSON_OBJECT_AS_ARRAY */
276 if (!assoc_null) {
277 if (assoc) {
278 options |= PHP_JSON_OBJECT_AS_ARRAY;
279 } else {
280 options &= ~PHP_JSON_OBJECT_AS_ARRAY;
281 }
282 }
283
284 php_json_decode_ex(return_value, str, str_len, options, depth);
285 }
286 /* }}} */
287
288 /* {{{ Returns the error code of the last json_encode() or json_decode() call. */
PHP_FUNCTION(json_last_error)289 PHP_FUNCTION(json_last_error)
290 {
291 ZEND_PARSE_PARAMETERS_NONE();
292
293 RETURN_LONG(JSON_G(error_code));
294 }
295 /* }}} */
296
297 /* {{{ Returns the error string of the last json_encode() or json_decode() call. */
PHP_FUNCTION(json_last_error_msg)298 PHP_FUNCTION(json_last_error_msg)
299 {
300 ZEND_PARSE_PARAMETERS_NONE();
301
302 RETURN_STRING(php_json_get_error_msg(JSON_G(error_code)));
303 }
304 /* }}} */
305