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
125    REGISTER_LONG_CONSTANT("JSON_OBJECT_AS_ARRAY",      PHP_JSON_OBJECT_AS_ARRAY,       CONST_CS | CONST_PERSISTENT);
126    REGISTER_LONG_CONSTANT("JSON_BIGINT_AS_STRING",     PHP_JSON_BIGINT_AS_STRING,      CONST_CS | CONST_PERSISTENT);
127
128    return SUCCESS;
129}
130/* }}} */
131
132/* {{{ PHP_GINIT_FUNCTION
133*/
134static PHP_GINIT_FUNCTION(json)
135{
136#if defined(COMPILE_DL_JSON) && defined(ZTS)
137    ZEND_TSRMLS_CACHE_UPDATE();
138#endif
139    json_globals->encoder_depth = 0;
140    json_globals->error_code = 0;
141    json_globals->encode_max_depth = 0;
142}
143/* }}} */
144
145
146/* {{{ json_module_entry
147 */
148zend_module_entry json_module_entry = {
149    STANDARD_MODULE_HEADER,
150    "json",
151    json_functions,
152    PHP_MINIT(json),
153    NULL,
154    NULL,
155    NULL,
156    PHP_MINFO(json),
157    PHP_JSON_VERSION,
158    PHP_MODULE_GLOBALS(json),
159    PHP_GINIT(json),
160    NULL,
161    NULL,
162    STANDARD_MODULE_PROPERTIES_EX
163};
164/* }}} */
165
166#ifdef COMPILE_DL_JSON
167#ifdef ZTS
168ZEND_TSRMLS_CACHE_DEFINE();
169#endif
170ZEND_GET_MODULE(json)
171#endif
172
173/* {{{ PHP_MINFO_FUNCTION
174 */
175static PHP_MINFO_FUNCTION(json)
176{
177    php_info_print_table_start();
178    php_info_print_table_row(2, "json support", "enabled");
179    php_info_print_table_row(2, "json version", PHP_JSON_VERSION);
180    php_info_print_table_end();
181}
182/* }}} */
183
184PHP_JSON_API void php_json_encode(smart_str *buf, zval *val, int options) /* {{{ */
185{
186    php_json_encode_zval(buf, val, options);
187}
188/* }}} */
189
190PHP_JSON_API void php_json_decode_ex(zval *return_value, char *str, size_t str_len, zend_long options, zend_long depth) /* {{{ */
191{
192    php_json_parser parser;
193
194    php_json_parser_init(&parser, return_value, str, str_len, (int)options, (int)depth);
195
196    if (php_json_yyparse(&parser)) {
197        JSON_G(error_code) = php_json_parser_error_code(&parser);
198        RETURN_NULL();
199    }
200}
201/* }}} */
202
203/* {{{ proto string json_encode(mixed data [, int options[, int depth]])
204   Returns the JSON representation of a value */
205static PHP_FUNCTION(json_encode)
206{
207    zval *parameter;
208    smart_str buf = {0};
209    zend_long options = 0;
210    zend_long depth = PHP_JSON_PARSER_DEFAULT_DEPTH;
211
212    if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|ll", &parameter, &options, &depth) == FAILURE) {
213        return;
214    }
215
216    JSON_G(error_code) = PHP_JSON_ERROR_NONE;
217
218    JSON_G(encode_max_depth) = (int)depth;
219
220    php_json_encode(&buf, parameter, (int)options);
221
222    if (JSON_G(error_code) != PHP_JSON_ERROR_NONE && !(options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR)) {
223        smart_str_free(&buf);
224        ZVAL_FALSE(return_value);
225    } else {
226        smart_str_0(&buf); /* copy? */
227        ZVAL_NEW_STR(return_value, buf.s);
228    }
229}
230/* }}} */
231
232/* {{{ proto mixed json_decode(string json [, bool assoc [, long depth]])
233   Decodes the JSON representation into a PHP value */
234static PHP_FUNCTION(json_decode)
235{
236    char *str;
237    size_t str_len;
238    zend_bool assoc = 0; /* return JS objects as PHP objects by default */
239    zend_long depth = PHP_JSON_PARSER_DEFAULT_DEPTH;
240    zend_long options = 0;
241
242    if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|bll", &str, &str_len, &assoc, &depth, &options) == FAILURE) {
243        return;
244    }
245
246    JSON_G(error_code) = 0;
247
248    if (!str_len) {
249        JSON_G(error_code) = PHP_JSON_ERROR_SYNTAX;
250        RETURN_NULL();
251    }
252
253    /* For BC reasons, the bool $assoc overrides the long $options bit for PHP_JSON_OBJECT_AS_ARRAY */
254    if (assoc) {
255        options |=  PHP_JSON_OBJECT_AS_ARRAY;
256    } else {
257        options &= ~PHP_JSON_OBJECT_AS_ARRAY;
258    }
259
260    php_json_decode_ex(return_value, str, str_len, options, depth);
261}
262/* }}} */
263
264/* {{{ proto int json_last_error()
265   Returns the error code of the last json_encode() or json_decode() call. */
266static PHP_FUNCTION(json_last_error)
267{
268    if (zend_parse_parameters_none() == FAILURE) {
269        return;
270    }
271
272    RETURN_LONG(JSON_G(error_code));
273}
274/* }}} */
275
276/* {{{ proto string json_last_error_msg()
277   Returns the error string of the last json_encode() or json_decode() call. */
278static PHP_FUNCTION(json_last_error_msg)
279{
280    if (zend_parse_parameters_none() == FAILURE) {
281        return;
282    }
283
284    switch(JSON_G(error_code)) {
285        case PHP_JSON_ERROR_NONE:
286            RETURN_STRING("No error");
287        case PHP_JSON_ERROR_DEPTH:
288            RETURN_STRING("Maximum stack depth exceeded");
289        case PHP_JSON_ERROR_STATE_MISMATCH:
290            RETURN_STRING("State mismatch (invalid or malformed JSON)");
291        case PHP_JSON_ERROR_CTRL_CHAR:
292            RETURN_STRING("Control character error, possibly incorrectly encoded");
293        case PHP_JSON_ERROR_SYNTAX:
294            RETURN_STRING("Syntax error");
295        case PHP_JSON_ERROR_UTF8:
296            RETURN_STRING("Malformed UTF-8 characters, possibly incorrectly encoded");
297        case PHP_JSON_ERROR_RECURSION:
298            RETURN_STRING("Recursion detected");
299        case PHP_JSON_ERROR_INF_OR_NAN:
300            RETURN_STRING("Inf and NaN cannot be JSON encoded");
301        case PHP_JSON_ERROR_UNSUPPORTED_TYPE:
302            RETURN_STRING("Type is not supported");
303        default:
304            RETURN_STRING("Unknown error");
305    }
306
307}
308/* }}} */
309
310/*
311 * Local variables:
312 * tab-width: 4
313 * c-basic-offset: 4
314 * End:
315 * vim600: noet sw=4 ts=4 fdm=marker
316 * vim<600: noet sw=4 ts=4
317 */
318