Coverage Report

Created: 2022-02-19 20:27

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