1/*
2  +----------------------------------------------------------------------+
3  | PHP Version 7                                                        |
4  +----------------------------------------------------------------------+
5  | Copyright (c) 1997-2015 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  +----------------------------------------------------------------------+
17*/
18
19/* $Id$ */
20
21#ifdef HAVE_CONFIG_H
22#include "config.h"
23#endif
24
25#include "php.h"
26#include "php_ini.h"
27#include "ext/standard/info.h"
28#include "ext/standard/html.h"
29#include "zend_smart_str.h"
30#include "php_json.h"
31#include "php_json_encoder.h"
32#include "php_json_parser.h"
33#include <zend_exceptions.h>
34
35#include <float.h>
36#if defined(DBL_MANT_DIG) && defined(DBL_MIN_EXP)
37#define NUM_BUF_SIZE (3 + DBL_MANT_DIG - DBL_MIN_EXP)
38#else
39#define NUM_BUF_SIZE 1080
40#endif
41
42
43static PHP_MINFO_FUNCTION(json);
44static PHP_FUNCTION(json_encode);
45static PHP_FUNCTION(json_decode);
46static PHP_FUNCTION(json_last_error);
47static PHP_FUNCTION(json_last_error_msg);
48
49PHP_JSON_API zend_class_entry *php_json_serializable_ce;
50
51ZEND_DECLARE_MODULE_GLOBALS(json)
52
53/* {{{ arginfo */
54ZEND_BEGIN_ARG_INFO_EX(arginfo_json_encode, 0, 0, 1)
55    ZEND_ARG_INFO(0, value)
56    ZEND_ARG_INFO(0, options)
57    ZEND_ARG_INFO(0, depth)
58ZEND_END_ARG_INFO()
59
60ZEND_BEGIN_ARG_INFO_EX(arginfo_json_decode, 0, 0, 1)
61    ZEND_ARG_INFO(0, json)
62    ZEND_ARG_INFO(0, assoc)
63    ZEND_ARG_INFO(0, depth)
64    ZEND_ARG_INFO(0, options)
65ZEND_END_ARG_INFO()
66
67ZEND_BEGIN_ARG_INFO(arginfo_json_last_error, 0)
68ZEND_END_ARG_INFO()
69
70ZEND_BEGIN_ARG_INFO(arginfo_json_last_error_msg, 0)
71ZEND_END_ARG_INFO()
72/* }}} */
73
74/* {{{ json_functions[] */
75static const zend_function_entry json_functions[] = {
76    PHP_FE(json_encode, arginfo_json_encode)
77    PHP_FE(json_decode, arginfo_json_decode)
78    PHP_FE(json_last_error, arginfo_json_last_error)
79    PHP_FE(json_last_error_msg, arginfo_json_last_error_msg)
80    PHP_FE_END
81};
82/* }}} */
83
84/* {{{ JsonSerializable methods */
85ZEND_BEGIN_ARG_INFO(json_serialize_arginfo, 0)
86    /* No arguments */
87ZEND_END_ARG_INFO();
88
89static const zend_function_entry json_serializable_interface[] = {
90    PHP_ABSTRACT_ME(JsonSerializable, jsonSerialize, json_serialize_arginfo)
91    PHP_FE_END
92};
93/* }}} */
94
95/* {{{ MINIT */
96static PHP_MINIT_FUNCTION(json)
97{
98    zend_class_entry ce;
99
100    INIT_CLASS_ENTRY(ce, "JsonSerializable", json_serializable_interface);
101    php_json_serializable_ce = zend_register_internal_interface(&ce);
102
103    REGISTER_LONG_CONSTANT("JSON_HEX_TAG",  PHP_JSON_HEX_TAG,  CONST_CS | CONST_PERSISTENT);
104    REGISTER_LONG_CONSTANT("JSON_HEX_AMP",  PHP_JSON_HEX_AMP,  CONST_CS | CONST_PERSISTENT);
105    REGISTER_LONG_CONSTANT("JSON_HEX_APOS", PHP_JSON_HEX_APOS, CONST_CS | CONST_PERSISTENT);
106    REGISTER_LONG_CONSTANT("JSON_HEX_QUOT", PHP_JSON_HEX_QUOT, CONST_CS | CONST_PERSISTENT);
107    REGISTER_LONG_CONSTANT("JSON_FORCE_OBJECT", PHP_JSON_FORCE_OBJECT, CONST_CS | CONST_PERSISTENT);
108    REGISTER_LONG_CONSTANT("JSON_NUMERIC_CHECK", PHP_JSON_NUMERIC_CHECK, CONST_CS | CONST_PERSISTENT);
109    REGISTER_LONG_CONSTANT("JSON_UNESCAPED_SLASHES", PHP_JSON_UNESCAPED_SLASHES, CONST_CS | CONST_PERSISTENT);
110    REGISTER_LONG_CONSTANT("JSON_PRETTY_PRINT", PHP_JSON_PRETTY_PRINT, CONST_CS | CONST_PERSISTENT);
111    REGISTER_LONG_CONSTANT("JSON_UNESCAPED_UNICODE", PHP_JSON_UNESCAPED_UNICODE, CONST_CS | CONST_PERSISTENT);
112    REGISTER_LONG_CONSTANT("JSON_PARTIAL_OUTPUT_ON_ERROR", PHP_JSON_PARTIAL_OUTPUT_ON_ERROR, CONST_CS | CONST_PERSISTENT);
113    REGISTER_LONG_CONSTANT("JSON_PRESERVE_ZERO_FRACTION", PHP_JSON_PRESERVE_ZERO_FRACTION, CONST_CS | CONST_PERSISTENT);
114
115    REGISTER_LONG_CONSTANT("JSON_ERROR_NONE", PHP_JSON_ERROR_NONE, CONST_CS | CONST_PERSISTENT);
116    REGISTER_LONG_CONSTANT("JSON_ERROR_DEPTH", PHP_JSON_ERROR_DEPTH, CONST_CS | CONST_PERSISTENT);
117    REGISTER_LONG_CONSTANT("JSON_ERROR_STATE_MISMATCH", PHP_JSON_ERROR_STATE_MISMATCH, CONST_CS | CONST_PERSISTENT);
118    REGISTER_LONG_CONSTANT("JSON_ERROR_CTRL_CHAR", PHP_JSON_ERROR_CTRL_CHAR, CONST_CS | CONST_PERSISTENT);
119    REGISTER_LONG_CONSTANT("JSON_ERROR_SYNTAX", PHP_JSON_ERROR_SYNTAX, CONST_CS | CONST_PERSISTENT);
120    REGISTER_LONG_CONSTANT("JSON_ERROR_UTF8", PHP_JSON_ERROR_UTF8, CONST_CS | CONST_PERSISTENT);
121    REGISTER_LONG_CONSTANT("JSON_ERROR_RECURSION", PHP_JSON_ERROR_RECURSION, CONST_CS | CONST_PERSISTENT);
122    REGISTER_LONG_CONSTANT("JSON_ERROR_INF_OR_NAN", PHP_JSON_ERROR_INF_OR_NAN, CONST_CS | CONST_PERSISTENT);
123    REGISTER_LONG_CONSTANT("JSON_ERROR_UNSUPPORTED_TYPE", PHP_JSON_ERROR_UNSUPPORTED_TYPE, CONST_CS | CONST_PERSISTENT);
124    REGISTER_LONG_CONSTANT("JSON_ERROR_INVALID_PROPERTY_NAME", PHP_JSON_ERROR_INVALID_PROPERTY_NAME, CONST_CS | CONST_PERSISTENT);
125    REGISTER_LONG_CONSTANT("JSON_ERROR_UTF16", PHP_JSON_ERROR_UTF16, CONST_CS | CONST_PERSISTENT);
126
127    REGISTER_LONG_CONSTANT("JSON_OBJECT_AS_ARRAY",      PHP_JSON_OBJECT_AS_ARRAY,       CONST_CS | CONST_PERSISTENT);
128    REGISTER_LONG_CONSTANT("JSON_BIGINT_AS_STRING",     PHP_JSON_BIGINT_AS_STRING,      CONST_CS | CONST_PERSISTENT);
129
130    return SUCCESS;
131}
132/* }}} */
133
134/* {{{ PHP_GINIT_FUNCTION
135*/
136static PHP_GINIT_FUNCTION(json)
137{
138#if defined(COMPILE_DL_JSON) && defined(ZTS)
139    ZEND_TSRMLS_CACHE_UPDATE();
140#endif
141    json_globals->encoder_depth = 0;
142    json_globals->error_code = 0;
143    json_globals->encode_max_depth = 0;
144}
145/* }}} */
146
147
148/* {{{ json_module_entry
149 */
150zend_module_entry json_module_entry = {
151    STANDARD_MODULE_HEADER,
152    "json",
153    json_functions,
154    PHP_MINIT(json),
155    NULL,
156    NULL,
157    NULL,
158    PHP_MINFO(json),
159    PHP_JSON_VERSION,
160    PHP_MODULE_GLOBALS(json),
161    PHP_GINIT(json),
162    NULL,
163    NULL,
164    STANDARD_MODULE_PROPERTIES_EX
165};
166/* }}} */
167
168#ifdef COMPILE_DL_JSON
169#ifdef ZTS
170ZEND_TSRMLS_CACHE_DEFINE();
171#endif
172ZEND_GET_MODULE(json)
173#endif
174
175/* {{{ PHP_MINFO_FUNCTION
176 */
177static PHP_MINFO_FUNCTION(json)
178{
179    php_info_print_table_start();
180    php_info_print_table_row(2, "json support", "enabled");
181    php_info_print_table_row(2, "json version", PHP_JSON_VERSION);
182    php_info_print_table_end();
183}
184/* }}} */
185
186PHP_JSON_API void php_json_encode(smart_str *buf, zval *val, int options) /* {{{ */
187{
188    php_json_encode_zval(buf, val, options);
189}
190/* }}} */
191
192PHP_JSON_API void php_json_decode_ex(zval *return_value, char *str, size_t str_len, zend_long options, zend_long depth) /* {{{ */
193{
194    php_json_parser parser;
195
196    php_json_parser_init(&parser, return_value, str, str_len, (int)options, (int)depth);
197
198    if (php_json_yyparse(&parser)) {
199        JSON_G(error_code) = php_json_parser_error_code(&parser);
200        RETURN_NULL();
201    }
202}
203/* }}} */
204
205/* {{{ proto string json_encode(mixed data [, int options[, int depth]])
206   Returns the JSON representation of a value */
207static PHP_FUNCTION(json_encode)
208{
209    zval *parameter;
210    smart_str buf = {0};
211    zend_long options = 0;
212    zend_long depth = PHP_JSON_PARSER_DEFAULT_DEPTH;
213
214    if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|ll", &parameter, &options, &depth) == FAILURE) {
215        return;
216    }
217
218    JSON_G(error_code) = PHP_JSON_ERROR_NONE;
219
220    JSON_G(encode_max_depth) = (int)depth;
221
222    php_json_encode(&buf, parameter, (int)options);
223
224    if (JSON_G(error_code) != PHP_JSON_ERROR_NONE && !(options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR)) {
225        smart_str_free(&buf);
226        ZVAL_FALSE(return_value);
227    } else {
228        smart_str_0(&buf); /* copy? */
229        ZVAL_NEW_STR(return_value, buf.s);
230    }
231}
232/* }}} */
233
234/* {{{ proto mixed json_decode(string json [, bool assoc [, long depth]])
235   Decodes the JSON representation into a PHP value */
236static PHP_FUNCTION(json_decode)
237{
238    char *str;
239    size_t str_len;
240    zend_bool assoc = 0; /* return JS objects as PHP objects by default */
241    zend_long depth = PHP_JSON_PARSER_DEFAULT_DEPTH;
242    zend_long options = 0;
243
244    if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|bll", &str, &str_len, &assoc, &depth, &options) == FAILURE) {
245        return;
246    }
247
248    JSON_G(error_code) = 0;
249
250    if (!str_len) {
251        JSON_G(error_code) = PHP_JSON_ERROR_SYNTAX;
252        RETURN_NULL();
253    }
254
255    /* For BC reasons, the bool $assoc overrides the long $options bit for PHP_JSON_OBJECT_AS_ARRAY */
256    if (assoc) {
257        options |=  PHP_JSON_OBJECT_AS_ARRAY;
258    } else {
259        options &= ~PHP_JSON_OBJECT_AS_ARRAY;
260    }
261
262    php_json_decode_ex(return_value, str, str_len, options, depth);
263}
264/* }}} */
265
266/* {{{ proto int json_last_error()
267   Returns the error code of the last json_encode() or json_decode() call. */
268static PHP_FUNCTION(json_last_error)
269{
270    if (zend_parse_parameters_none() == FAILURE) {
271        return;
272    }
273
274    RETURN_LONG(JSON_G(error_code));
275}
276/* }}} */
277
278/* {{{ proto string json_last_error_msg()
279   Returns the error string of the last json_encode() or json_decode() call. */
280static PHP_FUNCTION(json_last_error_msg)
281{
282    if (zend_parse_parameters_none() == FAILURE) {
283        return;
284    }
285
286    switch(JSON_G(error_code)) {
287        case PHP_JSON_ERROR_NONE:
288            RETURN_STRING("No error");
289        case PHP_JSON_ERROR_DEPTH:
290            RETURN_STRING("Maximum stack depth exceeded");
291        case PHP_JSON_ERROR_STATE_MISMATCH:
292            RETURN_STRING("State mismatch (invalid or malformed JSON)");
293        case PHP_JSON_ERROR_CTRL_CHAR:
294            RETURN_STRING("Control character error, possibly incorrectly encoded");
295        case PHP_JSON_ERROR_SYNTAX:
296            RETURN_STRING("Syntax error");
297        case PHP_JSON_ERROR_UTF8:
298            RETURN_STRING("Malformed UTF-8 characters, possibly incorrectly encoded");
299        case PHP_JSON_ERROR_RECURSION:
300            RETURN_STRING("Recursion detected");
301        case PHP_JSON_ERROR_INF_OR_NAN:
302            RETURN_STRING("Inf and NaN cannot be JSON encoded");
303        case PHP_JSON_ERROR_UNSUPPORTED_TYPE:
304            RETURN_STRING("Type is not supported");
305        case PHP_JSON_ERROR_INVALID_PROPERTY_NAME:
306            RETURN_STRING("The decoded property name is invalid");
307        case PHP_JSON_ERROR_UTF16:
308            RETURN_STRING("Single unpaired UTF-16 surrogate in unicode escape");
309        default:
310            RETURN_STRING("Unknown error");
311    }
312
313}
314/* }}} */
315
316/*
317 * Local variables:
318 * tab-width: 4
319 * c-basic-offset: 4
320 * End:
321 * vim600: noet sw=4 ts=4 fdm=marker
322 * vim<600: noet sw=4 ts=4
323 */
324