├── .gitignore
├── CREDITS
├── LICENSE
├── Makefile.frag
├── README.md
├── TODO.md
├── UPGRADE.md
├── bench
└── compare_with_json.php
├── config.m4
├── config.w32
├── jsond.c
├── jsond.php
├── jsond_buffer.c
├── jsond_dtoa.c
├── jsond_encoder.c
├── jsond_parser.tab.c
├── jsond_parser.tab.h
├── jsond_parser.y
├── jsond_scanner.c
├── jsond_scanner.re
├── jsond_yacc.c
├── package.xml
├── php_jsond.h
├── php_jsond_buffer.h
├── php_jsond_compat.h
├── php_jsond_dtoa.h
├── php_jsond_encoder.h
├── php_jsond_parser.h
├── php_jsond_scanner.h
├── php_jsond_scanner_defs.h
├── php_jsond_utf8_decoder.h
├── tests
├── 001.phpt
├── 002.phpt
├── 003.phpt
├── 004.phpt
├── 005.phpt
├── 006.phpt
├── 007.phpt
├── 008.phpt
├── bootstrap.inc
├── bug40503.phpt
├── bug41034.phpt
├── bug41067.phpt
├── bug41403.phpt
├── bug41504.phpt
├── bug41567.phpt
├── bug42090.phpt
├── bug42785.phpt
├── bug43941.phpt
├── bug45791.phpt
├── bug46215.phpt
├── bug46944.phpt
├── bug47644.phpt
├── bug50224.phpt
├── bug53946.phpt
├── bug54058.phpt
├── bug54484.phpt
├── bug55543.phpt
├── bug61537.phpt
├── bug61978.phpt
├── bug62010.phpt
├── bug62369.phpt
├── bug63737.phpt
├── bug64695.phpt
├── bug64874_part1.phpt
├── bug64874_part2.phpt
├── bug66021.phpt
├── bug66025.phpt
├── bug68546.phpt
├── bug68992.phpt
├── bug69187.phpt
├── bug71835.phpt
├── bug72069.phpt
├── bug72787.phpt
├── bug73113.phpt
├── bug73254.phpt
├── bug73991.phpt
├── fail001.phpt
├── inf_nan_error.phpt
├── json_decode_basic.phpt
├── json_decode_error.phpt
├── json_encode_basic.phpt
├── json_encode_basic_utf8.phpt
├── json_encode_error.phpt
├── json_encode_numeric.phpt
├── json_encode_pretty_print.phpt
├── json_encode_u2028_u2029.phpt
├── json_encode_unescaped_slashes.phpt
├── json_last_error_error.phpt
├── json_last_error_msg_error.phpt
├── pass001.1.phpt
├── pass001.1_64bit.phpt
├── pass001.phpt
├── pass002.phpt
├── pass003.phpt
├── serialize.phpt
└── unsupported_type_error.phpt
└── utils
├── jsond_auto_complete.php
└── package_files.php
/.gitignore:
--------------------------------------------------------------------------------
1 | .deps
2 | *.dep
3 | *.lo
4 | *.loT
5 | *.la
6 | .libs
7 | acinclude.m4
8 | aclocal.m4
9 | autom4te.cache
10 | build
11 | config.cache
12 | config.guess
13 | config.h
14 | config.h.in*
15 | config.log
16 | config.nice
17 | config.status
18 | config.sub
19 | configure
20 | configure.ac
21 | configure.in
22 | include
23 | install-sh
24 | libtool
25 | ltmain.sh
26 | Makefile
27 | Makefile.fragments
28 | Makefile.global
29 | Makefile.objects
30 | missing
31 | mkinstalldirs
32 | modules
33 | run-tests.php
34 | tests/*.diff
35 | tests/*.out
36 | tests/**.php
37 | tests/*.exp
38 | tests/*.log
39 | tests/*.sh
40 | nbproject/
41 |
--------------------------------------------------------------------------------
/CREDITS:
--------------------------------------------------------------------------------
1 | jsond
2 | Omar Kilani, Scott MacVicar, Jakub Zelenka
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | --------------------------------------------------------------------
2 | The PHP License, version 3.01
3 | Copyright (c) 1999 - 2012 The PHP Group. All rights reserved.
4 | --------------------------------------------------------------------
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, is permitted provided that the following conditions
8 | are met:
9 |
10 | 1. Redistributions of source code must retain the above copyright
11 | notice, this list of conditions and the following disclaimer.
12 |
13 | 2. Redistributions in binary form must reproduce the above copyright
14 | notice, this list of conditions and the following disclaimer in
15 | the documentation and/or other materials provided with the
16 | distribution.
17 |
18 | 3. The name "PHP" must not be used to endorse or promote products
19 | derived from this software without prior written permission. For
20 | written permission, please contact group@php.net.
21 |
22 | 4. Products derived from this software may not be called "PHP", nor
23 | may "PHP" appear in their name, without prior written permission
24 | from group@php.net. You may indicate that your software works in
25 | conjunction with PHP by saying "Foo for PHP" instead of calling
26 | it "PHP Foo" or "phpfoo"
27 |
28 | 5. The PHP Group may publish revised and/or new versions of the
29 | license from time to time. Each version will be given a
30 | distinguishing version number.
31 | Once covered code has been published under a particular version
32 | of the license, you may always continue to use it under the terms
33 | of that version. You may also choose to use such covered code
34 | under the terms of any subsequent version of the license
35 | published by the PHP Group. No one other than the PHP Group has
36 | the right to modify the terms applicable to covered code created
37 | under this License.
38 |
39 | 6. Redistributions of any form whatsoever must retain the following
40 | acknowledgment:
41 | "This product includes PHP software, freely available from
42 | ".
43 |
44 | THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND
45 | ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
46 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
47 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP
48 | DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
49 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
50 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
51 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
53 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
54 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
55 | OF THE POSSIBILITY OF SUCH DAMAGE.
56 |
57 | --------------------------------------------------------------------
58 |
59 | This software consists of voluntary contributions made by many
60 | individuals on behalf of the PHP Group.
61 |
62 | The PHP Group can be contacted via Email at group@php.net.
63 |
64 | For more information on the PHP Group and the PHP project,
65 | please see .
66 |
67 | PHP includes the Zend Engine, freely available at
68 | .
69 |
--------------------------------------------------------------------------------
/Makefile.frag:
--------------------------------------------------------------------------------
1 |
2 |
3 | $(srcdir)/jsond_scanner.c: $(srcdir)/jsond_scanner.re
4 | $(RE2C) -t $(srcdir)/php_jsond_scanner_defs.h --no-generation-date -bci -o $@ $(srcdir)/jsond_scanner.re
5 |
6 | $(srcdir)/jsond_parser.tab.c: $(srcdir)/jsond_parser.y
7 | $(YACC) --defines --skeleton=$(srcdir)/jsond_yacc.c -l $(srcdir)/jsond_parser.y -o $@
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PHP JSON Development extension
2 |
3 | The php-jsond is a development extension that contains some future changes for the official
4 | php-json extension. It also makes some new changes available in the previous PHP versions as it can
5 | be installed independently through PECL. Currently it supports PHP 7.2+.
6 |
7 |
8 | ## Installation
9 |
10 | ### Linux
11 |
12 | #### PECL
13 |
14 | This extension is available on PECL. The package is not currently stable. If the config
15 | `preferre_state` is stable, then the version needs to be specified.
16 |
17 | ```
18 | $ sudo pecl install jsond-1.x.y
19 | ```
20 |
21 | where `x` is an installed minor version number and `y` bug fixing version number.
22 |
23 |
24 | #### Manual Installation
25 |
26 | First clone the repository
27 | ```
28 | git clone https://github.com/bukka/php-jsond.git
29 | ```
30 |
31 | Then go to the created directory and compile the extension. The PHP development package has to be
32 | installed (command `phpize` must be available).
33 | ```
34 | cd php-jsond
35 | phpize
36 | ./configure
37 | make
38 | sudo make install
39 | ```
40 |
41 | ### Windows
42 |
43 | Precompiled binary `dll` libraries for php-jsond are available on [the PECL jsond page](http://pecl.php.net/package/jsond).
44 |
45 |
46 | ## Documentation
47 |
48 | ### Default API
49 |
50 | The functionality is exactly the same as documented in [JSON documentation](http://php.net/json), just the prefixes are different.
51 |
52 |
53 | #### Constants
54 |
55 | Constants have different prefix (`JSOND`) than JSON constants but they are the same as the one in PHP 7.
56 |
57 | ##### Error constants
58 | ```
59 | JSOND_ERROR_NONE (integer)
60 | JSOND_ERROR_DEPTH (integer)
61 | JSOND_ERROR_STATE_MISMATCH (integer)
62 | JSOND_ERROR_CTRL_CHAR (integer)
63 | JSOND_ERROR_SYNTAX (integer)
64 | JSOND_ERROR_UTF8 (integer)
65 | JSOND_ERROR_RECURSION (integer)
66 | JSOND_ERROR_INF_OR_NAN (integer)
67 | JSOND_ERROR_UNSUPPORTED_TYPE (integer)
68 | JSOND_ERROR_INVALID_PROPERTY_NAME (integer)
69 | JSOND_ERROR_UTF16 (integer)
70 | ```
71 |
72 | ##### Encoding constants
73 | ```
74 | JSOND_HEX_TAG (integer)
75 | JSOND_HEX_AMP (integer)
76 | JSOND_HEX_APOS (integer)
77 | JSOND_HEX_QUOT (integer)
78 | JSOND_FORCE_OBJECT (integer)
79 | JSOND_NUMERIC_CHECK (integer)
80 | JSOND_BIGINT_AS_STRING (integer)
81 | JSOND_PRETTY_PRINT (integer)
82 | JSOND_UNESCAPED_SLASHES (integer)
83 | JSOND_UNESCAPED_UNICODE (integer)
84 | JSOND_PARTIAL_OUTPUT_ON_ERROR (integer)
85 | JSOND_PRESERVE_ZERO_FRACTION (integer)
86 | JSOND_VALID_ESCAPE_UNICODE (integer)
87 | ```
88 |
89 | ##### Decoding constants
90 | ```
91 | JSOND_OBJECT_AS_ARRAY (integer)
92 | JSOND_BIGINT_AS_STRING (integer)
93 | ```
94 |
95 | #### Functions
96 |
97 | The prefix for functions is `jsond`.
98 |
99 | ```php
100 | mixed jsond_decode ( string $json [, bool $assoc = false [, int $depth = 512 [, int $options = 0 ]]] );
101 | string jsond_encode ( mixed $value [, int $options = 0 [, int $depth = 512 ]] );
102 | string jsond_last_error_msg ( void );
103 | int jsond_last_error ( void );
104 | ```
105 |
106 | #### The JsondSerializable interface
107 |
108 | Prefix for interface is `Jsond` otherwise it is the same as `JsonSerializable`.
109 |
110 | ```php
111 | JsondSerializable {
112 | /* Methods */
113 | abstract public mixed jsonSerialize ( void )
114 | }
115 | ```
116 |
117 |
118 | ### Drop-in alternative for the standard JSON extension
119 |
120 | If jsond is compiled with `--enable-jsond-with-json-prefix`, than the json functions are replaced
121 | with jsond variants and the API is exactly the same as the API documented in [JSON documentation](http://php.net/json).
122 |
123 | ### JSOND IDE Auto Complete
124 | If you use IDE like PhpStorm, you can set the file `utils/jsond_auto_complete.php` to the Include Path,
125 | then IDE will auto complete `jsond_encode` and `jsond_decode`.
126 |
127 | ## Upgrading from php-json
128 |
129 | All changes are listed in [UPGRADE.md](https://github.com/bukka/php-jsond/blob/master/UPGRADE.md)
130 |
131 | ## TODO list
132 |
133 | The TODO list can be found in [TODO.md](https://github.com/bukka/php-jsond/blob/master/TODO.md).
134 |
--------------------------------------------------------------------------------
/TODO.md:
--------------------------------------------------------------------------------
1 | # TODO list
2 |
3 | ## Decoding
4 | - use JSON_ERROR_CTRL_CHAR also in non string context (JS condition)
5 | - replace ill-formed characters with substitute character
6 | - https://bugs.php.net/bug.php?id=65082
7 | - https://bugs.php.net/bug.php?id=63898
8 | - extended error info containing error location
9 | - check if there are some potential issues with bigint checking
10 | - refactore algorithm in jsond_scanner.re
11 |
12 | ## Encoding
13 | - add shortcut macro for XSS attacks
14 | - https://bugs.php.net/bug.php?id=65257
15 | - compare utf8 validation with json and optimize it
16 | - improve and test native buffer
17 | - PHPC_CSTRL_RETVAL in PHP_JSON_BUF_RETURN is not ideal as it copies the whole buffer
18 |
19 | ## Build
20 | - add checks for specific re2c and Bison version
21 | - Windows Makefile.frag support - like https://github.com/php/php-src/commit/25ee9465d1c7043f4302329c901fecd38597b634
22 |
23 | ## Testing
24 | - new generator
25 |
26 | # Links
27 |
28 | ## Testing resources
29 | - Hoa: https://github.com/Hywan/jsond-test
30 | - [Comparison JSON impls](http://gggeek.altervista.org/sw/article_20070425.html) and [its source](https://github.com/gggeek/phpxmlrpc-extras/blob/master/jsonrpc/testsuite.php)
31 | - [Jan Tvrdik compat test](https://gist.github.com/JanTvrdik/10277952#file-test-php)
32 |
--------------------------------------------------------------------------------
/UPGRADE.md:
--------------------------------------------------------------------------------
1 | # Upgrading from the previous versions
2 |
3 | ## 2.0
4 |
5 | ### User visible changes
6 |
7 | ### General
8 | - Added compatibility with PHP 8.0
9 |
10 | #### Decoder
11 | - Added parser method API including `jsond_parser_method` for hooking JSON parser
12 | - Allowed `JSOND_OBJECT_AS_ARRAY` option to actually have meaning
13 |
14 | #### Encoder
15 | - Backported `jsond_encoder` context - fixes stacking of exceptions in `JsondSerializable` objects
16 | - https://github.com/php/php-src/pull/2173
17 | - https://bugs.php.net/bug.php?id=66025
18 | - https://bugs.php.net/bug.php?id=73254
19 | - Fixed segfault with throwing JsondSerializable
20 | - https://bugs.php.net/bug.php?id=73113
21 | - Escaped U+2028 and U+2029 when `JSOND_UNESCAPED_UNICODE` is supplied as `jsond_encode`
22 | options and added `JSOND_UNESCAPED_LINE_TERMINATORS` to restore the previous behaviour
23 | - Fixed behavior of `JsondSerializable` difference from `jsond_encode` when error
24 | - PHP bug #72069
25 | - Used serialize_precision instead of precision for encoding of double values
26 |
27 | ## 1.4
28 |
29 | ### User visible changes
30 |
31 | #### Decoder
32 | - Empty string is considered invalid and `JSOND_ERROR_SYNTAX` is raised
33 | - Removed option `JSOND_VALID_ESCAPED_UNICODE`
34 | - The `JSOND_ERROR_UTF16` will be always set for invalid \uXXXX code
35 | - PHP bug #62010
36 | - Added new error `JSOND_ERROR_INVALID_PROPERTY_NAME` for invalid property names
37 | - The only case when the property is invalid is if it starts with `\0` character
38 | - PHP bug #68546
39 | - Fixed compatibility with json ext for `JSOND_ERROR_CTRL_CHAR`
40 |
41 | #### Encoder
42 | - Added depth checking for greater than 0 and lower than `INT_MAX`
43 | - PHP bug #72787
44 | - Added `JSOND_PRESERVE_ZERO_FRACTION` option for better handling of float values
45 | - Fixed blank line inside empty array/object when JSOND_PRETTY_PRINT is set
46 | - PHP bug #66021
47 | - Fixed `JSOND_NUMERIC_CHECK` issue with NaN and Inf double
48 | - PHP bug #64695
49 |
50 | ### Internal changes
51 | - Added compatibility with PHP 7
52 | - Used new UTF8 decoder based on automaton from Bjoern Hoehrmann
53 | - Introduced new experimental buffer for encoding
54 | - Added a build option to enable it: `--enable-jsond-buffer-native`
55 | - Added a possibility to switch prefix to json and replace existing json functions and constants
56 | - Added a build option to use json prefixing: `--enable-jsond-with-json-prefix`
57 | - Use special template for Bison
58 | - Version 3.0.4 has to be used
59 | - The parser and scanner is rebuilt only if enabled in configuration
60 | - Added a build option to rebuild it: `--enable-jsond-filegen`
61 |
62 |
63 | ## 1.3
64 |
65 | ### User visible changes
66 |
67 | #### Decoder
68 | - Rejected ECMA-404 incompatible number formats
69 | - top level (PHP json_decode check): `07`, `0xff`, `.1`, `-.1`
70 | - all (JSON_Parser): `[1.]`, [1.e1]
71 | - Added new option `JSOND_VALID_ESCAPED_UNICODE` to check if \uXXXX code is not ill-formed surrogate pair
72 | - If set, the new error `JSOND_ERROR_UTF16` will be set for invalid \uXXXX code
73 |
74 | ### Internal changes
75 | - Removed JSON_parser.h header
76 | - Removed utf8_decode.h header
77 | - Error codes constants moved to php_json.h
78 | - Renamed `enum error_codes` to `php_json_error_codes` (typedef)
79 | - Changed ext global `error_code` type from `int` to `php_json_error_codes` enum
80 | - Renamed macro JSON_PARSER_DEFAULT_DEPTH to PHP_JSON_PARSER_DEFAULT_DEPTH
81 |
82 |
83 | ## 1.2
84 |
85 | Version 1.2 of jsond has never been released as it is a version of the json extension in PHP 5.
86 |
--------------------------------------------------------------------------------
/bench/compare_with_json.php:
--------------------------------------------------------------------------------
1 | $_SERVER, 'b' => $_SERVER)),
68 | );
69 |
70 | foreach ($jsons as $json) {
71 | echo "STR: $json\n";
72 | echo "DECODING\n";
73 | test_json_decode($json);
74 | test_jsond_decode($json);
75 | $json_object = json_decode($json);
76 | echo "ENCODING\n";
77 | test_json_encode($json_object);
78 | test_jsond_encode($json_object);
79 | }
80 |
--------------------------------------------------------------------------------
/config.m4:
--------------------------------------------------------------------------------
1 | dnl $Id$
2 | dnl config.m4 for extension jsond
3 |
4 | PHP_ARG_ENABLE(jsond,
5 | [whether to enable jsond support],
6 | [AS_HELP_STRING([--disable-jsond],
7 | [Disable new JavaScript Object Serialization support])],
8 | yes)
9 |
10 | AC_ARG_ENABLE(jsond-prefixing,
11 | [AS_HELP_STRING([--enable-jsond-with-json-prefix],
12 | [Enable json prefixing])],
13 | [AC_DEFINE([PHP_JSOND_WITH_JSON_PREFIX],1,
14 | [whether json prefixing is enabled])])
15 |
16 | AC_ARG_ENABLE(jsond-buffer-native,
17 | [AS_HELP_STRING([--enable-jsond-buffer-native],
18 | [Enable new jsond native buffer])],
19 | [AC_DEFINE([PHP_JSOND_BUF_TYPE_NATIVE],1,
20 | [whether native buffer is enabled])])
21 |
22 | AC_ARG_ENABLE(jsond-filegen,
23 | [AS_HELP_STRING([--enable-jsond-filegen],
24 | [Enable jsond parser and scanner files generation])],
25 | [PHP_JSOND_FILEGEN=yes], [PHP_JSOND_FILEGEN=no])
26 |
27 | if test "$PHP_JSOND" != "no"; then
28 | AC_DEFINE([HAVE_JSOND],1 ,[whether to enable jsond support])
29 | AC_HEADER_STDC
30 |
31 | PHP_NEW_EXTENSION(jsond,
32 | jsond.c \
33 | jsond_buffer.c \
34 | jsond_dtoa.c \
35 | jsond_encoder.c \
36 | jsond_parser.tab.c \
37 | jsond_scanner.c,
38 | $ext_shared)
39 |
40 | if test "$PHP_JSOND_FILEGEN" != "no"; then
41 | PHP_ADD_MAKEFILE_FRAGMENT()
42 | fi
43 | PHP_INSTALL_HEADERS([ext/jsond], [php_jsond.h php_jsond_parser.h php_jsond_scanner.h])
44 | PHP_SUBST(JSOND_SHARED_LIBADD)
45 | fi
46 |
--------------------------------------------------------------------------------
/config.w32:
--------------------------------------------------------------------------------
1 | // $Id$
2 | // vim:ft=javascript
3 |
4 | ARG_ENABLE("jsond", "enable jsond support", "no");
5 |
6 | if (PHP_JSOND != "no") {
7 | EXTENSION("jsond", "jsond.c jsond_buffer.c jsond_dtoa.c jsond_encoder.c jsond_parser.tab.c jsond_scanner.c");
8 | }
9 |
10 |
--------------------------------------------------------------------------------
/jsond.c:
--------------------------------------------------------------------------------
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: Jakub Zelenka |
14 | +----------------------------------------------------------------------+
15 | */
16 |
17 | #include "php.h"
18 | #include "php_ini.h"
19 | #include "ext/standard/info.h"
20 | #include "ext/standard/html.h"
21 | #include "php_jsond.h"
22 | #include "php_jsond_encoder.h"
23 | #include "php_jsond_buffer.h"
24 | #include "php_jsond_parser.h"
25 | #include
26 |
27 | /* double limits */
28 | #include
29 | #define PHP_JSON_DOUBLE_MAX_LENGTH (3 + DBL_MANT_DIG - DBL_MIN_EXP)
30 |
31 | /* PHP init and user functions */
32 | static PHP_MINFO_FUNCTION(jsond);
33 | static PHP_FUNCTION(jsond_encode);
34 | static PHP_FUNCTION(jsond_decode);
35 | static PHP_FUNCTION(jsond_last_error);
36 | static PHP_FUNCTION(jsond_last_error_msg);
37 |
38 | static const char digits[] = "0123456789abcdef";
39 |
40 | PHP_JSOND_API zend_class_entry *php_jsond_serializable_ce;
41 |
42 | PHP_JSOND_API ZEND_DECLARE_MODULE_GLOBALS(jsond)
43 |
44 | /* arginfo */
45 | ZEND_BEGIN_ARG_INFO_EX(arginfo_jsond_encode, 0, 0, 1)
46 | ZEND_ARG_INFO(0, value)
47 | ZEND_ARG_INFO(0, options)
48 | ZEND_ARG_INFO(0, depth)
49 | ZEND_END_ARG_INFO()
50 |
51 | ZEND_BEGIN_ARG_INFO_EX(arginfo_jsond_decode, 0, 0, 1)
52 | ZEND_ARG_INFO(0, json)
53 | ZEND_ARG_INFO(0, assoc)
54 | ZEND_ARG_INFO(0, depth)
55 | ZEND_ARG_INFO(0, options)
56 | ZEND_END_ARG_INFO()
57 |
58 | ZEND_BEGIN_ARG_INFO(arginfo_jsond_last_error, 0)
59 | ZEND_END_ARG_INFO()
60 |
61 | ZEND_BEGIN_ARG_INFO(arginfo_jsond_last_error_msg, 0)
62 | ZEND_END_ARG_INFO()
63 |
64 |
65 | /* jsond_functions[] */
66 | static zend_function_entry jsond_functions[] = {
67 | PHP_FE(jsond_encode, arginfo_jsond_encode)
68 | PHP_FE(jsond_decode, arginfo_jsond_decode)
69 | PHP_FE(jsond_last_error, arginfo_jsond_last_error)
70 | PHP_FE(jsond_last_error_msg, arginfo_jsond_last_error_msg)
71 | PHP_FE_END
72 | };
73 |
74 |
75 | /* JsonSerializable methods */
76 | ZEND_BEGIN_ARG_INFO(jsond_serialize_arginfo, 0)
77 | /* No arguments */
78 | ZEND_END_ARG_INFO()
79 |
80 | static zend_function_entry jsond_serializable_interface[] = {
81 | PHP_ABSTRACT_ME(PHP_JSOND_SERIALIZABLE_INTERFACE, jsonSerialize, jsond_serialize_arginfo)
82 | PHP_FE_END
83 | };
84 |
85 |
86 | /* php_json_already_exists */
87 | static inline zend_bool php_json_already_exists()
88 | {
89 | return !strncmp(PHP_JSOND_PREFIX_STRING, "json", 5) &&
90 | zend_hash_str_exists(&module_registry, "json", strlen("json"));
91 | }
92 |
93 |
94 | /* php_json_register_serializable_interface */
95 | static inline void php_jsond_register_serializable_interface()
96 | {
97 | zend_class_entry ce;
98 |
99 | /* register JSON serializable class */
100 | INIT_CLASS_ENTRY(ce, PHP_JSOND_SERIALIZABLE_INTERFACE_STRING, jsond_serializable_interface);
101 | PHP_JSOND_NAME(serializable_ce) = zend_register_internal_interface(&ce);
102 | }
103 |
104 |
105 | #define PHP_JSOND_REGISTER_LONG_CONSTANT(name, lval) \
106 | do { \
107 | if (NULL == zend_hash_str_find( \
108 | EG(zend_constants), PHP_JSOND_CONSTANT"_"name, strlen(PHP_JSOND_CONSTANT"_"name))) { \
109 | REGISTER_LONG_CONSTANT(PHP_JSOND_CONSTANT"_"name, lval, CONST_CS | CONST_PERSISTENT); \
110 | } \
111 | } while(0)
112 |
113 | /* MINIT */
114 | static PHP_MINIT_FUNCTION(jsond)
115 | {
116 | if (!php_json_already_exists()) {
117 | /* register jsond function */
118 | if (zend_register_functions(NULL, jsond_functions, NULL, 0) == FAILURE) {
119 | zend_error(E_CORE_WARNING,"jsond: Unable to register functions");
120 | return FAILURE;
121 | }
122 |
123 | php_jsond_register_serializable_interface();
124 | }
125 |
126 | /* decoding options */
127 | PHP_JSOND_REGISTER_LONG_CONSTANT("OBJECT_AS_ARRAY", PHP_JSON_OBJECT_AS_ARRAY);
128 | PHP_JSOND_REGISTER_LONG_CONSTANT("BIGINT_AS_STRING", PHP_JSON_BIGINT_AS_STRING);
129 |
130 | /* encoding options */
131 | PHP_JSOND_REGISTER_LONG_CONSTANT("HEX_TAG", PHP_JSON_HEX_TAG);
132 | PHP_JSOND_REGISTER_LONG_CONSTANT("HEX_AMP", PHP_JSON_HEX_AMP);
133 | PHP_JSOND_REGISTER_LONG_CONSTANT("HEX_APOS", PHP_JSON_HEX_APOS);
134 | PHP_JSOND_REGISTER_LONG_CONSTANT("HEX_QUOT", PHP_JSON_HEX_QUOT);
135 | PHP_JSOND_REGISTER_LONG_CONSTANT("FORCE_OBJECT", PHP_JSON_FORCE_OBJECT);
136 | PHP_JSOND_REGISTER_LONG_CONSTANT("NUMERIC_CHECK", PHP_JSON_NUMERIC_CHECK);
137 | PHP_JSOND_REGISTER_LONG_CONSTANT("UNESCAPED_SLASHES", PHP_JSON_UNESCAPED_SLASHES);
138 | PHP_JSOND_REGISTER_LONG_CONSTANT("PRETTY_PRINT", PHP_JSON_PRETTY_PRINT);
139 | PHP_JSOND_REGISTER_LONG_CONSTANT("UNESCAPED_UNICODE", PHP_JSON_UNESCAPED_UNICODE);
140 | PHP_JSOND_REGISTER_LONG_CONSTANT("PARTIAL_OUTPUT_ON_ERROR", PHP_JSON_PARTIAL_OUTPUT_ON_ERROR);
141 | PHP_JSOND_REGISTER_LONG_CONSTANT("PRESERVE_ZERO_FRACTION", PHP_JSON_PRESERVE_ZERO_FRACTION);
142 | PHP_JSOND_REGISTER_LONG_CONSTANT("UNESCAPED_LINE_TERMINATORS", PHP_JSON_UNESCAPED_LINE_TERMINATORS);
143 |
144 | /* error constants */
145 | PHP_JSOND_REGISTER_LONG_CONSTANT("ERROR_NONE", PHP_JSON_ERROR_NONE);
146 | PHP_JSOND_REGISTER_LONG_CONSTANT("ERROR_DEPTH", PHP_JSON_ERROR_DEPTH);
147 | PHP_JSOND_REGISTER_LONG_CONSTANT("ERROR_STATE_MISMATCH", PHP_JSON_ERROR_STATE_MISMATCH);
148 | PHP_JSOND_REGISTER_LONG_CONSTANT("ERROR_CTRL_CHAR", PHP_JSON_ERROR_CTRL_CHAR);
149 | PHP_JSOND_REGISTER_LONG_CONSTANT("ERROR_SYNTAX", PHP_JSON_ERROR_SYNTAX);
150 | PHP_JSOND_REGISTER_LONG_CONSTANT("ERROR_UTF8", PHP_JSON_ERROR_UTF8);
151 | PHP_JSOND_REGISTER_LONG_CONSTANT("ERROR_RECURSION", PHP_JSON_ERROR_RECURSION);
152 | PHP_JSOND_REGISTER_LONG_CONSTANT("ERROR_INF_OR_NAN", PHP_JSON_ERROR_INF_OR_NAN);
153 | PHP_JSOND_REGISTER_LONG_CONSTANT("ERROR_UNSUPPORTED_TYPE", PHP_JSON_ERROR_UNSUPPORTED_TYPE);
154 | PHP_JSOND_REGISTER_LONG_CONSTANT("ERROR_INVALID_PROPERTY_NAME", PHP_JSON_ERROR_INVALID_PROPERTY_NAME);
155 | PHP_JSOND_REGISTER_LONG_CONSTANT("ERROR_UTF16", PHP_JSON_ERROR_UTF16);
156 |
157 | return SUCCESS;
158 | }
159 |
160 | #define PHP_JSON_REPLACE_FN(_orig, _name) \
161 | _orig = zend_hash_str_find_ptr(EG(function_table), "json_"#_name, strlen("json_"#_name)); \
162 | _orig->internal_function.handler = PHP_JSOND_FN(_name);
163 |
164 |
165 | /* RINIT */
166 | PHP_RINIT_FUNCTION(jsond)
167 | {
168 | zend_function *orig;
169 |
170 | if (php_json_already_exists()) {
171 | PHP_JSON_REPLACE_FN(orig, encode);
172 | PHP_JSON_REPLACE_FN(orig, decode);
173 | PHP_JSON_REPLACE_FN(orig, last_error);
174 | PHP_JSON_REPLACE_FN(orig, last_error_msg);
175 |
176 | zend_string *class_name = zend_string_init(
177 | PHP_JSOND_SERIALIZABLE_INTERFACE_STRING,
178 | sizeof(PHP_JSOND_SERIALIZABLE_INTERFACE_STRING) - 1,
179 | 0
180 | );
181 | zend_class_entry *the_ce = zend_lookup_class(class_name);
182 | zend_string_release(class_name);
183 | if (!the_ce) {
184 | return FAILURE;
185 | }
186 | PHP_JSOND_NAME(serializable_ce) = the_ce;
187 | }
188 |
189 | return SUCCESS;
190 | }
191 |
192 |
193 | /* PHP_GINIT_FUNCTION */
194 | static PHP_GINIT_FUNCTION(jsond)
195 | {
196 | #if defined(ZTS) && defined(COMPILE_DL_JSOND)
197 | ZEND_TSRMLS_CACHE_UPDATE();
198 | #endif
199 | jsond_globals->encoder_depth = 0;
200 | jsond_globals->error_code = PHP_JSON_ERROR_NONE;
201 | jsond_globals->encode_max_depth = PHP_JSON_PARSER_DEFAULT_DEPTH;
202 | }
203 |
204 |
205 | /* jsond_module_entry */
206 | zend_module_entry jsond_module_entry = {
207 | STANDARD_MODULE_HEADER,
208 | "jsond",
209 | NULL,
210 | PHP_MINIT(jsond),
211 | NULL,
212 | PHP_RINIT(jsond),
213 | NULL,
214 | PHP_MINFO(jsond),
215 | PHP_JSOND_VERSION,
216 | PHP_MODULE_GLOBALS(jsond),
217 | PHP_GINIT(jsond),
218 | NULL,
219 | NULL,
220 | STANDARD_MODULE_PROPERTIES_EX
221 | };
222 |
223 | #ifdef COMPILE_DL_JSOND
224 | ZEND_GET_MODULE(jsond)
225 | #endif
226 |
227 | /* PHP_MINFO_FUNCTION */
228 | static PHP_MINFO_FUNCTION(jsond)
229 | {
230 | php_info_print_table_start();
231 | php_info_print_table_row(2, "jsond support", "enabled");
232 | php_info_print_table_row(2, "jsond version", PHP_JSOND_VERSION);
233 | php_info_print_table_end();
234 | }
235 |
236 | PHP_JSOND_API int php_jsond_encode(php_json_buffer *buf, zval *val, int options)
237 | {
238 | php_json_encoder encoder;
239 | int return_code;
240 |
241 | php_json_encode_init(&encoder);
242 | encoder.max_depth = JSOND_G(encode_max_depth);
243 | encoder.error_code = PHP_JSON_ERROR_NONE;
244 |
245 | return_code = php_json_encode_zval(buf, val, options, &encoder);
246 | JSOND_G(error_code) = encoder.error_code;
247 |
248 | return return_code;
249 | }
250 |
251 | PHP_JSOND_API int php_jsond_decode_ex(
252 | zval *return_value, char *str, size_t str_len, int options, int depth)
253 | {
254 | php_json_parser parser;
255 |
256 | PHP_JSOND_NAME(parser_init)(&parser, return_value, str, str_len, options, depth);
257 |
258 | if (php_json_yyparse(&parser)) {
259 | JSOND_G(error_code) = PHP_JSOND_NAME(parser_error_code)(&parser);
260 | RETVAL_NULL();
261 | return FAILURE;
262 | }
263 |
264 | return SUCCESS;
265 | }
266 |
267 |
268 | /* proto string json_encode(mixed data [, int options[, int depth]])
269 | Returns the JSON representation of a value */
270 | static PHP_FUNCTION(jsond_encode)
271 | {
272 | zval *parameter;
273 | php_json_buffer buf;
274 | zend_long options = 0;
275 | zend_long depth = PHP_JSON_PARSER_DEFAULT_DEPTH;
276 |
277 | ZEND_PARSE_PARAMETERS_START(1, 3)
278 | Z_PARAM_ZVAL(parameter)
279 | Z_PARAM_OPTIONAL
280 | Z_PARAM_LONG(options)
281 | Z_PARAM_LONG(depth)
282 | ZEND_PARSE_PARAMETERS_END();
283 |
284 | JSOND_G(error_code) = PHP_JSON_ERROR_NONE;
285 |
286 | JSOND_G(encode_max_depth) = depth;
287 |
288 | PHP_JSON_BUF_INIT(&buf);
289 | php_jsond_encode(&buf, parameter, (int)options);
290 |
291 | if ((JSOND_G(error_code) != PHP_JSON_ERROR_NONE && !(options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR)) ||
292 | PHP_JSON_BUF_LENGTH(buf) > LONG_MAX) {
293 | ZVAL_FALSE(return_value);
294 | PHP_JSON_BUF_DESTROY(&buf);
295 | } else {
296 | PHP_JSON_BUF_RETURN(buf, return_value);
297 | }
298 | }
299 |
300 | /* proto mixed json_decode(string json [, bool assoc [, long depth]])
301 | Decodes the JSON representation into a PHP value */
302 | static PHP_FUNCTION(jsond_decode)
303 | {
304 | char *str;
305 | size_t str_len;
306 | zend_bool assoc = 0; /* return JS objects as PHP objects by default */
307 | zend_bool assoc_null = 1;
308 | zend_long depth = PHP_JSON_PARSER_DEFAULT_DEPTH;
309 | zend_long options = 0;
310 |
311 | ZEND_PARSE_PARAMETERS_START(1, 4)
312 | Z_PARAM_STRING(str, str_len)
313 | Z_PARAM_OPTIONAL
314 | Z_PARAM_BOOL_EX(assoc, assoc_null, 1, 0)
315 | Z_PARAM_LONG(depth)
316 | Z_PARAM_LONG(options)
317 | ZEND_PARSE_PARAMETERS_END();
318 |
319 | JSOND_G(error_code) = 0;
320 |
321 | if (!str_len) {
322 | JSOND_G(error_code) = PHP_JSON_ERROR_SYNTAX;
323 | RETURN_NULL();
324 | }
325 |
326 | if (depth <= 0) {
327 | php_error_docref(NULL, E_WARNING, "Depth must be greater than zero");
328 | RETURN_NULL();
329 | }
330 |
331 | if (depth > INT_MAX) {
332 | php_error_docref(NULL, E_WARNING, "Depth must be lower than %d", INT_MAX);
333 | RETURN_NULL();
334 | }
335 |
336 | /* For BC reasons, the bool $assoc overrides the long $options bit for PHP_JSON_OBJECT_AS_ARRAY */
337 | if (!assoc_null) {
338 | if (assoc) {
339 | options |= PHP_JSON_OBJECT_AS_ARRAY;
340 | } else {
341 | options &= ~PHP_JSON_OBJECT_AS_ARRAY;
342 | }
343 | }
344 |
345 | php_jsond_decode_ex(return_value, str, (size_t) str_len, (int) options, (int) depth);
346 | }
347 |
348 | /* proto int json_last_error()
349 | Returns the error code of the last json_encode() or json_decode() call. */
350 | static PHP_FUNCTION(jsond_last_error)
351 | {
352 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "") == FAILURE) {
353 | return;
354 | }
355 |
356 | RETURN_LONG(JSOND_G(error_code));
357 | }
358 |
359 | #define PHP_JSON_ERROR_MSG_RETURN(_msg) \
360 | RETURN_STRINGL(_msg, sizeof(_msg) - 1)
361 |
362 | /* proto string json_last_error_msg()
363 | Returns the error string of the last json_encode() or json_decode() call. */
364 | static PHP_FUNCTION(jsond_last_error_msg)
365 | {
366 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "") == FAILURE) {
367 | return;
368 | }
369 |
370 | switch(JSOND_G(error_code)) {
371 | case PHP_JSON_ERROR_NONE:
372 | PHP_JSON_ERROR_MSG_RETURN("No error");
373 | case PHP_JSON_ERROR_DEPTH:
374 | PHP_JSON_ERROR_MSG_RETURN("Maximum stack depth exceeded");
375 | case PHP_JSON_ERROR_STATE_MISMATCH:
376 | PHP_JSON_ERROR_MSG_RETURN("State mismatch (invalid or malformed JSON)");
377 | case PHP_JSON_ERROR_CTRL_CHAR:
378 | PHP_JSON_ERROR_MSG_RETURN("Control character error, possibly incorrectly encoded");
379 | case PHP_JSON_ERROR_SYNTAX:
380 | PHP_JSON_ERROR_MSG_RETURN("Syntax error");
381 | case PHP_JSON_ERROR_UTF8:
382 | PHP_JSON_ERROR_MSG_RETURN("Malformed UTF-8 characters, possibly incorrectly encoded");
383 | case PHP_JSON_ERROR_RECURSION:
384 | PHP_JSON_ERROR_MSG_RETURN("Recursion detected");
385 | case PHP_JSON_ERROR_INF_OR_NAN:
386 | PHP_JSON_ERROR_MSG_RETURN("Inf and NaN cannot be JSON encoded");
387 | case PHP_JSON_ERROR_UNSUPPORTED_TYPE:
388 | PHP_JSON_ERROR_MSG_RETURN("Type is not supported");
389 | case PHP_JSON_ERROR_INVALID_PROPERTY_NAME:
390 | PHP_JSON_ERROR_MSG_RETURN("The decoded property name is invalid");
391 | case PHP_JSON_ERROR_UTF16:
392 | PHP_JSON_ERROR_MSG_RETURN("Single unpaired UTF-16 surrogate in unicode escape");
393 | default:
394 | PHP_JSON_ERROR_MSG_RETURN("Unknown error");
395 | }
396 |
397 | }
398 |
399 | /*
400 | * Local variables:
401 | * tab-width: 4
402 | * c-basic-offset: 4
403 | * End:
404 | * vim600: noet sw=4 ts=4 fdm=marker
405 | * vim<600: noet sw=4 ts=4
406 | */
407 |
--------------------------------------------------------------------------------
/jsond.php:
--------------------------------------------------------------------------------
1 | ";
3 |
4 | if(!extension_loaded('jsond')) {
5 | dl('jsond.' . PHP_SHLIB_SUFFIX);
6 | }
7 | $module = 'jsond';
8 | $functions = get_extension_funcs($module);
9 | echo "Functions available in the test extension:$br\n";
10 | foreach($functions as $func) {
11 | echo $func."$br\n";
12 | }
13 | echo "$br\n";
14 | $function = 'confirm_' . $module . '_compiled';
15 | if (extension_loaded($module)) {
16 | $str = $function($module);
17 | } else {
18 | $str = "Module $module is not compiled into PHP";
19 | }
20 | echo "$str\n";
21 | ?>
22 |
--------------------------------------------------------------------------------
/jsond_buffer.c:
--------------------------------------------------------------------------------
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: Jakub Zelenka |
14 | +----------------------------------------------------------------------+
15 | */
16 |
17 | #ifdef HAVE_CONFIG_H
18 | #include "config.h"
19 | #endif
20 |
21 | #ifdef PHP_JSOND_BUF_TYPE_NATIVE
22 |
23 | #include
24 |
25 | #include "php_jsond_buffer.h"
26 | #include "php_jsond.h"
27 |
28 | void php_json_buffer_init(php_json_buffer *buf)
29 | {
30 | buf->dbuf = NULL;
31 | buf->ptr = &buf->sbuf[0];
32 | buf->end = &buf->sbuf[PHP_JSON_BUFFER_STATIC_SIZE - 1];
33 | buf->dsize = 0;
34 | buf->mark = NULL;
35 | buf->flags = 0;
36 | }
37 |
38 | void php_json_buffer_destroy(php_json_buffer *buf)
39 | {
40 | if (buf->dbuf) {
41 | efree(buf->dbuf);
42 | }
43 | }
44 |
45 | void php_json_buffer_flush(php_json_buffer *buf, size_t pre_alloc_size)
46 | {
47 | ptrdiff_t static_size = buf->ptr - &buf->sbuf[0];
48 | size_t size = static_size + pre_alloc_size;
49 | if (buf->dbuf) {
50 | buf->dbuf = erealloc(buf->dbuf, buf->dsize + size);
51 | } else {
52 | buf->dbuf = emalloc(size);
53 | }
54 | memcpy(buf->dbuf + buf->dsize, &buf->sbuf[0], static_size);
55 | /* mark dynamic buffer if mark set and is not already dynamic */
56 | if (buf->mark && !(buf->flags & PHP_JSON_BUFFER_FLAG_MARK_DBUF)) {
57 | buf->mark = &buf->dbuf[buf->dsize + (buf->mark - &buf->sbuf[0])];
58 | buf->flags |= PHP_JSON_BUFFER_FLAG_MARK_DBUF;
59 | }
60 | buf->dsize += static_size;
61 | buf->ptr = &buf->sbuf[0];
62 | }
63 |
64 | void php_json_buffer_finish(php_json_buffer *buf)
65 | {
66 | php_json_buffer_flush(buf, 1);
67 | buf->dbuf[buf->dsize] = 0;
68 | }
69 |
70 | void php_json_buffer_alloc(php_json_buffer *buf, size_t len)
71 | {
72 |
73 | }
74 |
75 | void php_json_buffer_reset(php_json_buffer *buf)
76 | {
77 | if (!buf->mark) {
78 | if (buf->dbuf) {
79 | efree(buf->dbuf);
80 | }
81 | php_json_buffer_init(buf);
82 | } else {
83 | if (buf->flags & PHP_JSON_BUFFER_FLAG_MARK_DBUF) {
84 | buf->dsize = buf->mark - buf->dbuf;
85 | buf->dbuf = erealloc(buf->dbuf, buf->dsize);
86 | buf->ptr = &buf->sbuf[0];
87 | } else {
88 | buf->ptr = buf->mark;
89 | }
90 | }
91 | }
92 |
93 | #endif /* PHP_JSON_BUF_TYPE_NATIVE */
94 |
--------------------------------------------------------------------------------
/jsond_dtoa.c:
--------------------------------------------------------------------------------
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: Jakub Zelenka |
14 | +----------------------------------------------------------------------+
15 | */
16 |
17 | #include "php.h"
18 | #include "php_jsond_compat.h"
19 | #include "php_jsond_dtoa.h"
20 | #include
21 |
22 | char *php_jsond_gcvt(double value, int ndigit, char dec_point, char exponent, char *buf)
23 | {
24 | char *digits, *dst, *src;
25 | int i, decpt;
26 | php_jsond_dtoa_sign_t sign;
27 | int mode = ndigit >= 0 ? 2 : 0;
28 |
29 | if (mode == 0) {
30 | ndigit = 17;
31 | }
32 | digits = zend_dtoa(value, mode, ndigit, &decpt, &sign, NULL);
33 | if (decpt == 9999) {
34 | /*
35 | * Infinity or NaN, convert to inf or nan with sign.
36 | * We assume the buffer is at least ndigit long.
37 | */
38 | snprintf(buf, ndigit + 1, "%s%s", (sign && *digits == 'I') ? "-" : "", *digits == 'I' ? "INF" : "NAN");
39 | zend_freedtoa(digits);
40 | return (buf);
41 | }
42 |
43 | dst = buf;
44 | if (sign) {
45 | *dst++ = '-';
46 | }
47 |
48 | if ((decpt >= 0 && decpt > ndigit) || decpt < -3) { /* use E-style */
49 | /* exponential format (e.g. 1.2345e+13) */
50 | if (--decpt < 0) {
51 | sign = 1;
52 | decpt = -decpt;
53 | } else {
54 | sign = 0;
55 | }
56 | src = digits;
57 | *dst++ = *src++;
58 | *dst++ = dec_point;
59 | if (*src == '\0') {
60 | *dst++ = '0';
61 | } else {
62 | do {
63 | *dst++ = *src++;
64 | } while (*src != '\0');
65 | }
66 | *dst++ = exponent;
67 | if (sign) {
68 | *dst++ = '-';
69 | } else {
70 | *dst++ = '+';
71 | }
72 | if (decpt < 10) {
73 | *dst++ = '0' + decpt;
74 | *dst = '\0';
75 | } else {
76 | /* XXX - optimize */
77 | int n;
78 | for (n = decpt, i = 0; (n /= 10) != 0; i++);
79 | dst[i + 1] = '\0';
80 | while (decpt != 0) {
81 | dst[i--] = '0' + decpt % 10;
82 | decpt /= 10;
83 | }
84 | }
85 | } else if (decpt < 0) {
86 | /* standard format 0. */
87 | *dst++ = '0'; /* zero before decimal point */
88 | *dst++ = dec_point;
89 | do {
90 | *dst++ = '0';
91 | } while (++decpt < 0);
92 | src = digits;
93 | while (*src != '\0') {
94 | *dst++ = *src++;
95 | }
96 | *dst = '\0';
97 | } else {
98 | /* standard format */
99 | for (i = 0, src = digits; i < decpt; i++) {
100 | if (*src != '\0') {
101 | *dst++ = *src++;
102 | } else {
103 | *dst++ = '0';
104 | }
105 | }
106 | if (*src != '\0') {
107 | if (src == digits) {
108 | *dst++ = '0'; /* zero before decimal point */
109 | }
110 | *dst++ = dec_point;
111 | for (i = decpt; digits[i] != '\0'; i++) {
112 | *dst++ = digits[i];
113 | }
114 | }
115 | *dst = '\0';
116 | }
117 | zend_freedtoa(digits);
118 | return (buf);
119 | }
120 |
--------------------------------------------------------------------------------
/jsond_encoder.c:
--------------------------------------------------------------------------------
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 |
14 | | Jakub Zelenka |
15 | +----------------------------------------------------------------------+
16 | */
17 |
18 | #include "php.h"
19 | #include "php_ini.h"
20 | #include "ext/standard/info.h"
21 | #include "ext/standard/html.h"
22 | #include "php_jsond.h"
23 | #include "php_jsond_compat.h"
24 | #include "php_jsond_encoder.h"
25 | #include "php_jsond_dtoa.h"
26 | #include "php_jsond_buffer.h"
27 | #include "php_jsond_utf8_decoder.h"
28 | #include
29 |
30 | /* double limits */
31 | #include
32 | #if defined(DBL_MANT_DIG) && defined(DBL_MIN_EXP)
33 | #define PHP_JSON_DOUBLE_MAX_LENGTH (3 + DBL_MANT_DIG - DBL_MIN_EXP)
34 | #else
35 | #define PHP_JSON_DOUBLE_MAX_LENGTH 1080
36 | #endif
37 |
38 | ZEND_EXTERN_MODULE_GLOBALS(jsond)
39 |
40 | static const char php_json_digits[] = "0123456789abcdef";
41 |
42 | static int php_json_determine_array_type(zval *val)
43 | {
44 | int i;
45 | HashTable *myht = Z_ARRVAL_P(val);
46 |
47 | i = myht ? zend_hash_num_elements(myht) : 0;
48 | if (i > 0) {
49 | zend_ulong index, idx = 0;
50 | zend_string *key;
51 |
52 | if (HT_IS_PACKED(myht) && HT_IS_WITHOUT_HOLES(myht)) {
53 | return PHP_JSON_OUTPUT_ARRAY;
54 | }
55 |
56 | ZEND_HASH_FOREACH_KEY(myht, index, key) {
57 | if (key || index != idx) {
58 | return PHP_JSON_OUTPUT_OBJECT;
59 | }
60 | idx++;
61 | } ZEND_HASH_FOREACH_END();
62 | }
63 |
64 | return PHP_JSON_OUTPUT_ARRAY;
65 | }
66 |
67 | /* Pretty printing support functions */
68 |
69 | static inline void php_json_pretty_print_char(
70 | php_json_buffer *buf, int options, char c)
71 | {
72 | if (options & PHP_JSON_PRETTY_PRINT) {
73 | PHP_JSON_BUF_APPEND_CHAR(buf, c);
74 | }
75 | }
76 |
77 | static inline void php_json_pretty_print_indent(
78 | php_json_buffer *buf, int options, php_json_encoder *encoder)
79 | {
80 | int i;
81 |
82 | if (options & PHP_JSON_PRETTY_PRINT) {
83 | for (i = 0; i < encoder->depth; ++i) {
84 | PHP_JSON_BUF_APPEND_STRING(buf, " ", 4);
85 | }
86 | }
87 | }
88 |
89 | /* Double encoding */
90 |
91 | static inline int php_json_is_valid_double(double d)
92 | {
93 | return !zend_isinf(d) && !zend_isnan(d);
94 | }
95 |
96 | static inline void php_json_encode_double(
97 | php_json_buffer *buf, double d, int options)
98 | {
99 | size_t len;
100 | PHP_JSON_BUF_DOUBLE_BLOCK_INIT(buf, num, PHP_JSON_DOUBLE_MAX_LENGTH);
101 | php_jsond_gcvt(d, PG(serialize_precision), '.', 'e', &num[0]);
102 | len = strlen(num);
103 | if ((options & PHP_JSON_PRESERVE_ZERO_FRACTION) && strchr(num, '.') == NULL) {
104 | memcpy(&num[len], ".0", sizeof(".0"));
105 | len += 2;
106 | }
107 | PHP_JSON_BUF_DOUBLE_BLOCK_CLOSE(buf, num, len);
108 | }
109 |
110 | /* String encoding */
111 |
112 | static inline char *php_json_escape_string_flush_ex(
113 | php_json_buffer *buf, char *mark, char *s, char *esc,
114 | int esc_len, int extralen)
115 | {
116 | char *prechar = s - extralen;
117 | if (prechar != mark) {
118 | PHP_JSON_BUF_APPEND_STRING(buf, mark, prechar - mark);
119 | }
120 | if (esc_len) {
121 | PHP_JSON_BUF_APPEND_STRING(buf, esc, esc_len);
122 | }
123 | return s + 1;
124 | }
125 |
126 | static inline char *php_json_escape_string_flush(
127 | php_json_buffer *buf, char *mark, char *s, char *esc, int esc_len)
128 | {
129 | return php_json_escape_string_flush_ex(buf, mark, s, esc, esc_len, 0);
130 | }
131 |
132 | static int php_json_escape_string(
133 | php_json_buffer *buf, char *s, size_t len, int options,
134 | php_json_encoder *encoder)
135 | {
136 | size_t count;
137 | int codepoint;
138 | int state = 0;
139 | int codelen = 0;
140 | char *mark = s;
141 | PHP_JSON_BUF_MARK_DECLARE(buf);
142 |
143 | if (len == 0) {
144 | PHP_JSON_BUF_APPEND_STRING(buf, "\"\"", 2);
145 | return SUCCESS;
146 | }
147 |
148 | if (options & PHP_JSON_NUMERIC_CHECK) {
149 | double d;
150 | int type;
151 | long p;
152 |
153 | if ((type = is_numeric_string(s, len, &p, &d, 0)) != 0) {
154 | if (type == IS_LONG) {
155 | PHP_JSON_BUF_APPEND_LONG(buf, p);
156 | return SUCCESS;
157 | }
158 | if (type == IS_DOUBLE && php_json_is_valid_double(d)) {
159 | php_json_encode_double(buf, d, options);
160 | return SUCCESS;
161 | }
162 | }
163 | }
164 |
165 | /* set mark */
166 | PHP_JSON_BUF_MARK_SET(buf);
167 |
168 | /* pre-allocate for string length plus 2 quotes */
169 | PHP_JSON_BUF_ALLOC(buf, len);
170 | PHP_JSON_BUF_APPEND_CHAR(buf, '"');
171 |
172 | for (count = 0; count < len; count++, s++) {
173 | if (php_json_utf8_decode(&state, &codepoint, (unsigned char) *s)) {
174 | codelen++;
175 | continue;
176 | }
177 |
178 | switch (codepoint) {
179 | case '"':
180 | if (options & PHP_JSON_HEX_QUOT) {
181 | mark = php_json_escape_string_flush(buf, mark, s, "\\u0022", 6);
182 | } else {
183 | mark = php_json_escape_string_flush(buf, mark, s, "\\\"", 2);
184 | }
185 | break;
186 |
187 | case '\\':
188 | mark = php_json_escape_string_flush(buf, mark, s, "\\\\", 2);
189 | break;
190 |
191 | case '/':
192 | if (!(options & PHP_JSON_UNESCAPED_SLASHES)) {
193 | mark = php_json_escape_string_flush(buf, mark, s, "\\/", 2);
194 | }
195 | break;
196 |
197 | case '\b':
198 | mark = php_json_escape_string_flush(buf, mark, s, "\\b", 2);
199 | break;
200 |
201 | case '\f':
202 | mark = php_json_escape_string_flush(buf, mark, s, "\\f", 2);
203 | break;
204 |
205 | case '\n':
206 | mark = php_json_escape_string_flush(buf, mark, s, "\\n", 2);
207 | break;
208 |
209 | case '\r':
210 | mark = php_json_escape_string_flush(buf, mark, s, "\\r", 2);
211 | break;
212 |
213 | case '\t':
214 | mark = php_json_escape_string_flush(buf, mark, s, "\\t", 2);
215 | break;
216 |
217 | case '<':
218 | if (options & PHP_JSON_HEX_TAG) {
219 | mark = php_json_escape_string_flush(buf, mark, s, "\\u003C", 6);
220 | }
221 | break;
222 |
223 | case '>':
224 | if (options & PHP_JSON_HEX_TAG) {
225 | mark = php_json_escape_string_flush(buf, mark, s, "\\u003E", 6);
226 | }
227 | break;
228 |
229 | case '&':
230 | if (options & PHP_JSON_HEX_AMP) {
231 | mark = php_json_escape_string_flush(buf, mark, s, "\\u0026", 6);
232 | }
233 | break;
234 |
235 | case '\'':
236 | if (options & PHP_JSON_HEX_APOS) {
237 | mark = php_json_escape_string_flush(buf, mark, s, "\\u0027", 6);
238 | }
239 | break;
240 |
241 | default:
242 | if (codepoint < ' ' || (
243 | codepoint > 0x7f && (
244 | !(options & PHP_JSON_UNESCAPED_UNICODE) ||
245 | ((codepoint == 0x2028 || codepoint == 0x2029) && !(options & PHP_JSON_UNESCAPED_LINE_TERMINATORS))
246 | )
247 | )
248 | ) {
249 | mark = php_json_escape_string_flush_ex(buf, mark, s, "\\u", 2, codepoint < ' ' ? 0 : codelen);
250 | codelen = 0;
251 | if (codepoint <= 0xffff) {
252 | PHP_JSON_BUF_APPEND_CHAR(buf, php_json_digits[(codepoint & 0xf000) >> 12]);
253 | PHP_JSON_BUF_APPEND_CHAR(buf, php_json_digits[(codepoint & 0xf00) >> 8]);
254 | PHP_JSON_BUF_APPEND_CHAR(buf, php_json_digits[(codepoint & 0xf0) >> 4]);
255 | PHP_JSON_BUF_APPEND_CHAR(buf, php_json_digits[(codepoint & 0xf)]);
256 | } else {
257 | PHP_JSON_BUF_APPEND_CHAR(buf, php_json_digits[((0xD7C0 + (codepoint >> 10)) & 0xf000) >> 12]);
258 | PHP_JSON_BUF_APPEND_CHAR(buf, php_json_digits[((0xD7C0 + (codepoint >> 10)) & 0xf00) >> 8]);
259 | PHP_JSON_BUF_APPEND_CHAR(buf, php_json_digits[((0xD7C0 + (codepoint >> 10)) & 0xf0) >> 4]);
260 | PHP_JSON_BUF_APPEND_CHAR(buf, php_json_digits[((0xD7C0 + (codepoint >> 10)) & 0xf)]);
261 | PHP_JSON_BUF_APPEND_STRING(buf, "\\u", 2);
262 | PHP_JSON_BUF_APPEND_CHAR(buf, php_json_digits[((0xDC00 + (codepoint & 0x3FF)) & 0xf000) >> 12]);
263 | PHP_JSON_BUF_APPEND_CHAR(buf, php_json_digits[((0xDC00 + (codepoint & 0x3FF)) & 0xf00) >> 8]);
264 | PHP_JSON_BUF_APPEND_CHAR(buf, php_json_digits[((0xDC00 + (codepoint & 0x3FF)) & 0xf0) >> 4]);
265 | PHP_JSON_BUF_APPEND_CHAR(buf, php_json_digits[((0xDC00 + (codepoint & 0x3FF)) & 0xf)]);
266 | }
267 | }
268 | break;
269 | }
270 | }
271 |
272 | if (state != PHP_JSON_UTF8_ACCEPT) {
273 | encoder->error_code = PHP_JSON_ERROR_UTF8;
274 | if (options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR) {
275 | PHP_JSON_BUF_RESET(buf);
276 | PHP_JSON_BUF_APPEND_STRING(buf, "null", 4);
277 | }
278 | return FAILURE;
279 | } else {
280 | if (mark < s) {
281 | PHP_JSON_BUF_APPEND_STRING(buf, mark, s - mark);
282 | }
283 | PHP_JSON_BUF_APPEND_CHAR(buf, '"');
284 | }
285 | PHP_JSON_BUF_MARK_DELETE(buf);
286 |
287 | return SUCCESS;
288 | }
289 |
290 | /* Array encoding */
291 |
292 | #define PHP_JSON_HASH_PROTECT_RECURSION(_tmp_ht) \
293 | do { \
294 | if (_tmp_ht && PHP_JSON_APPLY_PROTECTION(_tmp_ht)) { \
295 | PHP_JSON_INC_APPLY_COUNT(_tmp_ht); \
296 | } \
297 | } while (0)
298 |
299 | #define PHP_JSON_HASH_UNPROTECT_RECURSION(_tmp_ht) \
300 | do { \
301 | if (_tmp_ht && PHP_JSON_APPLY_PROTECTION(_tmp_ht)) { \
302 | PHP_JSON_DEC_APPLY_COUNT(_tmp_ht); \
303 | } \
304 | } while (0)
305 |
306 | static int php_json_encode_array(
307 | php_json_buffer *buf, zval *val, int options,
308 | php_json_encoder *encoder)
309 | {
310 | int i, r, need_comma = 0;
311 | HashTable *myht;
312 |
313 | if (Z_TYPE_P(val) == IS_ARRAY) {
314 | myht = Z_ARRVAL_P(val);
315 | r = (options & PHP_JSON_FORCE_OBJECT) ? PHP_JSON_OUTPUT_OBJECT : php_json_determine_array_type(val);
316 | } else {
317 | myht = Z_OBJPROP_P(val);
318 | r = PHP_JSON_OUTPUT_OBJECT;
319 | }
320 |
321 | if (myht && PHP_JSON_HAS_APPLY_COUNT(myht)) {
322 | encoder->error_code = PHP_JSON_ERROR_RECURSION;
323 | if (options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR) {
324 | PHP_JSON_BUF_APPEND_STRING(buf, "null", 4);
325 | }
326 | return FAILURE;
327 | }
328 |
329 | PHP_JSON_HASH_PROTECT_RECURSION(myht);
330 |
331 | if (r == PHP_JSON_OUTPUT_ARRAY) {
332 | PHP_JSON_BUF_APPEND_CHAR(buf, '[');
333 | } else {
334 | PHP_JSON_BUF_APPEND_CHAR(buf, '{');
335 | }
336 |
337 | ++encoder->depth;
338 |
339 | i = myht ? zend_hash_num_elements(myht) : 0;
340 |
341 | if (i > 0) {
342 | zend_string *key;
343 | zval *data;
344 | zval *z_data;
345 | zend_ulong index;
346 | HashTable *tmp_ht;
347 |
348 | ZEND_HASH_FOREACH_KEY_VAL_IND(myht, index, key, z_data) {
349 | ZVAL_DEREF(z_data);
350 |
351 | if (r == PHP_JSON_OUTPUT_ARRAY) {
352 | if (need_comma) {
353 | PHP_JSON_BUF_APPEND_CHAR(buf, ',');
354 | } else {
355 | need_comma = 1;
356 | }
357 |
358 | php_json_pretty_print_char(buf, options, '\n');
359 | php_json_pretty_print_indent(buf, options, encoder);
360 | } else if (r == PHP_JSON_OUTPUT_OBJECT) {
361 | /* append key */
362 | if (key) {
363 | if (ZSTR_VAL(key)[0] == '\0' && ZSTR_LEN(key) > 0 && Z_TYPE_P(val) == IS_OBJECT) {
364 | /* Skip protected and private members. */
365 | continue;
366 | }
367 |
368 | if (need_comma) {
369 | PHP_JSON_BUF_APPEND_CHAR(buf, ',');
370 | } else {
371 | need_comma = 1;
372 | }
373 |
374 | php_json_pretty_print_char(buf, options, '\n');
375 | php_json_pretty_print_indent(buf, options, encoder);
376 |
377 | php_json_escape_string(buf, ZSTR_VAL(key), ZSTR_LEN(key),
378 | options & ~PHP_JSON_NUMERIC_CHECK, encoder);
379 | } else {
380 | if (need_comma) {
381 | PHP_JSON_BUF_APPEND_CHAR(buf, ',');
382 | } else {
383 | need_comma = 1;
384 | }
385 |
386 | php_json_pretty_print_char(buf, options, '\n');
387 | php_json_pretty_print_indent(buf, options, encoder);
388 |
389 | PHP_JSON_BUF_APPEND_CHAR(buf, '"');
390 | PHP_JSON_BUF_APPEND_LONG(buf, (long) index);
391 | PHP_JSON_BUF_APPEND_CHAR(buf, '"');
392 | }
393 | PHP_JSON_BUF_APPEND_CHAR(buf, ':');
394 | /* append value */
395 | php_json_pretty_print_char(buf, options, ' ');
396 | }
397 |
398 | if (php_json_encode_zval(buf, z_data, options, encoder) == FAILURE &&
399 | !(options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR)) {
400 | PHP_JSON_HASH_UNPROTECT_RECURSION(myht);
401 | return FAILURE;
402 | };
403 | } ZEND_HASH_FOREACH_END();
404 |
405 | }
406 |
407 | PHP_JSON_HASH_UNPROTECT_RECURSION(myht);
408 |
409 | if (encoder->depth > encoder->max_depth) {
410 | encoder->error_code = PHP_JSON_ERROR_DEPTH;
411 | if (!(options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR)) {
412 | return FAILURE;
413 | }
414 | }
415 | --encoder->depth;
416 |
417 | /* Only keep closing bracket on same line for empty arrays/objects */
418 | if (need_comma) {
419 | php_json_pretty_print_char(buf, options, '\n');
420 | php_json_pretty_print_indent(buf, options, encoder);
421 | }
422 |
423 | if (r == PHP_JSON_OUTPUT_ARRAY) {
424 | PHP_JSON_BUF_APPEND_CHAR(buf, ']');
425 | } else {
426 | PHP_JSON_BUF_APPEND_CHAR(buf, '}');
427 | }
428 |
429 | return SUCCESS;
430 | }
431 |
432 | /* Serializable interface */
433 |
434 | static int php_json_encode_serializable_object(
435 | php_json_buffer *buf, zval *val, int options,
436 | php_json_encoder *encoder)
437 | {
438 | zend_class_entry *ce = Z_OBJCE_P(val);
439 | zval fname;
440 | zval retval;
441 | HashTable* myht;
442 | int return_code;
443 |
444 | if (Z_TYPE_P(val) == IS_ARRAY) {
445 | myht = Z_ARRVAL_P(val);
446 | } else {
447 | myht = Z_OBJPROP_P(val);
448 | }
449 |
450 | if (myht && PHP_JSON_HAS_APPLY_COUNT(myht)) {
451 | encoder->error_code = PHP_JSON_ERROR_RECURSION;
452 | if (options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR) {
453 | PHP_JSON_BUF_APPEND_STRING(buf, "null", 4);
454 | }
455 | return FAILURE;
456 | }
457 |
458 | PHP_JSON_HASH_PROTECT_RECURSION(myht);
459 |
460 | ZVAL_STRING(&fname, "jsonSerialize");
461 |
462 | if (FAILURE == call_user_function(EG(function_table), val, &fname, &retval, 0, NULL)
463 | || Z_ISUNDEF(retval)) {
464 | if (!EG(exception)) {
465 | zend_throw_exception_ex(NULL, 0, "Failed calling %s::jsonSerialize()", ZSTR_VAL(ce->name));
466 | }
467 | if (options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR) {
468 | PHP_JSON_BUF_APPEND_STRING(buf, "null", sizeof("null") - 1);
469 | }
470 | zval_dtor(&fname);
471 | PHP_JSON_HASH_UNPROTECT_RECURSION(myht);
472 | return FAILURE;
473 | }
474 |
475 | if (EG(exception)) {
476 | /* Error already raised */
477 | zval_ptr_dtor(&retval);
478 | zval_dtor(&fname);
479 | if (options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR) {
480 | PHP_JSON_BUF_APPEND_STRING(buf, "null", sizeof("null") - 1);
481 | }
482 | PHP_JSON_HASH_UNPROTECT_RECURSION(myht);
483 | return FAILURE;
484 | }
485 |
486 | if ((Z_TYPE(retval) == IS_OBJECT) && (Z_OBJ_HANDLE(retval) == Z_OBJ_HANDLE_P(val))) {
487 | /* Handle the case where jsonSerialize does: return $this; by going straight to encode array */
488 | PHP_JSON_HASH_UNPROTECT_RECURSION(myht);
489 | return_code = php_json_encode_array(buf, &retval, options, encoder);
490 | } else {
491 | /* All other types, encode as normal */
492 | return_code = php_json_encode_zval(buf, &retval, options, encoder);
493 | PHP_JSON_HASH_UNPROTECT_RECURSION(myht);
494 | }
495 |
496 | zval_ptr_dtor(&retval);
497 | zval_dtor(&fname);
498 |
499 | return return_code;
500 | }
501 |
502 | /* ZVAL encoding */
503 |
504 | int php_json_encode_zval(php_json_buffer *buf, zval *val, int options,php_json_encoder *encoder)
505 | {
506 | again:
507 | switch (Z_TYPE_P(val)) {
508 | case IS_NULL:
509 | PHP_JSON_BUF_APPEND_STRING(buf, "null", 4);
510 | break;
511 |
512 | case IS_LONG:
513 | PHP_JSON_BUF_APPEND_LONG(buf, Z_LVAL_P(val));
514 | break;
515 |
516 | case IS_DOUBLE:
517 | if (php_json_is_valid_double(Z_DVAL_P(val))) {
518 | php_json_encode_double(buf, Z_DVAL_P(val), options);
519 | } else {
520 | encoder->error_code = PHP_JSON_ERROR_INF_OR_NAN;
521 | PHP_JSON_BUF_APPEND_CHAR(buf, '0');
522 | }
523 | break;
524 |
525 | case IS_STRING:
526 | return php_json_escape_string(
527 | buf, Z_STRVAL_P(val), Z_STRLEN_P(val), options, encoder);
528 |
529 | case IS_OBJECT:
530 | if (instanceof_function(Z_OBJCE_P(val), php_jsond_serializable_ce)) {
531 | return php_json_encode_serializable_object(buf, val, options, encoder);
532 | }
533 | /* fallthrough -- Non-serializable object */
534 | case IS_ARRAY:
535 | return php_json_encode_array(buf, val, options, encoder);
536 | case IS_TRUE:
537 | PHP_JSON_BUF_APPEND_STRING(buf, "true", 4);
538 | break;
539 |
540 | case IS_FALSE:
541 | PHP_JSON_BUF_APPEND_STRING(buf, "false", 5);
542 | break;
543 |
544 | case IS_REFERENCE:
545 | val = Z_REFVAL_P(val);
546 | goto again;
547 |
548 | default:
549 | encoder->error_code = PHP_JSON_ERROR_UNSUPPORTED_TYPE;
550 | if (options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR) {
551 | PHP_JSON_BUF_APPEND_STRING(buf, "null", 4);
552 | }
553 | return FAILURE;
554 | }
555 |
556 | return SUCCESS;
557 | }
558 |
--------------------------------------------------------------------------------
/jsond_parser.tab.h:
--------------------------------------------------------------------------------
1 | /* A Bison parser, made by GNU Bison 3.0.4. */
2 |
3 | /* Bison interface for Yacc-like parsers in C
4 |
5 | Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc.
6 |
7 | This program is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see . */
19 |
20 | /* As a special exception, you may create a larger work that contains
21 | part or all of the Bison parser skeleton and distribute that work
22 | under terms of your choice, so long as that work isn't itself a
23 | parser generator using the skeleton or a modified version thereof
24 | as a parser skeleton. Alternatively, if you modify or redistribute
25 | the parser skeleton itself, you may (at your option) remove this
26 | special exception, which will cause the skeleton and the resulting
27 | Bison output files to be licensed under the GNU General Public
28 | License without this special exception.
29 |
30 | This special exception was added by the Free Software Foundation in
31 | version 2.2 of Bison. */
32 |
33 | #ifndef YY_PHP_JSON_YY_PARSER_INCLUDED
34 | # define YY_PHP_JSON_YY_PARSER_INCLUDED
35 | /* Debug traces. */
36 | #ifndef YYDEBUG
37 | # define YYDEBUG 0
38 | #endif
39 | #if YYDEBUG
40 | extern int php_json_yydebug;
41 | #endif
42 |
43 | /* Token type. */
44 | #ifndef YYTOKENTYPE
45 | # define YYTOKENTYPE
46 | enum yytokentype
47 | {
48 | PHP_JSON_T_NUL = 258,
49 | PHP_JSON_T_TRUE = 259,
50 | PHP_JSON_T_FALSE = 260,
51 | PHP_JSON_T_INT = 261,
52 | PHP_JSON_T_DOUBLE = 262,
53 | PHP_JSON_T_STRING = 263,
54 | PHP_JSON_T_ESTRING = 264,
55 | PHP_JSON_T_EOI = 265,
56 | PHP_JSON_T_ERROR = 266
57 | };
58 | #endif
59 | /* Tokens. */
60 | #define PHP_JSON_T_NUL 258
61 | #define PHP_JSON_T_TRUE 259
62 | #define PHP_JSON_T_FALSE 260
63 | #define PHP_JSON_T_INT 261
64 | #define PHP_JSON_T_DOUBLE 262
65 | #define PHP_JSON_T_STRING 263
66 | #define PHP_JSON_T_ESTRING 264
67 | #define PHP_JSON_T_EOI 265
68 | #define PHP_JSON_T_ERROR 266
69 |
70 | /* Value type. */
71 | #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
72 |
73 | union YYSTYPE
74 | {
75 |
76 |
77 | zval value;
78 | struct {
79 | zend_string *key;
80 | zval val;
81 | } pair;
82 |
83 |
84 | };
85 |
86 | typedef union YYSTYPE YYSTYPE;
87 | # define YYSTYPE_IS_TRIVIAL 1
88 | # define YYSTYPE_IS_DECLARED 1
89 | #endif
90 |
91 |
92 |
93 | int php_json_yyparse (php_json_parser *parser);
94 |
95 | #endif /* !YY_PHP_JSON_YY_PARSER_INCLUDED */
96 |
--------------------------------------------------------------------------------
/jsond_parser.y:
--------------------------------------------------------------------------------
1 | %code top {
2 | /*
3 | +----------------------------------------------------------------------+
4 | | Copyright (c) The PHP Group |
5 | +----------------------------------------------------------------------+
6 | | This source file is subject to version 3.01 of the PHP license, |
7 | | that is bundled with this package in the file LICENSE, and is |
8 | | available through the world-wide-web at the following url: |
9 | | http://www.php.net/license/3_01.txt |
10 | | If you did not receive a copy of the PHP license and are unable to |
11 | | obtain it through the world-wide-web, please send a note to |
12 | | license@php.net so we can mail you a copy immediately. |
13 | +----------------------------------------------------------------------+
14 | | Author: Jakub Zelenka |
15 | +----------------------------------------------------------------------+
16 | */
17 |
18 | #include "php.h"
19 | #include "php_jsond.h"
20 | #include "php_jsond_compat.h"
21 | #include "php_jsond_parser.h"
22 |
23 | #define YYDEBUG 0
24 |
25 | #if YYDEBUG
26 | int json_yydebug = 1;
27 | #endif
28 |
29 | #ifdef _MSC_VER
30 | #define YYMALLOC malloc
31 | #define YYFREE free
32 | #endif
33 |
34 | #define PHP_JSON_USE(uv) ((void) (uv))
35 | #define PHP_JSON_USE_1(uvr, uv1) PHP_JSON_USE(uvr); PHP_JSON_USE(uv1)
36 | #define PHP_JSON_USE_2(uvr, uv1, uv2) \
37 | PHP_JSON_USE(uvr); PHP_JSON_USE(uv1); PHP_JSON_USE(uv2)
38 |
39 | #define PHP_JSON_DEPTH_DEC --parser->depth
40 | #define PHP_JSON_DEPTH_INC \
41 | if (parser->max_depth && parser->depth >= parser->max_depth) { \
42 | parser->scanner.errcode = PHP_JSON_ERROR_DEPTH; \
43 | YYERROR; \
44 | } \
45 | ++parser->depth
46 |
47 | }
48 |
49 | %pure-parser
50 | %name-prefix "php_json_yy"
51 | %lex-param { php_json_parser *parser }
52 | %parse-param { php_json_parser *parser }
53 |
54 | %union {
55 | zval value;
56 | struct {
57 | zend_string *key;
58 | zval val;
59 | } pair;
60 | }
61 |
62 |
63 | %token PHP_JSON_T_NUL
64 | %token PHP_JSON_T_TRUE
65 | %token PHP_JSON_T_FALSE
66 | %token PHP_JSON_T_INT
67 | %token PHP_JSON_T_DOUBLE
68 | %token PHP_JSON_T_STRING
69 | %token PHP_JSON_T_ESTRING
70 | %token PHP_JSON_T_EOI
71 | %token PHP_JSON_T_ERROR
72 |
73 | %type start object key value array errlex
74 | %type members member elements element
75 | %type pair
76 |
77 | %destructor { zval_dtor(&$$); }
78 | %destructor { PHP_JSOND_RELEASE_STRING($$.key); zval_dtor(&$$.val); }
79 |
80 | %code {
81 | int php_json_yylex(union YYSTYPE *value, php_json_parser *parser);
82 | void php_json_yyerror(php_json_parser *parser, char const *msg);
83 |
84 | }
85 |
86 | %% /* Rules */
87 |
88 | start:
89 | value PHP_JSON_T_EOI
90 | {
91 | $$ = $1;
92 | ZVAL_COPY_VALUE(parser->return_value, &$1);
93 | PHP_JSON_USE($2);
94 | YYACCEPT;
95 | }
96 | | value errlex
97 | {
98 | PHP_JSON_USE_2($$, $1, $2);
99 | }
100 | ;
101 |
102 | object:
103 | '{' {
104 | PHP_JSON_DEPTH_INC;
105 | if (parser->methods.object_start && FAILURE == parser->methods.object_start(parser)) {
106 | YYERROR;
107 | }
108 | }
109 | members object_end
110 | {
111 | PHP_JSON_DEPTH_DEC;
112 | $$ = $3;
113 | if (parser->methods.object_end && FAILURE == parser->methods.object_end(parser, &$$)) {
114 | YYERROR;
115 | }
116 | }
117 | ;
118 |
119 | object_end:
120 | '}'
121 | | ']'
122 | {
123 | parser->scanner.errcode = PHP_JSON_ERROR_STATE_MISMATCH;
124 | YYERROR;
125 | }
126 | ;
127 |
128 | members:
129 | /* empty */
130 | {
131 | parser->methods.object_create(parser, &$$);
132 | }
133 | | member
134 | ;
135 |
136 | member:
137 | pair
138 | {
139 | parser->methods.object_create(parser, &$$);
140 | if (parser->methods.object_update(parser, &$$, $1.key, &$1.val) == FAILURE)
141 | YYERROR;
142 | }
143 | | member ',' pair
144 | {
145 | if (parser->methods.object_update(parser, &$$, $3.key, &$3.val) == FAILURE)
146 | YYERROR;
147 | $$ = $1;
148 | }
149 | | member errlex
150 | {
151 | PHP_JSON_USE_2($$, $1, $2);
152 | }
153 | ;
154 |
155 | pair:
156 | key ':' value
157 | {
158 | $$.key = Z_STR($1);
159 | $$.val = $3;
160 | }
161 | | key errlex
162 | {
163 | PHP_JSON_USE_2($$, $1, $2);
164 | }
165 | ;
166 |
167 | array:
168 | '['
169 | {
170 | PHP_JSON_DEPTH_INC;
171 | if (parser->methods.array_start && FAILURE == parser->methods.array_start(parser)) {
172 | YYERROR;
173 | }
174 | }
175 | elements array_end
176 | {
177 | PHP_JSON_DEPTH_DEC;
178 | $$ = $3;
179 | if (parser->methods.array_end && FAILURE == parser->methods.array_end(parser, &$$)) {
180 | YYERROR;
181 | }
182 | }
183 | ;
184 |
185 | array_end:
186 | ']'
187 | | '}'
188 | {
189 | parser->scanner.errcode = PHP_JSON_ERROR_STATE_MISMATCH;
190 | YYERROR;
191 | }
192 | ;
193 |
194 | elements:
195 | /* empty */
196 | {
197 | parser->methods.array_create(parser, &$$);
198 | }
199 | | element
200 | ;
201 |
202 | element:
203 | value
204 | {
205 | parser->methods.array_create(parser, &$$);
206 | parser->methods.array_append(parser, &$$, &$1);
207 | }
208 | | element ',' value
209 | {
210 | parser->methods.array_append(parser, &$1, &$3);
211 | $$ = $1;
212 | }
213 | | element errlex
214 | {
215 | PHP_JSON_USE_2($$, $1, $2);
216 | }
217 | ;
218 |
219 | key:
220 | PHP_JSON_T_STRING
221 | | PHP_JSON_T_ESTRING
222 | ;
223 |
224 | value:
225 | object
226 | | array
227 | | PHP_JSON_T_STRING
228 | | PHP_JSON_T_ESTRING
229 | | PHP_JSON_T_INT
230 | | PHP_JSON_T_DOUBLE
231 | | PHP_JSON_T_NUL
232 | | PHP_JSON_T_TRUE
233 | | PHP_JSON_T_FALSE
234 | | errlex
235 | ;
236 |
237 | errlex:
238 | PHP_JSON_T_ERROR
239 | {
240 | PHP_JSON_USE_1($$, $1);
241 | YYERROR;
242 | }
243 | ;
244 |
245 | %% /* Functions */
246 |
247 | static int php_json_parser_array_create(php_json_parser *parser, zval *array)
248 | {
249 | array_init(array);
250 | return SUCCESS;
251 | }
252 |
253 |
254 | static int php_json_parser_array_append(php_json_parser *parser, zval *array, zval *zvalue)
255 | {
256 | zend_hash_next_index_insert(Z_ARRVAL_P(array), zvalue);
257 | return SUCCESS;
258 | }
259 |
260 | static int php_json_parser_object_create(php_json_parser *parser, zval *object)
261 | {
262 | if (parser->scanner.options & PHP_JSON_OBJECT_AS_ARRAY) {
263 | array_init(object);
264 | } else {
265 | object_init(object);
266 | }
267 | }
268 |
269 | static int php_json_parser_object_update(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue)
270 | {
271 |
272 | /* if JSON_OBJECT_AS_ARRAY is set */
273 | if (Z_TYPE_P(object) == IS_ARRAY) {
274 | zend_symtable_update(Z_ARRVAL_P(object), key, zvalue);
275 | } else {
276 | zval zkey;
277 |
278 | if (ZSTR_LEN(key) > 0 && ZSTR_VAL(key)[0] == '\0') {
279 | parser->scanner.errcode = PHP_JSON_ERROR_INVALID_PROPERTY_NAME;
280 | PHP_JSOND_RELEASE_STRING(key);
281 | zval_dtor(zvalue);
282 | zval_dtor(object);
283 | return FAILURE;
284 | }
285 | PHP_JSOND_WRITE_PROPERTY(object, key, zvalue);
286 | Z_TRY_DELREF_P(zvalue);
287 | }
288 | PHP_JSOND_RELEASE_STRING(key);
289 |
290 | return SUCCESS;
291 | }
292 |
293 | int php_json_yylex(union YYSTYPE *value, php_json_parser *parser)
294 | {
295 | int token = php_json_scan(&parser->scanner);
296 | value->value = parser->scanner.value;
297 | return token;
298 | }
299 |
300 | void php_json_yyerror(php_json_parser *parser, char const *msg)
301 | {
302 | if (!parser->scanner.errcode) {
303 | parser->scanner.errcode = PHP_JSON_ERROR_SYNTAX;
304 | }
305 | }
306 |
307 | PHP_JSOND_API php_json_error_code PHP_JSOND_NAME(parser_error_code)(const php_json_parser *parser)
308 | {
309 | return parser->scanner.errcode;
310 | }
311 |
312 | static const php_json_parser_methods default_parser_methods =
313 | {
314 | php_json_parser_array_create,
315 | php_json_parser_array_append,
316 | NULL,
317 | NULL,
318 | php_json_parser_object_create,
319 | php_json_parser_object_update,
320 | NULL,
321 | NULL,
322 | };
323 |
324 | PHP_JSOND_API void PHP_JSOND_NAME(parser_init_ex)(
325 | php_json_parser *parser, zval *return_value,
326 | char *str, size_t str_len,
327 | int options, int max_depth,
328 | const php_json_parser_methods *parser_methods)
329 | {
330 | memset(parser, 0, sizeof(php_json_parser));
331 | php_json_scanner_init(&parser->scanner, str, str_len, options);
332 | parser->depth = 1;
333 | parser->max_depth = max_depth;
334 | parser->return_value = return_value;
335 | memcpy(&parser->methods, parser_methods, sizeof(php_json_parser_methods));
336 | }
337 |
338 | PHP_JSOND_API void PHP_JSOND_NAME(parser_init)(
339 | php_json_parser *parser, zval *return_value,
340 | char *str, size_t str_len,
341 | int options, int max_depth)
342 | {
343 | PHP_JSOND_NAME(parser_init_ex)(
344 | parser,
345 | return_value,
346 | str,
347 | str_len,
348 | options,
349 | max_depth,
350 | &default_parser_methods);
351 | }
352 |
353 |
354 | PHP_JSOND_API int PHP_JSOND_NAME(parse)(php_json_parser *parser)
355 | {
356 | return php_json_yyparse(parser);
357 | }
358 |
--------------------------------------------------------------------------------
/jsond_scanner.re:
--------------------------------------------------------------------------------
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: Jakub Zelenka |
14 | +----------------------------------------------------------------------+
15 | */
16 |
17 | #include "php.h"
18 | #include "php_jsond_scanner.h"
19 | #include "php_jsond_scanner_defs.h"
20 | #include "php_jsond_parser.h"
21 | #include "jsond_parser.tab.h"
22 |
23 | #define YYCTYPE php_json_ctype
24 | #define YYCURSOR s->cursor
25 | #define YYLIMIT s->limit
26 | #define YYMARKER s->marker
27 | #define YYCTXMARKER s->ctxmarker
28 |
29 | #define YYGETCONDITION() s->state
30 | #define YYSETCONDITION(yystate) s->state = yystate
31 |
32 | #define YYFILL(n)
33 |
34 | #define PHP_JSON_CONDITION_SET(condition) YYSETCONDITION(yyc##condition)
35 | #define PHP_JSON_CONDITION_GOTO(condition) goto yyc_##condition
36 |
37 | #define PHP_JSON_SCANNER_COPY_ESC() php_json_scanner_copy_string(s, 0)
38 | #define PHP_JSON_SCANNER_COPY_UTF() php_json_scanner_copy_string(s, 5)
39 | #define PHP_JSON_SCANNER_COPY_UTF_SP() php_json_scanner_copy_string(s, 11)
40 |
41 |
42 | static void php_json_scanner_copy_string(php_json_scanner *s, int esc_size)
43 | {
44 | size_t len = s->cursor - s->str_start - esc_size - 1;
45 | if (len) {
46 | memcpy(s->pstr, s->str_start, len);
47 | s->pstr += len;
48 | }
49 | }
50 |
51 | static int php_json_hex_to_int(char code)
52 | {
53 | if (code >= '0' && code <= '9') {
54 | return code - '0';
55 | } else if (code >= 'A' && code <= 'F') {
56 | return code - ('A' - 10);
57 | } else if (code >= 'a' && code <= 'f') {
58 | return code - ('a' - 10);
59 | } else {
60 | /* this should never happened (just to suppress compiler warning) */
61 | return -1;
62 | }
63 | }
64 |
65 | static int php_json_ucs2_to_int_ex(php_json_scanner *s, int size, int start)
66 | {
67 | int i, code = 0;
68 | php_json_ctype *pc = s->cursor - start;
69 | for (i = 0; i < size; i++) {
70 | code |= php_json_hex_to_int(*(pc--)) << (i * 4);
71 | }
72 | return code;
73 | }
74 |
75 | static int php_json_ucs2_to_int(php_json_scanner *s, int size)
76 | {
77 | return php_json_ucs2_to_int_ex(s, size, 1);
78 | }
79 |
80 | void php_json_scanner_init(php_json_scanner *s, char *str, size_t str_len, int options)
81 | {
82 | s->cursor = (php_json_ctype *) str;
83 | s->limit = (php_json_ctype *) str + str_len;
84 | s->options = options;
85 | PHP_JSON_CONDITION_SET(JS);
86 | }
87 |
88 | int php_json_scan(php_json_scanner *s)
89 | {
90 | ZVAL_NULL(&s->value);
91 |
92 | std:
93 | s->token = s->cursor;
94 |
95 | /*!re2c
96 | re2c:indent:top = 1;
97 | re2c:yyfill:enable = 0;
98 |
99 | DIGIT = [0-9] ;
100 | DIGITNZ = [1-9] ;
101 | UINT = "0" | ( DIGITNZ DIGIT* ) ;
102 | INT = "-"? UINT ;
103 | HEX = DIGIT | [a-fA-F] ;
104 | HEXNZ = DIGITNZ | [a-fA-F] ;
105 | HEX7 = [0-7] ;
106 | HEXC = DIGIT | [a-cA-C] ;
107 | FLOAT = INT "." DIGIT+ ;
108 | EXP = ( INT | FLOAT ) [eE] [+-]? DIGIT+ ;
109 | NL = "\r"? "\n" ;
110 | WS = [ \t\r]+ ;
111 | EOI = "\000";
112 | CTRL = [\x00-\x1F] ;
113 | UTF8T = [\x80-\xBF] ;
114 | UTF8_1 = [\x00-\x7F] ;
115 | UTF8_2 = [\xC2-\xDF] UTF8T ;
116 | UTF8_3A = "\xE0" [\xA0-\xBF] UTF8T ;
117 | UTF8_3B = [\xE1-\xEC] UTF8T{2} ;
118 | UTF8_3C = "\xED" [\x80-\x9F] UTF8T ;
119 | UTF8_3D = [\xEE-\xEF] UTF8T{2} ;
120 | UTF8_3 = UTF8_3A | UTF8_3B | UTF8_3C | UTF8_3D ;
121 | UTF8_4A = "\xF0"[\x90-\xBF] UTF8T{2} ;
122 | UTF8_4B = [\xF1-\xF3] UTF8T{3} ;
123 | UTF8_4C = "\xF4" [\x80-\x8F] UTF8T{2} ;
124 | UTF8_4 = UTF8_4A | UTF8_4B | UTF8_4C ;
125 | UTF8 = UTF8_1 | UTF8_2 | UTF8_3 | UTF8_4 ;
126 | ANY = [^] ;
127 | ESCPREF = "\\" ;
128 | ESCSYM = ( "\"" | "\\" | "/" | [bfnrt] ) ;
129 | ESC = ESCPREF ESCSYM ;
130 | UTFSYM = "u" ;
131 | UTFPREF = ESCPREF UTFSYM ;
132 | UCS2 = UTFPREF HEX{4} ;
133 | UTF16_1 = UTFPREF "00" HEX7 HEX ;
134 | UTF16_2 = UTFPREF "0" HEX7 HEX{2} ;
135 | UTF16_3 = UTFPREF ( ( ( HEXC | [efEF] ) HEX ) | ( [dD] HEX7 ) ) HEX{2} ;
136 | UTF16_4 = UTFPREF [dD] [89abAB] HEX{2} UTFPREF [dD] [c-fC-F] HEX{2} ;
137 |
138 | "{" { return '{'; }
139 | "}" { return '}'; }
140 | "[" { return '['; }
141 | "]" { return ']'; }
142 | ":" { return ':'; }
143 | "," { return ','; }
144 | "null" {
145 | ZVAL_NULL(&s->value);
146 | return PHP_JSON_T_NUL;
147 | }
148 | "true" {
149 | ZVAL_TRUE(&s->value);
150 | return PHP_JSON_T_TRUE;
151 | }
152 | "false" {
153 | ZVAL_FALSE(&s->value);
154 | return PHP_JSON_T_FALSE;
155 | }
156 | INT {
157 | zend_bool bigint = 0, negative = s->token[0] == '-';
158 | size_t digits = (size_t) (s->cursor - s->token - negative);
159 | if (digits >= PHP_JSON_INT_MAX_LENGTH) {
160 | if (digits == PHP_JSON_INT_MAX_LENGTH) {
161 | int cmp = strncmp((char *) (s->token + negative), PHP_JSON_INT_MAX_DIGITS, PHP_JSON_INT_MAX_LENGTH);
162 | if (!(cmp < 0 || (cmp == 0 && negative))) {
163 | bigint = 1;
164 | }
165 | } else {
166 | bigint = 1;
167 | }
168 | }
169 | if (!bigint) {
170 | ZVAL_LONG(&s->value, strtol((char *) s->token, NULL, 10));
171 | return PHP_JSON_T_INT;
172 | } else if (s->options & PHP_JSON_BIGINT_AS_STRING) {
173 | ZVAL_STRINGL(&s->value, (char *) s->token, s->cursor - s->token);
174 | return PHP_JSON_T_STRING;
175 | } else {
176 | ZVAL_DOUBLE(&s->value, zend_strtod((char *) s->token, NULL));
177 | return PHP_JSON_T_DOUBLE;
178 | }
179 | }
180 | FLOAT|EXP {
181 | ZVAL_DOUBLE(&s->value, zend_strtod((char *) s->token, NULL));
182 | return PHP_JSON_T_DOUBLE;
183 | }
184 | NL|WS { goto std; }
185 | EOI {
186 | if (s->limit < s->cursor) {
187 | return PHP_JSON_T_EOI;
188 | } else {
189 | s->errcode = PHP_JSON_ERROR_CTRL_CHAR;
190 | return PHP_JSON_T_ERROR;
191 | }
192 | }
193 | ["] {
194 | s->str_start = s->cursor;
195 | s->str_esc = 0;
196 | PHP_JSON_CONDITION_SET(STR_P1);
197 | PHP_JSON_CONDITION_GOTO(STR_P1);
198 | }
199 | CTRL {
200 | s->errcode = PHP_JSON_ERROR_CTRL_CHAR;
201 | return PHP_JSON_T_ERROR;
202 | }
203 | UTF8 {
204 | s->errcode = PHP_JSON_ERROR_SYNTAX;
205 | return PHP_JSON_T_ERROR;
206 | }
207 | ANY {
208 | s->errcode = PHP_JSON_ERROR_UTF8;
209 | return PHP_JSON_T_ERROR;
210 | }
211 |
212 | CTRL {
213 | s->errcode = PHP_JSON_ERROR_CTRL_CHAR;
214 | return PHP_JSON_T_ERROR;
215 | }
216 | UTF16_1 {
217 | s->str_esc += 5;
218 | PHP_JSON_CONDITION_GOTO(STR_P1);
219 | }
220 | UTF16_2 {
221 | s->str_esc += 4;
222 | PHP_JSON_CONDITION_GOTO(STR_P1);
223 | }
224 | UTF16_3 {
225 | s->str_esc += 3;
226 | PHP_JSON_CONDITION_GOTO(STR_P1);
227 | }
228 | UTF16_4 {
229 | s->str_esc += 8;
230 | PHP_JSON_CONDITION_GOTO(STR_P1);
231 | }
232 | UCS2 {
233 | s->errcode = PHP_JSON_ERROR_UTF16;
234 | return PHP_JSON_T_ERROR;
235 | }
236 | ESC {
237 | s->str_esc++;
238 | PHP_JSON_CONDITION_GOTO(STR_P1);
239 | }
240 | ESCPREF {
241 | s->errcode = PHP_JSON_ERROR_SYNTAX;
242 | return PHP_JSON_T_ERROR;
243 | }
244 | ["] {
245 | zend_string *str;
246 | size_t len = s->cursor - s->str_start - s->str_esc - 1;
247 | if (len == 0) {
248 | PHP_JSON_CONDITION_SET(JS);
249 | ZVAL_EMPTY_STRING(&s->value);
250 | return PHP_JSON_T_ESTRING;
251 | }
252 | str = zend_string_alloc(len, 0);
253 | ZSTR_VAL(str)[len] = '\0';
254 | ZVAL_STR(&s->value, str);
255 | if (s->str_esc) {
256 | s->pstr = (php_json_ctype *) Z_STRVAL(s->value);
257 | s->cursor = s->str_start;
258 | PHP_JSON_CONDITION_SET(STR_P2);
259 | PHP_JSON_CONDITION_GOTO(STR_P2);
260 | } else {
261 | memcpy(Z_STRVAL(s->value), s->str_start, len);
262 | PHP_JSON_CONDITION_SET(JS);
263 | return PHP_JSON_T_STRING;
264 | }
265 | }
266 | UTF8 { PHP_JSON_CONDITION_GOTO(STR_P1); }
267 | ANY {
268 | s->errcode = PHP_JSON_ERROR_UTF8;
269 | return PHP_JSON_T_ERROR;
270 | }
271 |
272 | UTF16_1 {
273 | int utf16 = php_json_ucs2_to_int(s, 2);
274 | PHP_JSON_SCANNER_COPY_UTF();
275 | *(s->pstr++) = (char) utf16;
276 | s->str_start = s->cursor;
277 | PHP_JSON_CONDITION_GOTO(STR_P2);
278 | }
279 | UTF16_2 {
280 | int utf16 = php_json_ucs2_to_int(s, 3);
281 | PHP_JSON_SCANNER_COPY_UTF();
282 | *(s->pstr++) = (char) (0xc0 | (utf16 >> 6));
283 | *(s->pstr++) = (char) (0x80 | (utf16 & 0x3f));
284 | s->str_start = s->cursor;
285 | PHP_JSON_CONDITION_GOTO(STR_P2);
286 | }
287 | UTF16_3 {
288 | int utf16 = php_json_ucs2_to_int(s, 4);
289 | PHP_JSON_SCANNER_COPY_UTF();
290 | *(s->pstr++) = (char) (0xe0 | (utf16 >> 12));
291 | *(s->pstr++) = (char) (0x80 | ((utf16 >> 6) & 0x3f));
292 | *(s->pstr++) = (char) (0x80 | (utf16 & 0x3f));
293 | s->str_start = s->cursor;
294 | PHP_JSON_CONDITION_GOTO(STR_P2);
295 | }
296 | UTF16_4 {
297 | int utf32, utf16_hi, utf16_lo;
298 | utf16_hi = php_json_ucs2_to_int(s, 4);
299 | utf16_lo = php_json_ucs2_to_int_ex(s, 4, 7);
300 | utf32 = ((utf16_lo & 0x3FF) << 10) + (utf16_hi & 0x3FF) + 0x10000;
301 | PHP_JSON_SCANNER_COPY_UTF_SP();
302 | *(s->pstr++) = (char) (0xf0 | (utf32 >> 18));
303 | *(s->pstr++) = (char) (0x80 | ((utf32 >> 12) & 0x3f));
304 | *(s->pstr++) = (char) (0x80 | ((utf32 >> 6) & 0x3f));
305 | *(s->pstr++) = (char) (0x80 | (utf32 & 0x3f));
306 | s->str_start = s->cursor;
307 | PHP_JSON_CONDITION_GOTO(STR_P2);
308 | }
309 | ESCPREF {
310 | char esc;
311 | PHP_JSON_SCANNER_COPY_ESC();
312 | switch (*s->cursor) {
313 | case 'b':
314 | esc = '\b';
315 | break;
316 | case 'f':
317 | esc = '\f';
318 | break;
319 | case 'n':
320 | esc = '\n';
321 | break;
322 | case 'r':
323 | esc = '\r';
324 | break;
325 | case 't':
326 | esc = '\t';
327 | break;
328 | case '\\':
329 | case '/':
330 | case '"':
331 | esc = *s->cursor;
332 | break;
333 | default:
334 | s->errcode = PHP_JSON_ERROR_SYNTAX;
335 | return PHP_JSON_T_ERROR;
336 | }
337 | *(s->pstr++) = esc;
338 | ++YYCURSOR;
339 | s->str_start = s->cursor;
340 | PHP_JSON_CONDITION_GOTO(STR_P2);
341 | }
342 | ["] => JS {
343 | PHP_JSON_SCANNER_COPY_ESC();
344 | return PHP_JSON_T_STRING;
345 | }
346 | ANY { PHP_JSON_CONDITION_GOTO(STR_P2); }
347 |
348 | <*>ANY {
349 | s->errcode = PHP_JSON_ERROR_SYNTAX;
350 | return PHP_JSON_T_ERROR;
351 | }
352 | */
353 |
354 | }
355 |
356 |
--------------------------------------------------------------------------------
/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 | jsond
10 | pecl.php.net
11 | JavaScript Object Notation
12 | This is a drop-in alternative to the standard PHP JSON extension.
13 |
14 | Jakub Zelenka
15 | bukka
16 | bukka@php.net
17 | yes
18 |
19 | 2017-04-14
20 |
21 | 1.4.0
22 | 1.4.0
23 |
24 |
25 | stable
26 | stable
27 |
28 | PHP 3.01
29 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 | 5.3.3
130 |
131 |
132 | 1.4.0a1
133 |
134 |
135 |
136 | jsond
137 |
138 |
139 |
140 | 2016-12-27
141 |
142 | 1.4.0RC1
143 | 1.4.0RC1
144 |
145 |
146 | beta
147 | beta
148 |
149 | PHP 3.01
150 |
166 |
167 |
168 | 2014-03-20
169 |
170 | 1.3.0
171 | 1.3.0
172 |
173 |
174 | beta
175 | beta
176 |
177 | PHP 3.01
178 |
181 |
182 |
183 |
184 |
--------------------------------------------------------------------------------
/php_jsond.h:
--------------------------------------------------------------------------------
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: Jakub Zelenka |
14 | +----------------------------------------------------------------------+
15 | */
16 |
17 | /* $Id$ */
18 |
19 | #ifndef PHP_JSOND_H
20 | #define PHP_JSOND_H
21 |
22 | #define PHP_JSOND_VERSION "1.5.0-dev"
23 |
24 | extern zend_module_entry jsond_module_entry;
25 | #define phpext_jsond_ptr &jsond_module_entry
26 |
27 | #if defined(PHP_WIN32) && defined(JSOND_EXPORTS)
28 | #define PHP_JSOND_API __declspec(dllexport)
29 | #else
30 | #define PHP_JSOND_API PHPAPI
31 | #endif
32 |
33 | #include "php.h"
34 |
35 | #ifdef ZTS
36 | #include "TSRM.h"
37 | #endif
38 |
39 | #ifdef HAVE_CONFIG_H
40 | #include "config.h"
41 | #endif
42 |
43 | #ifdef PHP_JSOND_WITH_JSON_PREFIX
44 | #define PHP_JSOND_PREFIX json
45 | #define PHP_JSOND_PREFIX_STRING "json"
46 | #define PHP_JSOND_CONSTANT "JSON"
47 | #define PHP_JSOND_SERIALIZABLE_INTERFACE JsonSerializable
48 | #define PHP_JSOND_SERIALIZABLE_INTERFACE_STRING "JsonSerializable"
49 | #define PHP_JSOND_SERIALIZABLE_INTERFACE_STRING_LC "jsonserializable"
50 | #define PHP_JSOND_NAME(name) php_json_ ## name
51 | #define PHP_JSOND_IDENT(name) json_ ## name
52 | #define PHP_JSOND_FN(jname) ZEND_FN(json_ ## jname)
53 | #else
54 | #define PHP_JSOND_PREFIX jsond
55 | #define PHP_JSOND_PREFIX_STRING "jsond"
56 | #define PHP_JSOND_CONSTANT "JSOND"
57 | #define PHP_JSOND_SERIALIZABLE_INTERFACE JsondSerializable
58 | #define PHP_JSOND_SERIALIZABLE_INTERFACE_STRING "JsondSerializable"
59 | #define PHP_JSOND_SERIALIZABLE_INTERFACE_STRING_LC "jsondserializable"
60 | #define PHP_JSOND_NAME(jname) php_jsond_ ## jname
61 | #define PHP_JSOND_IDENT(jname) jsond_ ## jname
62 | #define PHP_JSOND_FN(jname) ZEND_FN(jsond_ ## jname)
63 | #endif
64 |
65 | #define PHP_JSOND_FUNCTION(jname) PHP_FUNCTION(PHP_JSOND_IDENT(jname))
66 | #define PHP_JSOND_FE(jname, arginfo) PHP_FE(PHP_JSOND_IDENT(jname), arginfo)
67 |
68 | #ifndef HASH_KEY_NON_EXISTENT
69 | #define HASH_KEY_NON_EXISTENT HASH_KEY_NON_EXISTANT
70 | #endif
71 |
72 | #ifndef INIT_PZVAL_COPY
73 | #define INIT_PZVAL_COPY(z, v) \
74 | do { \
75 | (z)->value = (v)->value; \
76 | Z_TYPE_P(z) = Z_TYPE_P(v); \
77 | INIT_PZVAL(z) \
78 | } while (0)
79 | #endif
80 |
81 |
82 | /* This is important for the inline functions in debug mode as well
83 | * which is not done zend_always_inline. Such function are not inlined in
84 | * GCC 5 which results in a linking error */
85 | #if defined(__GNUC__) && __GNUC__ >= 3
86 | #define php_json_always_inline inline __attribute__((always_inline))
87 | #else
88 | #define php_json_always_inline inline
89 | #endif
90 |
91 | /* long limits */
92 | #if SIZEOF_LONG == 4
93 | #define PHP_JSON_INT_MAX_LENGTH 10
94 | #define PHP_JSON_INT_MAX_DIGITS "2147483648"
95 | #elif SIZEOF_LONG == 8
96 | #define PHP_JSON_INT_MAX_LENGTH 19
97 | #define PHP_JSON_INT_MAX_DIGITS "9223372036854775808"
98 | #else
99 | #error "Unknown SIZEOF_LONG"
100 | #endif
101 |
102 | typedef enum {
103 | PHP_JSON_ERROR_NONE = 0,
104 | PHP_JSON_ERROR_DEPTH,
105 | PHP_JSON_ERROR_STATE_MISMATCH,
106 | PHP_JSON_ERROR_CTRL_CHAR,
107 | PHP_JSON_ERROR_SYNTAX,
108 | PHP_JSON_ERROR_UTF8,
109 | PHP_JSON_ERROR_RECURSION,
110 | PHP_JSON_ERROR_INF_OR_NAN,
111 | PHP_JSON_ERROR_UNSUPPORTED_TYPE,
112 | PHP_JSON_ERROR_INVALID_PROPERTY_NAME,
113 | PHP_JSON_ERROR_UTF16
114 | } php_json_error_code;
115 |
116 | /* json_encode() options */
117 | #define PHP_JSON_HEX_TAG (1<<0)
118 | #define PHP_JSON_HEX_AMP (1<<1)
119 | #define PHP_JSON_HEX_APOS (1<<2)
120 | #define PHP_JSON_HEX_QUOT (1<<3)
121 | #define PHP_JSON_FORCE_OBJECT (1<<4)
122 | #define PHP_JSON_NUMERIC_CHECK (1<<5)
123 | #define PHP_JSON_UNESCAPED_SLASHES (1<<6)
124 | #define PHP_JSON_PRETTY_PRINT (1<<7)
125 | #define PHP_JSON_UNESCAPED_UNICODE (1<<8)
126 | #define PHP_JSON_PARTIAL_OUTPUT_ON_ERROR (1<<9)
127 | #define PHP_JSON_PRESERVE_ZERO_FRACTION (1<<10)
128 | #define PHP_JSON_UNESCAPED_LINE_TERMINATORS (1<<11)
129 |
130 | /* Internal flags */
131 | #define PHP_JSON_OUTPUT_ARRAY 0
132 | #define PHP_JSON_OUTPUT_OBJECT 1
133 |
134 | /* json_decode() options */
135 | #define PHP_JSON_OBJECT_AS_ARRAY (1<<0)
136 | #define PHP_JSON_BIGINT_AS_STRING (1<<1)
137 |
138 | /* default depth */
139 | #define PHP_JSON_PARSER_DEFAULT_DEPTH 512
140 |
141 |
142 | ZEND_BEGIN_MODULE_GLOBALS(jsond)
143 | int encoder_depth;
144 | int encode_max_depth;
145 | php_json_error_code error_code;
146 | ZEND_END_MODULE_GLOBALS(jsond)
147 | PHP_JSOND_API ZEND_EXTERN_MODULE_GLOBALS(jsond)
148 |
149 | #define JSOND_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(jsond, v)
150 |
151 | #if defined(ZTS) && defined(COMPILE_DL_JSOND)
152 | ZEND_TSRMLS_CACHE_EXTERN();
153 | #endif
154 |
155 | #include "php_jsond_buffer.h"
156 |
157 | PHP_JSOND_API int PHP_JSOND_NAME(encode)(php_json_buffer *buf, zval *val, int options);
158 | PHP_JSOND_API int PHP_JSOND_NAME(decode_ex)(zval *return_value, char *str, size_t str_len, int options, int depth);
159 | extern PHP_JSOND_API zend_class_entry *PHP_JSOND_NAME(serializable_ce);
160 |
161 | static inline int PHP_JSOND_NAME(decode)(zval *return_value, char *str, size_t str_len, zend_bool assoc, int depth)
162 | {
163 | return PHP_JSOND_NAME(decode_ex)(return_value, str, str_len, assoc ? PHP_JSON_OBJECT_AS_ARRAY : 0, depth);
164 | }
165 |
166 | #endif /* PHP_JSOND_H */
167 |
168 |
169 | /*
170 | * Local variables:
171 | * tab-width: 4
172 | * c-basic-offset: 4
173 | * End:
174 | * vim600: noet sw=4 ts=4 fdm=marker
175 | * vim<600: noet sw=4 ts=4
176 | */
177 |
--------------------------------------------------------------------------------
/php_jsond_buffer.h:
--------------------------------------------------------------------------------
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: Jakub Zelenka |
14 | +----------------------------------------------------------------------+
15 | */
16 |
17 | #ifndef PHP_JSOND_BUFFER_H
18 | #define PHP_JSOND_BUFFER_H
19 |
20 | #include "php.h"
21 |
22 | #define PHP_JSON_NOOP ((void) 0)
23 |
24 | #ifdef PHP_JSOND_BUF_TYPE_NATIVE
25 |
26 | /* static buffer size */
27 | #define PHP_JSON_BUFFER_STATIC_SIZE 2048
28 | /* size of extra allocation when extending buffer */
29 | #define PHP_JSON_BUFFER_EXTRA_ALLOC_SIZE 0
30 |
31 | /* flags */
32 | #define PHP_JSON_BUFFER_FLAG_MARK_DBUF 1
33 |
34 | typedef struct _php_json_buffer{
35 | char sbuf[PHP_JSON_BUFFER_STATIC_SIZE];
36 | char *dbuf;
37 | char *ptr;
38 | char *end;
39 | char *mark;
40 | size_t dsize;
41 | int flags;
42 | } php_json_buffer;
43 |
44 | void php_json_buffer_init(php_json_buffer *buf);
45 | void php_json_buffer_destroy(php_json_buffer *buf);
46 | void php_json_buffer_flush(php_json_buffer *buf, size_t pre_alloc_size);
47 | void php_json_buffer_finish(php_json_buffer *buf);
48 | void php_json_buffer_alloc(php_json_buffer *buf, size_t len);
49 | void php_json_buffer_reset(php_json_buffer *buf);
50 |
51 | static inline void php_json_buffer_append_stringl(php_json_buffer *buf, const char *str, size_t len)
52 | {
53 | char *new_ptr = buf->ptr + len;
54 | if (new_ptr <= buf->end) {
55 | memcpy(buf->ptr, str, len);
56 | buf->ptr = new_ptr;
57 | } else {
58 | php_json_buffer_flush(buf, len + PHP_JSON_BUFFER_EXTRA_ALLOC_SIZE);
59 | memcpy(buf->dbuf + buf->dsize, str, len);
60 | buf->dsize += len;
61 | }
62 | }
63 |
64 | static inline void php_json_buffer_append_char(php_json_buffer *buf, char c) /* {{{ */
65 | {
66 | if (buf->ptr > buf->end) {
67 | php_json_buffer_flush(buf, PHP_JSON_BUFFER_EXTRA_ALLOC_SIZE);
68 | }
69 | *buf->ptr = c;
70 | buf->ptr++;
71 | }
72 | /* }}} */
73 |
74 | #define PHP_JSON_INT_BUFFER_SIZE 32
75 |
76 | static inline void php_json_buffer_append_long(php_json_buffer *buf, long l) /* {{{ */
77 | {
78 | char str[PHP_JSON_INT_BUFFER_SIZE];
79 | char *p = &str[PHP_JSON_INT_BUFFER_SIZE];
80 | zend_bool negative;
81 |
82 | if (l < 0) {
83 | negative = 1;
84 | l = -l;
85 | } else {
86 | negative = 0;
87 | }
88 |
89 | do {
90 | *--p = (char) (l % 10) + '0';
91 | l /= 10;
92 | } while (l > 0);
93 |
94 | if (negative) {
95 | *--p = '-';
96 | }
97 |
98 | php_json_buffer_append_stringl(buf, p, &str[PHP_JSON_INT_BUFFER_SIZE] - p);
99 | }
100 | /* }}} */
101 |
102 | static inline char *php_json_buffer_block_open(php_json_buffer *buf, size_t len) /* {{{ */
103 | {
104 | if (buf->ptr + len > buf->end) {
105 | php_json_buffer_flush(buf, PHP_JSON_BUFFER_EXTRA_ALLOC_SIZE);
106 | }
107 | return buf->ptr;
108 | }
109 | /* }}} */
110 |
111 | static inline void php_json_buffer_block_close(php_json_buffer *buf, size_t len) /* {{{ */
112 | {
113 | buf->ptr += len;
114 | }
115 | /* }}} */
116 |
117 | static inline void php_json_buffer_mark_set(php_json_buffer *buf) /* {{{ */
118 | {
119 | buf->mark = buf->ptr;
120 | }
121 | /* }}} */
122 |
123 | static inline void php_json_buffer_mark_del(php_json_buffer *buf) /* {{{ */
124 | {
125 | buf->mark = NULL;
126 | buf->flags &= ~PHP_JSON_BUFFER_FLAG_MARK_DBUF;
127 | }
128 | /* }}} */
129 |
130 | #define PHP_JSON_BUFFER_STRVAL(_buf) (_buf).dbuf
131 | #define PHP_JSON_BUFFER_STRLEN(_buf) (_buf).dsize
132 |
133 | #define PHP_JSON_BUF_INIT(_buf) \
134 | php_json_buffer_init(_buf)
135 |
136 | #define PHP_JSON_BUF_DESTROY(_buf) \
137 | php_json_buffer_destroy(_buf)
138 |
139 | #define PHP_JSON_BUF_FINISH(_buf) \
140 | php_json_buffer_finish(_buf)
141 |
142 | #define PHP_JSON_BUF_FLUSH(_buf, _pre_alloc_size) \
143 | php_json_buffer_flush(_buf, _pre_alloc_size)
144 |
145 | #define PHP_JSON_BUF_ALLOC(_buf, _len) \
146 | php_json_buffer_alloc(_buf, _len)
147 |
148 | #define PHP_JSON_BUF_APPEND_STRING(_buf, _str, _len) \
149 | php_json_buffer_append_stringl(_buf, _str, _len)
150 |
151 | #define PHP_JSON_BUF_APPEND_CHAR(_buf, _c) \
152 | php_json_buffer_append_char(_buf, _c)
153 |
154 | #define PHP_JSON_BUF_APPEND_LONG(_buf, _l) \
155 | php_json_buffer_append_long(_buf, _l)
156 |
157 | #define PHP_JSON_BUF_DOUBLE_BLOCK_INIT(_buf, _dst, _max_len) \
158 | char *_dst = php_json_buffer_block_open(\
159 | _buf, MIN(PG(serialize_precision) + MAX_LENGTH_OF_DOUBLE, _max_len) + 1)
160 |
161 | #define PHP_JSON_BUF_DOUBLE_BLOCK_CLOSE(_buf, _dst, _len) \
162 | php_json_buffer_block_close(_buf, _len)
163 |
164 | #define PHP_JSON_BUF_MARK_DECLARE(_buf) \
165 | PHP_JSON_NOOP
166 |
167 | #define PHP_JSON_BUF_MARK_SET(_buf) \
168 | php_json_buffer_mark_set(_buf)
169 |
170 | #define PHP_JSON_BUF_MARK_DELETE(_buf) \
171 | php_json_buffer_mark_del(_buf)
172 |
173 | #define PHP_JSON_BUF_RESET(_buf) \
174 | php_json_buffer_reset(_buf)
175 |
176 | #define PHP_JSON_BUF_LENGTH PHP_JSON_BUFFER_STRLEN
177 |
178 | #define PHP_JSON_BUF_RETURN(_buf_s, return_value) do { \
179 | PHP_JSON_BUF_FINISH(&_buf_s); \
180 | RETVAL_STRINGL(PHP_JSON_BUFFER_STRVAL(_buf_s), (int) PHP_JSON_BUFFER_STRLEN(_buf_s)); \
181 | PHP_JSON_BUF_DESTROY(&_buf_s); \
182 | } while(0)
183 |
184 |
185 | #else
186 |
187 | #include "zend_smart_string.h"
188 |
189 | #define php_json_buffer smart_string
190 |
191 | #define PHP_JSON_BUF_INIT(_buf) \
192 | memset(_buf, 0, sizeof(smart_string))
193 |
194 | #define PHP_JSON_BUF_DESTROY(_buf) \
195 | smart_string_free(_buf);
196 |
197 | #define PHP_JSON_BUF_FLUSH(_buf, _pre_alloc_size)
198 |
199 | #define PHP_JSON_BUF_FINISH(_buf)
200 |
201 | #define PHP_JSON_BUF_ALLOC(_buf, _len) \
202 | smart_string_alloc(_buf, _len+2, 0)
203 |
204 | #define PHP_JSON_BUF_APPEND_STRING(_buf, _str, _len) \
205 | smart_string_appendl(_buf, _str, _len)
206 |
207 | #define PHP_JSON_BUF_APPEND_CHAR(_buf, _c) \
208 | smart_string_appendc(_buf, _c)
209 |
210 | #define PHP_JSON_BUF_APPEND_LONG(_buf, _l) \
211 | smart_string_append_long(_buf, _l)
212 |
213 | #define PHP_JSON_BUF_DOUBLE_BLOCK_INIT(_buf, _dst, _max_len) \
214 | char _dst[_max_len]
215 |
216 | #define PHP_JSON_BUF_DOUBLE_BLOCK_CLOSE(_buf, _dst, _len) \
217 | smart_string_appendl(_buf, _dst, _len);
218 |
219 | #define _PHP_JSON_BUF_MARK_NAME(_buf) _buf##__oldlen
220 |
221 | #define PHP_JSON_BUF_MARK_DECLARE(_buf) \
222 | size_t _PHP_JSON_BUF_MARK_NAME(_buf), newlen
223 |
224 | #define PHP_JSON_BUF_MARK_SET(_buf) \
225 | _PHP_JSON_BUF_MARK_NAME(_buf) = _buf->len
226 |
227 | #define PHP_JSON_BUF_MARK_DELETE(_buf) \
228 | PHP_JSON_NOOP
229 |
230 | #define PHP_JSON_BUF_RESET(_buf) \
231 | buf->len = _PHP_JSON_BUF_MARK_NAME(_buf)
232 |
233 | #define PHP_JSON_BUF_LENGTH(_buf_s) _buf_s.len
234 |
235 | #define PHP_JSON_BUF_RETURN(_buf_s, return_value) do { \
236 | if (_buf_s.c) { \
237 | RETVAL_STRINGL(_buf_s.c, _buf_s.len); \
238 | } else { \
239 | RETVAL_EMPTY_STRING(); \
240 | } \
241 | PHP_JSON_BUF_DESTROY(&_buf_s); \
242 | } while(0)
243 |
244 | #endif /* PHP_JSON_BUF_TYPE_NATIVE */
245 |
246 | #endif /* PHP_JSOND_BUFFER_H */
247 |
--------------------------------------------------------------------------------
/php_jsond_compat.h:
--------------------------------------------------------------------------------
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: Jakub Zelenka |
14 | +----------------------------------------------------------------------+
15 | */
16 |
17 | /* The compatibility changes to support at least PHP 7.2 */
18 |
19 | #ifndef PHP_JSOND_COMPAT_H
20 | #define PHP_JSOND_COMPAT_H
21 |
22 | /* Recursion protection changes */
23 | #if PHP_VERSION_ID < 70300
24 | #define PHP_JSON_HAS_APPLY_COUNT(_tht) (ZEND_HASH_GET_APPLY_COUNT(_tht) > 0)
25 | #define PHP_JSON_GET_APPLY_COUNT ZEND_HASH_GET_APPLY_COUNT
26 | #define PHP_JSON_INC_APPLY_COUNT ZEND_HASH_INC_APPLY_COUNT
27 | #define PHP_JSON_DEC_APPLY_COUNT ZEND_HASH_DEC_APPLY_COUNT
28 | #define PHP_JSON_APPLY_PROTECTION ZEND_HASH_APPLY_PROTECTION
29 | #else
30 | #define PHP_JSON_HAS_APPLY_COUNT GC_IS_RECURSIVE
31 | #define PHP_JSON_GET_APPLY_COUNT GC_IS_RECURSIVE
32 | #define PHP_JSON_INC_APPLY_COUNT GC_PROTECT_RECURSION
33 | #define PHP_JSON_DEC_APPLY_COUNT GC_UNPROTECT_RECURSION
34 | #define PHP_JSON_APPLY_PROTECTION(_tht) (!(GC_FLAGS(_tht) & GC_IMMUTABLE))
35 | #endif
36 |
37 | /* zend_string_release_ex introduction */
38 | #if PHP_VERSION_ID < 70300
39 | #define PHP_JSOND_RELEASE_STRING zend_string_release
40 | #else
41 | #define PHP_JSOND_RELEASE_STRING(_str) zend_string_release_ex(_str, 0)
42 | #endif
43 |
44 | /* zend_std_write_property changes */
45 | #if PHP_VERSION_ID < 80000
46 | #define PHP_JSOND_WRITE_PROPERTY(_object, _key, _value) \
47 | do { \
48 | zval _zkey; \
49 | ZVAL_NEW_STR(&_zkey, _key); \
50 | zend_std_write_property(_object, &_zkey, _value, NULL); \
51 | } while(0)
52 |
53 | #else
54 | #define PHP_JSOND_WRITE_PROPERTY(_object, _key, _value) \
55 | zend_std_write_property(Z_OBJ_P(_object), _key, _value, NULL)
56 | #endif
57 |
58 | /* zend_dtoa sign type */
59 | #if PHP_VERSION_ID < 80100
60 | typedef int php_jsond_dtoa_sign_t;
61 | #else
62 | typedef bool php_jsond_dtoa_sign_t;
63 | #endif
64 |
65 | #endif /* PHP_JSOND_COMPAT_H */
--------------------------------------------------------------------------------
/php_jsond_dtoa.h:
--------------------------------------------------------------------------------
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: Jakub Zelenka |
14 | +----------------------------------------------------------------------+
15 | */
16 |
17 | #ifndef PHP_JSOND_DTOA_H
18 | #define PHP_JSOND_DTOA_H
19 |
20 | char *php_jsond_gcvt(double value, int ndigit, char dec_point, char exponent, char *buf);
21 |
22 | #endif /* PHP_JSOND_DTOA_H */
23 |
--------------------------------------------------------------------------------
/php_jsond_encoder.h:
--------------------------------------------------------------------------------
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: Jakub Zelenka |
14 | +----------------------------------------------------------------------+
15 | */
16 |
17 | #ifndef PHP_JSOND_ENCODER_H
18 | #define PHP_JSOND_ENCODER_H
19 |
20 | #include "php.h"
21 | #include "php_jsond_buffer.h"
22 |
23 | typedef struct _php_json_encoder php_json_encoder;
24 |
25 | struct _php_json_encoder {
26 | int depth;
27 | int max_depth;
28 | php_json_error_code error_code;
29 | };
30 |
31 | static inline void php_json_encode_init(php_json_encoder *encoder)
32 | {
33 | memset(encoder, 0, sizeof(php_json_encoder));
34 | }
35 |
36 | int php_json_encode_zval(php_json_buffer *buf, zval *val, int options, php_json_encoder *encoder);
37 |
38 | #endif /* PHP_JSOND_ENCODER_H */
39 |
40 |
--------------------------------------------------------------------------------
/php_jsond_parser.h:
--------------------------------------------------------------------------------
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: Jakub Zelenka |
14 | +----------------------------------------------------------------------+
15 | */
16 |
17 | #ifndef PHP_JSOND_PARSER_H
18 | #define PHP_JSOND_PARSER_H
19 |
20 | #include "php.h"
21 | #include "php_jsond_scanner.h"
22 |
23 | typedef struct _php_json_parser php_json_parser;
24 |
25 | typedef int (*php_json_parser_func_array_create_t)(
26 | php_json_parser *parser, zval *array);
27 | typedef int (*php_json_parser_func_array_append_t)(
28 | php_json_parser *parser, zval *array, zval *zvalue);
29 | typedef int (*php_json_parser_func_array_start_t)(
30 | php_json_parser *parser);
31 | typedef int (*php_json_parser_func_array_end_t)(
32 | php_json_parser *parser, zval *object);
33 | typedef int (*php_json_parser_func_object_create_t)(
34 | php_json_parser *parser, zval *object);
35 | typedef int (*php_json_parser_func_object_update_t)(
36 | php_json_parser *parser, zval *object, zend_string *key, zval *zvalue);
37 | typedef int (*php_json_parser_func_object_start_t)(
38 | php_json_parser *parser);
39 | typedef int (*php_json_parser_func_object_end_t)(
40 | php_json_parser *parser, zval *object);
41 |
42 | typedef struct _php_json_parser_methods {
43 | php_json_parser_func_array_create_t array_create;
44 | php_json_parser_func_array_append_t array_append;
45 | php_json_parser_func_array_start_t array_start;
46 | php_json_parser_func_array_end_t array_end;
47 | php_json_parser_func_object_create_t object_create;
48 | php_json_parser_func_object_update_t object_update;
49 | php_json_parser_func_object_start_t object_start;
50 | php_json_parser_func_object_end_t object_end;
51 | } php_json_parser_methods;
52 |
53 | struct _php_json_parser {
54 | php_json_scanner scanner;
55 | zval *return_value;
56 | int depth;
57 | int max_depth;
58 | php_json_parser_methods methods;
59 | };
60 |
61 | PHP_JSOND_API void PHP_JSOND_NAME(parser_init_ex)(
62 | php_json_parser *parser,
63 | zval *return_value,
64 | char *str,
65 | size_t str_len,
66 | int options,
67 | int max_depth,
68 | const php_json_parser_methods *methods);
69 |
70 | PHP_JSOND_API void PHP_JSOND_NAME(parser_init)(
71 | php_json_parser *parser,
72 | zval *return_value,
73 | char *str,
74 | size_t str_len,
75 | int options,
76 | int max_depth);
77 |
78 | PHP_JSOND_API php_json_error_code PHP_JSOND_NAME(parser_error_code)(const php_json_parser *parser);
79 |
80 | PHP_JSOND_API int PHP_JSOND_NAME(parse)(php_json_parser *parser);
81 |
82 | int php_json_yyparse(php_json_parser *parser);
83 |
84 | #endif /* PHP_JSOND_PARSER_H */
85 |
86 |
--------------------------------------------------------------------------------
/php_jsond_scanner.h:
--------------------------------------------------------------------------------
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: Jakub Zelenka |
14 | +----------------------------------------------------------------------+
15 | */
16 |
17 | #ifndef PHP_JSOND_SCANNER_H
18 | #define PHP_JSOND_SCANNER_H
19 |
20 | #include "php.h"
21 | #include "php_jsond.h"
22 |
23 | typedef unsigned char php_json_ctype;
24 |
25 | typedef struct _php_json_scanner {
26 | php_json_ctype *cursor; /* cursor position */
27 | php_json_ctype *token; /* token position */
28 | php_json_ctype *limit; /* the last read character + 1 position */
29 | php_json_ctype *marker; /* marker position for backtracking */
30 | php_json_ctype *ctxmarker; /* marker position for context backtracking */
31 | php_json_ctype *str_start; /* start position of the string */
32 | php_json_ctype *pstr; /* string pointer for escapes conversion */
33 | int str_esc; /* number of extra characters for escaping */
34 | int state; /* condition state */
35 | zval value; /* value */
36 | int options; /* options */
37 | php_json_error_code errcode; /* error type if there is an error */
38 | } php_json_scanner;
39 |
40 |
41 | void php_json_scanner_init(
42 | php_json_scanner *scanner, char *str, size_t str_len, int options);
43 |
44 | int php_json_scan(php_json_scanner *s);
45 |
46 | #endif /* PHP_JSOND_SCANNER_H */
47 |
48 |
--------------------------------------------------------------------------------
/php_jsond_scanner_defs.h:
--------------------------------------------------------------------------------
1 | /* Generated by re2c 1.3 */
2 |
3 | enum YYCONDTYPE {
4 | yycJS,
5 | yycSTR_P1,
6 | yycSTR_P2,
7 | };
8 |
--------------------------------------------------------------------------------
/php_jsond_utf8_decoder.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2008-2009 Bjoern Hoehrmann
3 | *
4 | * Permission is hereby granted, free of charge, to any person
5 | * obtaining a copy of this software and associated
6 | * documentation files (the "Software"), to deal in the Software
7 | * without restriction, including without limitation the rights to use,
8 | * copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | * copies of the Software, and to permit persons to whom the Software
10 | * is furnished to do so, subject to the following conditions:
11 | *
12 | * The above copyright notice and this permission notice shall be
13 | * included in all copies or substantial portions of the Software.
14 | *
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
22 | * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 | */
24 |
25 | #ifndef PHP_JSOND_UTF8_DECODER_H
26 | #define PHP_JSOND_UTF8_DECODER_H
27 |
28 | #define PHP_JSON_UTF8_ACCEPT 0
29 | #define PHP_JSON_UTF8_REJECT 12
30 |
31 | const char php_json_utf8d[] = {
32 | /* The first part of the table maps bytes to character classes that
33 | * to reduce the size of the transition table and create bitmasks. */
34 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
35 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
36 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
37 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
38 | 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
39 | 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
40 | 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
41 | 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
42 |
43 | /* The second part is a transition table that maps a combination
44 | * of a state of the automaton and a character class to a state. */
45 | 0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12,
46 | 12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12,
47 | 12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12,
48 | 12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12,
49 | 12,36,12,12,12,12,12,12,12,12,12,12
50 | };
51 |
52 | php_json_always_inline int php_json_utf8_decode(int* state, int* codep, unsigned int byte)
53 | {
54 | int type = php_json_utf8d[byte];
55 |
56 | *codep = (*state != PHP_JSON_UTF8_ACCEPT) ?
57 | (byte & 0x3fu) | (*codep << 6) : (0xff >> type) & (byte);
58 |
59 | *state = php_json_utf8d[256 + *state + type];
60 | return *state;
61 | }
62 |
63 | #endif /* PHP_JSOND_UTF8_DECODER_H */
64 |
--------------------------------------------------------------------------------
/tests/001.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | json_decode() tests
3 | --SKIPIF--
4 |
5 | --FILE--
6 | "));
20 | var_dump($jsond_decode(";"));
21 | var_dump($jsond_decode("руссиш"));
22 | var_dump($jsond_decode("blah"));
23 | var_dump($jsond_decode("NULL"));
24 | var_dump($jsond_decode('{ "test": { "foo": "bar" } }'));
25 | var_dump($jsond_decode('{ "test": { "foo": "" } }'));
26 | var_dump($jsond_decode('{ "": { "foo": "" } }'));
27 | var_dump($jsond_decode('{ "": { "": "" } }'));
28 | var_dump($jsond_decode('{ "": { "": "" }'));
29 | var_dump($jsond_decode('{ "": "": "" } }'));
30 |
31 | ?>
32 | ===DONE===
33 | --EXPECTF--
34 | Warning: %s() expects at least 1 parameter, 0 given in %s on line %d
35 | NULL
36 | NULL
37 | NULL
38 | NULL
39 | NULL
40 | NULL
41 | NULL
42 | NULL
43 | NULL
44 | NULL
45 | NULL
46 | object(stdClass)#%d (1) {
47 | ["test"]=>
48 | object(stdClass)#%d (1) {
49 | ["foo"]=>
50 | string(3) "bar"
51 | }
52 | }
53 | object(stdClass)#%d (1) {
54 | ["test"]=>
55 | object(stdClass)#%d (1) {
56 | ["foo"]=>
57 | string(0) ""
58 | }
59 | }
60 | object(stdClass)#%d (1) {
61 | [""]=>
62 | object(stdClass)#%d (1) {
63 | ["foo"]=>
64 | string(0) ""
65 | }
66 | }
67 | object(stdClass)#%d (1) {
68 | [""]=>
69 | object(stdClass)#%d (1) {
70 | [""]=>
71 | string(0) ""
72 | }
73 | }
74 | NULL
75 | NULL
76 | ===DONE===
77 |
--------------------------------------------------------------------------------
/tests/002.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | json_encode() tests
3 | --SKIPIF--
4 |
5 | --FILE--
6 | "")));
14 | var_dump($jsond_encode(array(array(1))));
15 | var_dump($jsond_encode(array()));
16 |
17 | var_dump($jsond_encode(array(""=>""), jsond_constant('FORCE_OBJECT')));
18 | var_dump($jsond_encode(array(array(1)), jsond_constant('FORCE_OBJECT')));
19 | var_dump($jsond_encode(array(), jsond_constant('FORCE_OBJECT')));
20 |
21 | var_dump($jsond_encode(1));
22 | var_dump($jsond_encode("руссиш"));
23 |
24 |
25 | echo "Done\n";
26 | ?>
27 | --EXPECTF--
28 | string(2) """"
29 | string(4) "null"
30 | string(4) "true"
31 | string(7) "{"":""}"
32 | string(5) "[[1]]"
33 | string(2) "[]"
34 | string(7) "{"":""}"
35 | string(13) "{"0":{"0":1}}"
36 | string(2) "{}"
37 | string(1) "1"
38 | string(38) ""\u0440\u0443\u0441\u0441\u0438\u0448""
39 | Done
40 |
--------------------------------------------------------------------------------
/tests/003.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | json_encode() & endless loop - 1
3 | --SKIPIF--
4 |
8 | --FILE--
9 |
31 | --EXPECTF--
32 | Array
33 | (
34 | [0] => Array
35 | *RECURSION*
36 | )
37 |
38 | bool(false)
39 | int(6)
40 | string(%d) "Recursion detected"
41 |
42 | bool(true)
43 | int(6)
44 | string(%d) "Recursion detected"
45 | Done
46 |
--------------------------------------------------------------------------------
/tests/004.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | json_encode() & endless loop - 2
3 | --SKIPIF--
4 |
8 | --FILE--
9 | prop = $a;
14 |
15 | var_dump($a);
16 |
17 | echo "\n";
18 |
19 | var_dump($jsond_encode($a));
20 | var_dump($jsond_last_error(), $jsond_last_error_msg());
21 |
22 | echo "\n";
23 |
24 | var_dump($jsond_encode($a, jsond_constant('PARTIAL_OUTPUT_ON_ERROR')));
25 | var_dump($jsond_last_error(), $jsond_last_error_msg());
26 |
27 | echo "Done\n";
28 | ?>
29 | --EXPECTF--
30 | object(stdClass)#%d (1) {
31 | ["prop"]=>
32 | *RECURSION*
33 | }
34 |
35 | bool(false)
36 | int(6)
37 | string(%d) "Recursion detected"
38 |
39 | string(13) "{"prop":null}"
40 | int(6)
41 | string(%d) "Recursion detected"
42 | Done
43 |
--------------------------------------------------------------------------------
/tests/005.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | json_encode() & endless loop - 3
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
17 | --EXPECTF--
18 | array(1) {
19 | [0]=>
20 | array(0) {
21 | }
22 | }
23 | string(4) "[[]]"
24 | Done
25 |
--------------------------------------------------------------------------------
/tests/006.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | json_encode() & extended encoding
3 | --SKIPIF--
4 |
5 | --FILE--
6 | ',"'bar'",'"baz"','&blong&');
10 |
11 | echo "Normal: ", $jsond_encode($a), "\n";
12 | echo "Tags: ", $jsond_encode($a, jsond_constant('HEX_TAG')), "\n";
13 | echo "Apos: ", $jsond_encode($a, jsond_constant('HEX_APOS')), "\n";
14 | echo "Quot: ", $jsond_encode($a, jsond_constant('HEX_QUOT')), "\n";
15 | echo "Amp: ", $jsond_encode($a, jsond_constant('HEX_AMP')), "\n";
16 | echo "All: ", $jsond_encode($a, jsond_constant('HEX_TAG', 'HEX_APOS', 'HEX_QUOT', 'HEX_AMP')), "\n";
17 | ?>
18 | --EXPECT--
19 | Normal: ["","'bar'","\"baz\"","&blong&"]
20 | Tags: ["\u003Cfoo\u003E","'bar'","\"baz\"","&blong&"]
21 | Apos: ["","\u0027bar\u0027","\"baz\"","&blong&"]
22 | Quot: ["","'bar'","\u0022baz\u0022","&blong&"]
23 | Amp: ["","'bar'","\"baz\"","\u0026blong\u0026"]
24 | All: ["\u003Cfoo\u003E","\u0027bar\u0027","\u0022baz\u0022","\u0026blong\u0026"]
25 |
--------------------------------------------------------------------------------
/tests/007.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | json_last_error() tests
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
22 | --EXPECT--
23 | array(1) {
24 | [0]=>
25 | int(1)
26 | }
27 | int(0)
28 | string(8) "No error"
29 | NULL
30 | int(1)
31 | string(28) "Maximum stack depth exceeded"
32 | NULL
33 | int(2)
34 | string(42) "State mismatch (invalid or malformed JSON)"
35 | NULL
36 | int(3)
37 | string(53) "Control character error, possibly incorrectly encoded"
38 | NULL
39 | int(4)
40 | string(12) "Syntax error"
41 | Done
42 |
--------------------------------------------------------------------------------
/tests/008.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | json_decode() with large integers
3 | --INI--
4 | serialize_precision=14
5 | --SKIPIF--
6 |
7 | --FILE--
8 | largenum);
14 | $x = $jsond_decode($jsond, false, 512, jsond_constant('BIGINT_AS_STRING'));
15 | var_dump($x->largenum);
16 | echo "Done\n";
17 | ?>
18 | --EXPECT--
19 | float(1.2345678901235E+29)
20 | string(30) "123456789012345678901234567890"
21 | Done
22 |
--------------------------------------------------------------------------------
/tests/bootstrap.inc:
--------------------------------------------------------------------------------
1 | getMessage(), $expected_message_prefix) === false) {
28 | echo "ERROR: " . $exception->getMessage() . "\n";
29 | } else {
30 | echo "\n" . $warning . "\n";
31 | var_dump(NULL);
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/tests/bug40503.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Bug #40503 (json_encode() value corruption on 32bit systems with overflown values)
3 | --INI--
4 | serialize_precision=14
5 | --SKIPIF--
6 |
7 | --FILE--
8 |
21 | --EXPECT--
22 | 2147483647 == 2147483647
23 | 2147483648 == 2147483648
24 |
--------------------------------------------------------------------------------
/tests/bug41034.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Bug #41034 (json_encode() ignores null byte started keys in arrays)
3 | --SKIPIF--
4 |
5 | --FILE--
6 | 1,"\0null-prefixed value"));
10 | echo "\nDone\n";
11 | ?>
12 | --EXPECT--
13 | {"0":0,"\u0000ab":1,"1":"\u0000null-prefixed value"}
14 | Done
15 |
--------------------------------------------------------------------------------
/tests/bug41067.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Bug #41067 (json_encode() problem with UTF-16 input)
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
20 | --EXPECT--
21 | f09d8480
22 | ["\ud834\udd00"]
23 |
24 | f09d8480
25 | END
26 |
--------------------------------------------------------------------------------
/tests/bug41403.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Bug #41403 (json_decode cannot decode floats if localeconv decimal_point is not '.')
3 | --SKIPIF--
4 |
15 | --INI--
16 | serialize_precision=14
17 | --FILE--
18 |
35 | --EXPECTF--
36 | array(1) {
37 | [0]=>
38 | float(2.1)
39 | }
40 | array(1) {
41 | [0]=>
42 | float(0.15)
43 | }
44 | array(1) {
45 | [0]=>
46 | float(123.13452345)
47 | }
48 | array(2) {
49 | [0]=>
50 | int(123)
51 | [1]=>
52 | int(13452345)
53 | }
54 | Done
55 |
--------------------------------------------------------------------------------
/tests/bug41504.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Bug #41504 (json_decode() converts empty array keys to "_empty_")
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
15 | --EXPECT--
16 | array(1) {
17 | [""]=>
18 | string(5) "value"
19 | }
20 | array(2) {
21 | [""]=>
22 | string(5) "value"
23 | ["key"]=>
24 | string(5) "value"
25 | }
26 | array(2) {
27 | ["key"]=>
28 | string(5) "value"
29 | [""]=>
30 | string(5) "value"
31 | }
32 | Done
33 |
--------------------------------------------------------------------------------
/tests/bug41567.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Bug #41567 (json_encode() double conversion is inconsistent with PHP)
3 | --INI--
4 | serialize_precision=14
5 | --SKIPIF--
6 |
7 | --FILE--
8 |
16 | --EXPECT--
17 | float(123456789.12345)
18 | Done
19 |
--------------------------------------------------------------------------------
/tests/bug42090.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Bug #42090 (json_decode causes segmentation fault)
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
19 | --EXPECT--
20 | string(0) ""
21 | NULL
22 | NULL
23 | NULL
24 | string(4) ""\"""
25 | string(1) """
26 | string(2) """"
27 |
--------------------------------------------------------------------------------
/tests/bug42785.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Bug #42785 (Incorrect formatting of double values with non-english locales)
3 | --INI--
4 | serialize_precision=-1
5 | --SKIPIF--
6 |
13 | --FILE--
14 | a = 100.10;
28 | $bar1->b = "foo";
29 | var_dump($jsond_encode($bar1));
30 | ?>
31 | --EXPECT--
32 | string(13) "[100.1,"bar"]"
33 | string(21) "{"a":100.1,"b":"foo"}"
34 |
--------------------------------------------------------------------------------
/tests/bug43941.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Bug #43941 (json_encode() invalid UTF-8)
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
18 | --EXPECTF--
19 | string(5) ""abc""
20 | bool(false)
21 | string(4) "null"
22 | string(17) "[null,null,"abc"]"
23 | Done
24 |
--------------------------------------------------------------------------------
/tests/bug45791.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Bug #45791 (json_decode() does not handle number 0e0)
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
12 | --EXPECT--
13 | object(stdClass)#1 (1) {
14 | ["zero"]=>
15 | float(0)
16 | }
17 |
--------------------------------------------------------------------------------
/tests/bug46215.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Bug #46215 (json_encode mutates its parameter and has some class-specific state)
3 | --SKIPIF--
4 |
9 | --FILE--
10 |
23 | --EXPECT--
24 | foo Object
25 | (
26 | [a:protected] => Array
27 | (
28 | )
29 |
30 | )
31 |
--------------------------------------------------------------------------------
/tests/bug46944.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Bug #46944 (json_encode() doesn't handle 3 byte utf8 correctly)
3 | --SKIPIF--
4 |
5 | --FILE--
6 | > 2);
11 | $second = 0x8f|($i & 3) << 4;
12 | $string = sprintf("aa%c%c\xbf\xbdzz", $first, $second);
13 | echo $jsond_encode($string) . "\n";
14 | }
15 |
16 |
17 | echo "Done\n";
18 | ?>
19 | --EXPECT--
20 | "aa\ud83f\udffdzz"
21 | "aa\ud87f\udffdzz"
22 | "aa\ud8bf\udffdzz"
23 | "aa\ud8ff\udffdzz"
24 | "aa\ud93f\udffdzz"
25 | "aa\ud97f\udffdzz"
26 | "aa\ud9bf\udffdzz"
27 | "aa\ud9ff\udffdzz"
28 | "aa\uda3f\udffdzz"
29 | "aa\uda7f\udffdzz"
30 | "aa\udabf\udffdzz"
31 | "aa\udaff\udffdzz"
32 | "aa\udb3f\udffdzz"
33 | "aa\udb7f\udffdzz"
34 | "aa\udbbf\udffdzz"
35 | "aa\udbff\udffdzz"
36 | Done
37 |
--------------------------------------------------------------------------------
/tests/bug47644.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Bug #47644 (valid large integers are truncated)
3 | --SKIPIF--
4 |
8 | --FILE--
9 |
18 | --EXPECT--
19 | array(1) {
20 | [0]=>
21 | int(10000000000000000)
22 | }
23 | array(1) {
24 | [0]=>
25 | int(10000000000000001)
26 | }
27 | array(1) {
28 | [0]=>
29 | int(10000000000000002)
30 | }
31 | array(1) {
32 | [0]=>
33 | int(10000000000000003)
34 | }
35 | array(1) {
36 | [0]=>
37 | int(10000000000000004)
38 | }
39 | array(1) {
40 | [0]=>
41 | int(10000000000000005)
42 | }
43 | Done
44 |
--------------------------------------------------------------------------------
/tests/bug50224.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | bug #50224 (json_encode() does not always encode a float as a float)
3 | --SKIPIF--
4 |
5 | --FILE--
6 | 12.0, 'integer' => 12),
16 | jsond_constant('PRESERVE_ZERO_FRACTION')));
17 |
18 | echo "\n* Testing encode/decode symmetry\n\n";
19 |
20 | var_dump($jsond_decode($jsond_encode(12.3, jsond_constant('PRESERVE_ZERO_FRACTION'))));
21 | var_dump($jsond_decode($jsond_encode(12, jsond_constant('PRESERVE_ZERO_FRACTION'))));
22 | var_dump($jsond_decode($jsond_encode(12.0, jsond_constant('PRESERVE_ZERO_FRACTION'))));
23 | var_dump($jsond_decode($jsond_encode(0.0, jsond_constant('PRESERVE_ZERO_FRACTION'))));
24 | var_dump($jsond_decode($jsond_encode(array(12, 12.0, 12.3),
25 | jsond_constant('PRESERVE_ZERO_FRACTION'))));
26 | var_dump($jsond_decode($jsond_encode((object)array('float' => 12.0, 'integer' => 12),
27 | jsond_constant('PRESERVE_ZERO_FRACTION'))));
28 | var_dump($jsond_decode($jsond_encode((object)array('float' => 12.0, 'integer' => 12),
29 | jsond_constant('PRESERVE_ZERO_FRACTION')), true));
30 | ?>
31 | --EXPECTF--
32 | * Testing JSON output
33 |
34 | string(4) "12.3"
35 | string(2) "12"
36 | string(4) "12.0"
37 | string(3) "0.0"
38 | string(14) "[12,12.0,12.3]"
39 | string(27) "{"float":12.0,"integer":12}"
40 |
41 | * Testing encode/decode symmetry
42 |
43 | float(12.3)
44 | int(12)
45 | float(12)
46 | float(0)
47 | array(3) {
48 | [0]=>
49 | int(12)
50 | [1]=>
51 | float(12)
52 | [2]=>
53 | float(12.3)
54 | }
55 | object(stdClass)#%d (2) {
56 | ["float"]=>
57 | float(12)
58 | ["integer"]=>
59 | int(12)
60 | }
61 | array(2) {
62 | ["float"]=>
63 | float(12)
64 | ["integer"]=>
65 | int(12)
66 | }
67 |
--------------------------------------------------------------------------------
/tests/bug53946.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | bug #53946 (json_encode() with JSOND_UNESCAPED_UNICODE)
3 | --SKIPIF--
4 |
5 | --FILE--
6 | 𝄞<"));
11 | var_dump($jsond_encode(
12 | "latin 1234 -/ russian мама мыла раму specialchars \x02 \x08 \n U+1D11E >𝄞<",
13 | jsond_constant('UNESCAPED_UNICODE')));
14 | var_dump($jsond_encode("ab\xE0"));
15 | var_dump($jsond_encode("ab\xE0", jsond_constant('UNESCAPED_UNICODE')));
16 | ?>
17 | --EXPECTF--
18 | string(156) ""latin 1234 -\/ russian \u043c\u0430\u043c\u0430 \u043c\u044b\u043b\u0430 \u0440\u0430\u043c\u0443 specialchars \u0002 \b \n U+1D11E >\ud834\udd1e<""
19 | string(100) ""latin 1234 -\/ russian мама мыла раму specialchars \u0002 \b \n U+1D11E >𝄞<""
20 | bool(false)
21 | bool(false)
22 |
--------------------------------------------------------------------------------
/tests/bug54058.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Bug #54058 (json_last_error() invalid UTF-8 produces wrong error)
3 | --SKIPIF--
4 |
5 | --FILE--
6 | foo = quoted_printable_decode('=B0');
16 | $jsond_encode($a);
17 | var_dump($jsond_last_error(), $jsond_last_error_msg());
18 |
19 | $b = new stdclass;
20 | $b->foo = $bad_utf8;
21 | $b->bar = 1;
22 | $jsond_encode($b);
23 | var_dump($jsond_last_error(), $jsond_last_error_msg());
24 |
25 | $c = array(
26 | 'foo' => $bad_utf8,
27 | 'bar' => 1
28 | );
29 | $jsond_encode($c);
30 | var_dump($jsond_last_error(), $jsond_last_error_msg());
31 |
32 | ?>
33 | --EXPECTF--
34 | int(5)
35 | string(56) "Malformed UTF-8 characters, possibly incorrectly encoded"
36 | int(5)
37 | string(56) "Malformed UTF-8 characters, possibly incorrectly encoded"
38 | int(5)
39 | string(56) "Malformed UTF-8 characters, possibly incorrectly encoded"
40 | int(5)
41 | string(56) "Malformed UTF-8 characters, possibly incorrectly encoded"
42 |
--------------------------------------------------------------------------------
/tests/bug54484.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Bug #54484 (Empty string in json_decode doesn't reset json_last_error)
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
27 | --EXPECT--
28 | int(0)
29 | int(4)
30 | int(4)
31 | int(3)
32 | int(4)
33 |
--------------------------------------------------------------------------------
/tests/bug55543.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Bug #55543 (json_encode() with JSOND_NUMERIC_CHECK & numeric string properties)
3 | --SKIPIF--
4 |
5 | --FILE--
6 | {"1"} = "5";
11 |
12 | var_dump($jsond_encode($a, jsond_constant('NUMERIC_CHECK')));
13 | ?>
14 | --EXPECT--
15 | string(7) "{"1":5}"
16 |
--------------------------------------------------------------------------------
/tests/bug61537.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Bug #61537 (json_encode() incorrectly truncates/discards information)
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
28 | --EXPECTF--
29 | bool(false)
30 | int(5)
31 | string(56) "Malformed UTF-8 characters, possibly incorrectly encoded"
32 | string(4) "null"
33 | int(5)
34 | string(56) "Malformed UTF-8 characters, possibly incorrectly encoded"
35 |
36 | bool(false)
37 | int(5)
38 | string(56) "Malformed UTF-8 characters, possibly incorrectly encoded"
39 | string(4) "null"
40 | int(5)
41 | string(56) "Malformed UTF-8 characters, possibly incorrectly encoded"
42 |
--------------------------------------------------------------------------------
/tests/bug61978.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Bug #61978 (Object recursion not detected for classes that implement JsonSerializable)
3 | --SKIPIF--
4 |
5 | --FILE--
6 | test = '123';
14 | $this->me = $this;
15 | }
16 | }
17 |
18 | if ($jsond_prefix === 'jsond') {
19 | class JsonTest2 implements JsondSerializable {
20 | public $test;
21 | public function __construct() {
22 | $this->test = '123';
23 | }
24 | public function jsonSerialize() {
25 | return array(
26 | 'test' => $this->test,
27 | 'me' => $this
28 | );
29 | }
30 | }
31 | } else {
32 | class JsonTest2 implements JsonSerializable {
33 | public $test;
34 | public function __construct() {
35 | $this->test = '123';
36 | }
37 | public function jsonSerialize() {
38 | return array(
39 | 'test' => $this->test,
40 | 'me' => $this
41 | );
42 | }
43 |
44 | }
45 | }
46 |
47 |
48 | $obj1 = new JsonTest1();
49 | var_dump($jsond_encode($obj1, jsond_constant('PARTIAL_OUTPUT_ON_ERROR')));
50 |
51 | echo "==\n";
52 |
53 | $obj2 = new JsonTest2();
54 | var_dump($jsond_encode($obj2, jsond_constant('PARTIAL_OUTPUT_ON_ERROR')));
55 |
56 | ?>
57 | --EXPECTF--
58 | string(24) "{"test":"123","me":null}"
59 | ==
60 | string(24) "{"test":"123","me":null}"
61 |
--------------------------------------------------------------------------------
/tests/bug62010.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Bug #62010 (json_decode produces invalid byte-sequences)
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
13 | --EXPECTF--
14 | NULL
15 | bool(true)
16 | string(50) "Single unpaired UTF-16 surrogate in unicode escape"
17 |
--------------------------------------------------------------------------------
/tests/bug62369.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | FR #62369 (Segfault on json_encode(deeply_nested_array)
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
24 | --EXPECTF--
25 | OK
26 | ERROR
27 |
--------------------------------------------------------------------------------
/tests/bug63737.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Bug #63737 (json_decode does not properly decode with options parameter)
3 | --INI--
4 | serialize_precision=14
5 | --SKIPIF--
6 |
7 | --FILE--
8 |
29 | --EXPECT--
30 | float(1.2345678901235E+29)
31 | string(30) "123456789012345678901234567890"
32 | float(-1.2345678901235E+29)
33 | string(31) "-123456789012345678901234567890"
34 | float(1.2345678901235E+29)
35 | float(1.2345678901235E+29)
36 | float(-1.2345678901235E+29)
37 | float(-1.2345678901235E+29)
38 | Done
39 |
--------------------------------------------------------------------------------
/tests/bug64695.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Bug #64695 JSON_NUMERIC_CHECK has issues with strings that are numbers plus the letter e
3 | --SKIPIF--
4 |
5 | --FILE--
6 | '123343e871700');
10 | var_dump($jsond_encode($t, jsond_constant('NUMERIC_CHECK')));
11 |
12 | echo "Done\n";
13 | ?>
14 | --EXPECT--
15 | string(24) "{"test":"123343e871700"}"
16 | Done
17 |
--------------------------------------------------------------------------------
/tests/bug64874_part1.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Whitespace part of bug #64874 ("json_decode handles whitespace and case-sensitivity incorrectly")
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
49 | --EXPECT--
50 | bool(true)
51 | bool(false)
52 |
53 | bool(true)
54 | bool(false)
55 |
56 | bool(true)
57 | bool(false)
58 |
59 | bool(true)
60 | bool(false)
61 |
62 | bool(true)
63 | bool(false)
64 |
65 | bool(true)
66 | bool(false)
67 |
68 | bool(true)
69 | bool(false)
70 |
71 | bool(true)
72 | bool(false)
73 |
74 | bool(true)
75 | bool(false)
76 |
77 | bool(true)
78 | bool(false)
79 |
80 | bool(true)
81 | bool(false)
82 |
83 | bool(true)
84 | bool(false)
85 |
86 | bool(true)
87 | bool(false)
88 |
89 | bool(true)
90 | bool(false)
91 |
92 | bool(true)
93 | bool(false)
94 |
95 | bool(true)
96 | bool(false)
97 |
98 | bool(true)
99 | bool(false)
100 |
101 | bool(true)
102 | bool(false)
103 |
104 | bool(true)
105 | bool(false)
106 |
107 | bool(true)
108 | bool(false)
109 |
110 | bool(true)
111 | bool(false)
112 |
113 | bool(true)
114 | bool(false)
115 |
116 | bool(true)
117 | bool(false)
118 |
119 | bool(true)
120 | bool(false)
121 |
122 | Done
123 |
--------------------------------------------------------------------------------
/tests/bug64874_part2.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Case-sensitivity part of bug #64874 ("json_decode handles whitespace and case-sensitivity incorrectly")
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
37 | --EXPECT--
38 | bool(true)
39 | SUCCESS
40 | NULL
41 | ERROR
42 | array(1) {
43 | [0]=>
44 | bool(true)
45 | }
46 | SUCCESS
47 | NULL
48 | ERROR
49 |
50 | bool(false)
51 | SUCCESS
52 | NULL
53 | ERROR
54 | array(1) {
55 | [0]=>
56 | bool(false)
57 | }
58 | SUCCESS
59 | NULL
60 | ERROR
61 |
62 | NULL
63 | SUCCESS
64 | NULL
65 | ERROR
66 | array(1) {
67 | [0]=>
68 | NULL
69 | }
70 | SUCCESS
71 | NULL
72 | ERROR
73 |
74 | Done
75 |
--------------------------------------------------------------------------------
/tests/bug66021.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Bug #66021 (Blank line inside empty array/object when JSON_PRETTY_PRINT is set)
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
16 | --EXPECT--
17 | [
18 | [],
19 | {},
20 | {}
21 | ]
22 |
--------------------------------------------------------------------------------
/tests/bug66025.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Bug #66025 (Indent wrong when json_encode() called from jsonSerialize function)
3 | --SKIPIF--
4 |
7 | --FILE--
8 |
27 | --EXPECT--
28 | ["[\n 1\n]"]
--------------------------------------------------------------------------------
/tests/bug68546.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Bug #68546 (json_decode() Fatal error: Cannot access property started with '\0')
3 | --SKIPIF--
4 |
8 | --FILE--
9 |
20 | --EXPECT--
21 | NULL
22 | bool(true)
23 | NULL
24 | bool(true)
25 | string(36) "The decoded property name is invalid"
26 | Done
27 |
--------------------------------------------------------------------------------
/tests/bug68992.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Bug #68992 (json_encode stacks exceptions thrown by JsonSerializable classes)
3 | --SKIPIF--
4 |
7 | --FILE--
8 | getMessage(), $e->getCode(), get_class($e));
35 | } while ($e = $e->getPrevious());
36 | }
37 | ?>
38 | --EXPECT--
39 | Not implemented! (0) [Exception]
--------------------------------------------------------------------------------
/tests/bug69187.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Bug #69187 json_last_error return BC in PHP7
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
34 | --EXPECT--
35 | NULL
36 | int(4)
37 | NULL
38 | int(4)
39 | NULL
40 | int(4)
41 | int(0)
42 | int(0)
43 | int(1)
44 | int(0)
45 | int(1)
46 | int(0)
47 | int(5)
48 | int(3)
49 | int(5)
50 | int(3)
51 |
--------------------------------------------------------------------------------
/tests/bug71835.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Bug #71835 (json_encode sometimes incorrectly detects recursion with JsonSerializable)
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
41 | --EXPECT--
42 | string(6) "[[[]]]"
43 | string(6) "[[[]]]"
44 |
--------------------------------------------------------------------------------
/tests/bug72069.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Bug #72069 (Behavior \JsonSerializable different from json_encode)
3 | --SKIPIF--
4 |
5 | --FILE--
6 | $jsond_decode("null", true)];
16 | }
17 | }
18 | } else {
19 | class A implements \JsonSerializable
20 | {
21 | function jsonSerialize()
22 | {
23 | global $jsond_decode;
24 | return ['end' => $jsond_decode("null", true)];
25 | }
26 | }
27 | }
28 |
29 | $result = $jsond_encode(['end' => $jsond_decode("null", true)]);
30 | var_dump($result);
31 | $a = new A();
32 | $toJsonData = $a->jsonSerialize();
33 | $result = $jsond_encode($a);
34 | var_dump($result);
35 |
36 | $result = $jsond_encode($toJsonData);
37 | var_dump($result);
38 | ?>
39 | --EXPECT--
40 | string(12) "{"end":null}"
41 | string(12) "{"end":null}"
42 | string(12) "{"end":null}"
43 |
--------------------------------------------------------------------------------
/tests/bug72787.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Bug #72787 (json_decode reads out of bounds)
3 | --SKIPIF--
4 |
5 |
6 | --FILE--
7 |
13 | --EXPECTF--
14 |
15 | Warning: %s(): Depth must be lower than %d in %s on line %d
16 | NULL
17 |
--------------------------------------------------------------------------------
/tests/bug73113.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Bug #73113 (Segfault with throwing JsonSerializable) - also test that the custom exception is not wrapped
3 | --SKIPIF--
4 |
5 | --FILE--
6 | getMessage();
28 | }
29 | ?>
30 | --EXPECTF--
31 | This error is expected
--------------------------------------------------------------------------------
/tests/bug73254.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Bug #73254 (Incorrect indentation generated by json_encode() with JSON_PRETTY_PRINT)
3 | --SKIPIF--
4 |
7 | --FILE--
8 | $fp];
15 | echo $jsond_encode($data), "\n";
16 | echo $jsond_encode([$jsond_encode([1], jsond_constant('PRETTY_PRINT'))]), "\n";
17 |
18 | ?>
19 | --EXPECT--
20 | ["[\n 1\n]"]
21 |
22 | ["[\n 1\n]"]
23 |
--------------------------------------------------------------------------------
/tests/bug73991.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Bug #73991 (Allow JSON_OBJECT_AS_ARRAY to have an effect)
3 | --FILE--
4 |
14 | --EXPECTF--
15 | object(stdClass)#%d (1) {
16 | ["foo"]=>
17 | string(3) "bar"
18 | }
19 | array(1) {
20 | ["foo"]=>
21 | string(3) "bar"
22 | }
23 | object(stdClass)#%d (1) {
24 | ["foo"]=>
25 | string(3) "bar"
26 | }
27 | array(1) {
28 | ["foo"]=>
29 | string(3) "bar"
30 | }
31 |
--------------------------------------------------------------------------------
/tests/fail001.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | JSON (http://www.crockford.com/JSON/JSON_checker/test/fail*.json)
3 | --SKIPIF--
4 |
7 | --FILE--
8 |
48 | --EXPECT--
49 | Testing: "A JSON payload should be an object or array, not a string."
50 | AS OBJECT
51 | string(58) "A JSON payload should be an object or array, not a string."
52 | AS ARRAY
53 | string(58) "A JSON payload should be an object or array, not a string."
54 | Testing: ["Unclosed array"
55 | AS OBJECT
56 | NULL
57 | AS ARRAY
58 | NULL
59 | Testing: {unquoted_key: "keys must be quoted}
60 | AS OBJECT
61 | NULL
62 | AS ARRAY
63 | NULL
64 | Testing: ["extra comma",]
65 | AS OBJECT
66 | NULL
67 | AS ARRAY
68 | NULL
69 | Testing: ["double extra comma",,]
70 | AS OBJECT
71 | NULL
72 | AS ARRAY
73 | NULL
74 | Testing: [ , "<-- missing value"]
75 | AS OBJECT
76 | NULL
77 | AS ARRAY
78 | NULL
79 | Testing: ["Comma after the close"],
80 | AS OBJECT
81 | NULL
82 | AS ARRAY
83 | NULL
84 | Testing: ["Extra close"]]
85 | AS OBJECT
86 | NULL
87 | AS ARRAY
88 | NULL
89 | Testing: {"Extra comma": true,}
90 | AS OBJECT
91 | NULL
92 | AS ARRAY
93 | NULL
94 | Testing: {"Extra value after close": true} "misplaced quoted value"
95 | AS OBJECT
96 | NULL
97 | AS ARRAY
98 | NULL
99 | Testing: {"Illegal expression": 1 + 2}
100 | AS OBJECT
101 | NULL
102 | AS ARRAY
103 | NULL
104 | Testing: {"Illegal invocation": alert()}
105 | AS OBJECT
106 | NULL
107 | AS ARRAY
108 | NULL
109 | Testing: {"Numbers cannot have leading zeroes": 013}
110 | AS OBJECT
111 | NULL
112 | AS ARRAY
113 | NULL
114 | Testing: {"Numbers cannot be hex": 0x14}
115 | AS OBJECT
116 | NULL
117 | AS ARRAY
118 | NULL
119 | Testing: ["Illegal backslash escape: \x15"]
120 | AS OBJECT
121 | NULL
122 | AS ARRAY
123 | NULL
124 | Testing: ["Illegal backslash escape: \'"]
125 | AS OBJECT
126 | NULL
127 | AS ARRAY
128 | NULL
129 | Testing: ["Illegal backslash escape: \017"]
130 | AS OBJECT
131 | NULL
132 | AS ARRAY
133 | NULL
134 | Testing: [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
135 | AS OBJECT
136 | NULL
137 | AS ARRAY
138 | NULL
139 | Testing: {"Missing colon" null}
140 | AS OBJECT
141 | NULL
142 | AS ARRAY
143 | NULL
144 | Testing: {"Double colon":: null}
145 | AS OBJECT
146 | NULL
147 | AS ARRAY
148 | NULL
149 | Testing: {"Comma instead of colon", null}
150 | AS OBJECT
151 | NULL
152 | AS ARRAY
153 | NULL
154 | Testing: ["Colon instead of comma": false]
155 | AS OBJECT
156 | NULL
157 | AS ARRAY
158 | NULL
159 | Testing: ["Bad value", truth]
160 | AS OBJECT
161 | NULL
162 | AS ARRAY
163 | NULL
164 | Testing: ['single quote']
165 | AS OBJECT
166 | NULL
167 | AS ARRAY
168 | NULL
169 |
170 |
--------------------------------------------------------------------------------
/tests/inf_nan_error.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | An error is thrown when INF or NaN are encoded
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
31 | --EXPECTF--
32 | float(INF)
33 | bool(false)
34 | int(7)
35 | string(34) "Inf and NaN cannot be JSON encoded"
36 | string(1) "0"
37 | int(7)
38 | string(34) "Inf and NaN cannot be JSON encoded"
39 |
40 | float(NAN)
41 | bool(false)
42 | int(7)
43 | string(34) "Inf and NaN cannot be JSON encoded"
44 | string(1) "0"
45 | int(7)
46 | string(34) "Inf and NaN cannot be JSON encoded"
47 |
--------------------------------------------------------------------------------
/tests/json_decode_basic.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Test json_decode() function : basic functionality
3 | --SKIPIF--
4 |
9 | --FILE--
10 |
50 | ===Done===
51 | --EXPECTF--
52 | *** Testing json_decode() : basic functionality ***
53 | -- Iteration 1 --
54 | int(0)
55 | int(0)
56 | -- Iteration 2 --
57 | int(123)
58 | int(123)
59 | -- Iteration 3 --
60 | int(-123)
61 | int(-123)
62 | -- Iteration 4 --
63 | int(2147483647)
64 | int(2147483647)
65 | -- Iteration 5 --
66 | int(-2147483648)
67 | int(-2147483648)
68 | -- Iteration 6 --
69 | float(123.456)
70 | float(123.456)
71 | -- Iteration 7 --
72 | int(1230)
73 | int(1230)
74 | -- Iteration 8 --
75 | int(-1230)
76 | int(-1230)
77 | -- Iteration 9 --
78 | bool(true)
79 | bool(true)
80 | -- Iteration 10 --
81 | bool(false)
82 | bool(false)
83 | -- Iteration 11 --
84 | NULL
85 | NULL
86 | -- Iteration 12 --
87 | string(3) "abc"
88 | string(3) "abc"
89 | -- Iteration 13 --
90 | string(13) "Hello World
91 | "
92 | string(13) "Hello World
93 | "
94 | -- Iteration 14 --
95 | array(0) {
96 | }
97 | array(0) {
98 | }
99 | -- Iteration 15 --
100 | array(5) {
101 | [0]=>
102 | int(1)
103 | [1]=>
104 | int(2)
105 | [2]=>
106 | int(3)
107 | [3]=>
108 | int(4)
109 | [4]=>
110 | int(5)
111 | }
112 | array(5) {
113 | [0]=>
114 | int(1)
115 | [1]=>
116 | int(2)
117 | [2]=>
118 | int(3)
119 | [3]=>
120 | int(4)
121 | [4]=>
122 | int(5)
123 | }
124 | -- Iteration 16 --
125 | object(stdClass)#%d (5) {
126 | ["myInt"]=>
127 | int(99)
128 | ["myFloat"]=>
129 | float(123.45)
130 | ["myNull"]=>
131 | NULL
132 | ["myBool"]=>
133 | bool(true)
134 | ["myString"]=>
135 | string(11) "Hello World"
136 | }
137 | array(5) {
138 | ["myInt"]=>
139 | int(99)
140 | ["myFloat"]=>
141 | float(123.45)
142 | ["myNull"]=>
143 | NULL
144 | ["myBool"]=>
145 | bool(true)
146 | ["myString"]=>
147 | string(11) "Hello World"
148 | }
149 | -- Iteration 17 --
150 | object(stdClass)#%d (6) {
151 | ["Jan"]=>
152 | int(31)
153 | ["Feb"]=>
154 | int(29)
155 | ["Mar"]=>
156 | int(31)
157 | ["April"]=>
158 | int(30)
159 | ["May"]=>
160 | int(31)
161 | ["June"]=>
162 | int(30)
163 | }
164 | array(6) {
165 | ["Jan"]=>
166 | int(31)
167 | ["Feb"]=>
168 | int(29)
169 | ["Mar"]=>
170 | int(31)
171 | ["April"]=>
172 | int(30)
173 | ["May"]=>
174 | int(31)
175 | ["June"]=>
176 | int(30)
177 | }
178 | -- Iteration 18 --
179 | string(0) ""
180 | string(0) ""
181 | -- Iteration 19 --
182 | object(stdClass)#%d (0) {
183 | }
184 | array(0) {
185 | }
186 | ===Done===
187 |
--------------------------------------------------------------------------------
/tests/json_decode_error.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Test json_decode() function : error conditions
3 | --SKIPIF--
4 |
9 | --FILE--
10 |
34 | ===Done===
35 | --EXPECTF--
36 | *** Testing %s : error conditions ***
37 |
38 | -- Testing json_decode() function with no arguments --
39 |
40 | Warning: %s expects at least 1 parameter, 0 given in %s on line %d
41 | NULL
42 |
43 | -- Testing json_decode() function with more than expected no. of arguments --
44 |
45 | Warning: %s expects at most 4 parameters, 5 given in %s on line %d
46 | NULL
47 | ===Done===
48 |
--------------------------------------------------------------------------------
/tests/json_encode_basic.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Test json_encode() function : basic functionality
3 | --SKIPIF--
4 |
9 | --FILE--
10 | MyInt = 99;
33 | $obj->MyFloat = 123.45;
34 | $obj->MyBool = true;
35 | $obj->MyNull = null;
36 | $obj->MyString = "Hello World";
37 |
38 | // array with different values for $string
39 | $inputs = array (
40 |
41 | // integers
42 | /*1*/ 0,
43 | 123,
44 | -123,
45 | 2147483647,
46 | -2147483648,
47 |
48 | // floats
49 | /*6*/ 123.456,
50 | 1.23E3,
51 | -1.23E3,
52 |
53 | // boolean
54 | /*9*/ TRUE,
55 | true,
56 | FALSE,
57 | false,
58 |
59 | // NULL
60 | /*13*/ NULL,
61 | null,
62 |
63 | // strings
64 | /*15*/ "abc",
65 | 'abc',
66 | "Hello\t\tWorld\n",
67 |
68 | // arrays
69 | /*18*/ array(),
70 | array(1,2,3,4,5),
71 | array(1 => "Sun", 2=>"Mon", 3 => "Tue", 4 => "Wed", 5 => "Thur", 6 => "Fri", 7 => "Sat"),
72 | array("Jan" => 31, "Feb" => 29, "Mar" => 31, "April" => 30, "May" => 31, "June" => 30),
73 |
74 | // empty data
75 | /*22*/ "",
76 | '',
77 |
78 | // undefined data
79 | /*24*/ @$undefined_var,
80 |
81 | // unset data
82 | /*25*/ @$unset_var,
83 |
84 | // resource variable
85 | /*26*/ $fp,
86 |
87 | // object variable
88 | /*27*/ $obj
89 |
90 | );
91 |
92 | // loop through with each element of the $inputs array to test jsond_encode() function
93 | $count = 1;
94 | foreach($inputs as $input) {
95 | echo "-- Iteration $count --\n";
96 | var_dump($jsond_encode($input));
97 | $count ++;
98 | }
99 |
100 | ?>
101 | ===Done===
102 | --EXPECTF--
103 | *** Testing json_encode() : basic functionality ***
104 | -- Iteration 1 --
105 | string(1) "0"
106 | -- Iteration 2 --
107 | string(3) "123"
108 | -- Iteration 3 --
109 | string(4) "-123"
110 | -- Iteration 4 --
111 | string(10) "2147483647"
112 | -- Iteration 5 --
113 | string(11) "-2147483648"
114 | -- Iteration 6 --
115 | string(7) "123.456"
116 | -- Iteration 7 --
117 | string(4) "1230"
118 | -- Iteration 8 --
119 | string(5) "-1230"
120 | -- Iteration 9 --
121 | string(4) "true"
122 | -- Iteration 10 --
123 | string(4) "true"
124 | -- Iteration 11 --
125 | string(5) "false"
126 | -- Iteration 12 --
127 | string(5) "false"
128 | -- Iteration 13 --
129 | string(4) "null"
130 | -- Iteration 14 --
131 | string(4) "null"
132 | -- Iteration 15 --
133 | string(5) ""abc""
134 | -- Iteration 16 --
135 | string(5) ""abc""
136 | -- Iteration 17 --
137 | string(18) ""Hello\t\tWorld\n""
138 | -- Iteration 18 --
139 | string(2) "[]"
140 | -- Iteration 19 --
141 | string(11) "[1,2,3,4,5]"
142 | -- Iteration 20 --
143 | string(72) "{"1":"Sun","2":"Mon","3":"Tue","4":"Wed","5":"Thur","6":"Fri","7":"Sat"}"
144 | -- Iteration 21 --
145 | string(58) "{"Jan":31,"Feb":29,"Mar":31,"April":30,"May":31,"June":30}"
146 | -- Iteration 22 --
147 | string(2) """"
148 | -- Iteration 23 --
149 | string(2) """"
150 | -- Iteration 24 --
151 | string(4) "null"
152 | -- Iteration 25 --
153 | string(4) "null"
154 | -- Iteration 26 --
155 | bool(false)
156 | -- Iteration 27 --
157 | string(82) "{"MyInt":99,"MyFloat":123.45,"MyBool":true,"MyNull":null,"MyString":"Hello World"}"
158 | ===Done===
159 |
--------------------------------------------------------------------------------
/tests/json_encode_basic_utf8.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Test json_encode() function : basic functionality with UTF8 string input
3 | --SKIPIF--
4 |
9 | --FILE--
10 |
19 | ===Done===
20 | --EXPECTF--
21 | *** Testing json_encode() : basic functionality with UTF-8 input***
22 | string(103) ""\u65e5\u672c\u8a9e\u30c6\u30ad\u30b9\u30c8\u3067\u3059\u300201234\uff15\uff16\uff17\uff18\uff19\u3002""
23 | ===Done===
24 |
--------------------------------------------------------------------------------
/tests/json_encode_error.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Test json_encode() function : error conditions
3 | --SKIPIF--
4 |
9 | --FILE--
10 |
27 | ===Done===
28 | --EXPECTF--
29 | *** Testing json_encode() : error conditions ***
30 |
31 | -- Testing json_encode() function with no arguments --
32 |
33 | Warning: %s expects at least 1 parameter, 0 given in %s on line %d
34 | NULL
35 |
36 | -- Testing json_encode() function with more than expected no. of arguments --
37 | string(5) ""abc""
38 | ===Done===
39 |
--------------------------------------------------------------------------------
/tests/json_encode_numeric.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Test json_encode() function with numeric flag
3 | --SKIPIF--
4 |
9 | --FILE--
10 |
22 | --EXPECT--
23 | string(1) "1"
24 | string(6) "9.4324"
25 | string(22) "[122321,3232595.33423]"
26 | string(3) ""1""
27 | string(8) ""9.4324""
28 | string(26) "["122321","3232595.33423"]"
29 |
--------------------------------------------------------------------------------
/tests/json_encode_pretty_print.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | json_encode() with JSON_PRETTY_PRINT
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
22 | --EXPECT--
23 | [
24 | 1,
25 | 2,
26 | 3,
27 | [
28 | 1,
29 | 2,
30 | 3
31 | ]
32 | ]
33 | Match: 1
34 | {
35 | "a": 1,
36 | "b": [
37 | 1,
38 | 2
39 | ],
40 | "c": {
41 | "d": 42
42 | }
43 | }
44 | Match: 1
45 |
--------------------------------------------------------------------------------
/tests/json_encode_u2028_u2029.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | json_encode() tests for U+2028, U+2029
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
24 | --EXPECT--
25 | string(12) "["a\u00e1b"]"
26 | string(8) "["aáb"]"
27 | string(10) ""a\u2027b""
28 | string(7) ""a‧b""
29 | string(10) ""a\u2028b""
30 | string(10) ""a\u2028b""
31 | string(10) ""a\u2028b""
32 | string(7) ""a
b""
33 | string(10) ""a\u2029b""
34 | string(10) ""a\u2029b""
35 | string(10) ""a\u2029b""
36 | string(7) ""a
b""
37 | string(10) ""a\u202ab""
38 | string(7) ""ab""
39 |
--------------------------------------------------------------------------------
/tests/json_encode_unescaped_slashes.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | json_decode() unescaped slashes test
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
12 | --EXPECT--
13 | string(6) ""a\/b""
14 | string(5) ""a/b""
15 |
--------------------------------------------------------------------------------
/tests/json_last_error_error.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | json_last_error() failures
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
24 | --EXPECTF--
25 | int(0)
26 |
27 | Warning: %s expects exactly 0 parameters, 1 given in %s on line %d
28 | NULL
29 |
30 | Warning: %s expects exactly 0 parameters, 4 given in %s on line %d
31 | NULL
32 |
33 |
--------------------------------------------------------------------------------
/tests/json_last_error_msg_error.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | json_last_error_msg() failures
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
24 | --EXPECTF--
25 | string(8) "No error"
26 |
27 | Warning: %s expects exactly 0 parameters, 1 given in %s on line %d
28 | NULL
29 |
30 | Warning: %s expects exactly 0 parameters, 4 given in %s on line %d
31 | NULL
32 |
33 |
--------------------------------------------------------------------------------
/tests/pass001.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | JSON (http://www.crockford.com/JSON/JSON_checker/test/pass1.json)
3 | --INI--
4 | serialize_precision=14
5 | --SKIPIF--
6 |
9 | --FILE--
10 | ?\",
40 | \"hex\": \"\\u0123\\u4567\\u89AB\\uCDEF\\uabcd\\uef4A\",
41 | \"true\": true,
42 | \"false\": false,
43 | \"null\": null,
44 | \"array\":[ ],
45 | \"object\":{ },
46 | \"address\": \"50 St. James Street\",
47 | \"url\": \"http://www.JSON.org/\",
48 | \"comment\": \"// /* */\": \" \",
50 | \" s p a c e d \" :[1,2 , 3
51 |
52 | ,
53 |
54 | 4 , 5 , 6 ,7 ],
55 | \"compact\": [1,2,3,4,5,6,7],
56 | \"jsondtext\": \"{\\\"object with 1 member\\\":[\\\"array with 1 element\\\"]}\",
57 | \"quotes\": \"" \\u0022 %22 0x22 034 "\",
58 | \"\\/\\\\\\\"\\uCAFE\\uBABE\\uAB98\\uFCDE\\ubcda\\uef4A\\b\\f\\n\\r\\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?\"
59 | : \"A key can be any string\"
60 | },
61 | 0.5 ,98.6
62 | ,
63 | 99.44
64 | ,
65 |
66 | 1066
67 |
68 |
69 | ,\"rosebud\"]
70 | ";
71 |
72 | echo 'Testing: ' . $test . "\n";
73 | echo "DECODE: AS OBJECT\n";
74 | $obj = $jsond_decode($test);
75 | var_dump($obj);
76 | echo "DECODE: AS ARRAY\n";
77 | $arr = $jsond_decode($test, true);
78 | var_dump($arr);
79 |
80 | echo "ENCODE: FROM OBJECT\n";
81 | $obj_enc = $jsond_encode($obj, jsond_constant('PARTIAL_OUTPUT_ON_ERROR'));
82 | echo $obj_enc . "\n";
83 | echo "ENCODE: FROM ARRAY\n";
84 | $arr_enc = $jsond_encode($arr, jsond_constant('PARTIAL_OUTPUT_ON_ERROR'));
85 | echo $arr_enc . "\n";
86 |
87 | echo "DECODE AGAIN: AS OBJECT\n";
88 | $obj = $jsond_decode($obj_enc);
89 | var_dump($obj);
90 | echo "DECODE AGAIN: AS ARRAY\n";
91 | $arr = $jsond_decode($arr_enc, true);
92 | var_dump($arr);
93 |
94 | ?>
95 | --EXPECTF--
96 | Testing:
97 | [
98 | "JSON Test Pattern pass1",
99 | {"object with 1 member":["array with 1 element"]},
100 | {},
101 | [],
102 | -42,
103 | true,
104 | false,
105 | null,
106 | {
107 | "integer": 1234567890,
108 | "real": -9876.543210,
109 | "e": 0.123456789e-12,
110 | "E": 1.234567890E+34,
111 | "": 23456789012E666,
112 | "zero": 0,
113 | "one": 1,
114 | "space": " ",
115 | "quote": "\"",
116 | "backslash": "\\",
117 | "controls": "\b\f\n\r\t",
118 | "slash": "/ & \/",
119 | "alpha": "abcdefghijklmnopqrstuvwyz",
120 | "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ",
121 | "digit": "0123456789",
122 | "special": "`1~!@#$%^&*()_+-={':[,]}|;.>?",
123 | "hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A",
124 | "true": true,
125 | "false": false,
126 | "null": null,
127 | "array":[ ],
128 | "object":{ },
129 | "address": "50 St. James Street",
130 | "url": "http://www.JSON.org/",
131 | "comment": "// /* */": " ",
133 | " s p a c e d " :[1,2 , 3
134 |
135 | ,
136 |
137 | 4 , 5 , 6 ,7 ],
138 | "compact": [1,2,3,4,5,6,7],
139 | "jsondtext": "{\"object with 1 member\":[\"array with 1 element\"]}",
140 | "quotes": "" \u0022 %22 0x22 034 "",
141 | "\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?"
142 | : "A key can be any string"
143 | },
144 | 0.5 ,98.6
145 | ,
146 | 99.44
147 | ,
148 |
149 | 1066
150 |
151 |
152 | ,"rosebud"]
153 |
154 | DECODE: AS OBJECT
155 | array(14) {
156 | [0]=>
157 | string(23) "JSON Test Pattern pass1"
158 | [1]=>
159 | object(stdClass)#%d (1) {
160 | ["object with 1 member"]=>
161 | array(1) {
162 | [0]=>
163 | string(20) "array with 1 element"
164 | }
165 | }
166 | [2]=>
167 | object(stdClass)#%d (0) {
168 | }
169 | [3]=>
170 | array(0) {
171 | }
172 | [4]=>
173 | int(-42)
174 | [5]=>
175 | bool(true)
176 | [6]=>
177 | bool(false)
178 | [7]=>
179 | NULL
180 | [8]=>
181 | object(stdClass)#%d (31) {
182 | ["integer"]=>
183 | int(1234567890)
184 | ["real"]=>
185 | float(-9876.54321)
186 | ["e"]=>
187 | float(1.23456789E-13)
188 | ["E"]=>
189 | float(1.23456789E+34)
190 | [""]=>
191 | float(INF)
192 | ["zero"]=>
193 | int(0)
194 | ["one"]=>
195 | int(1)
196 | ["space"]=>
197 | string(1) " "
198 | ["quote"]=>
199 | string(1) """
200 | ["backslash"]=>
201 | string(1) "\"
202 | ["controls"]=>
203 | string(5) "
204 |
"
205 | ["slash"]=>
206 | string(5) "/ & /"
207 | ["alpha"]=>
208 | string(25) "abcdefghijklmnopqrstuvwyz"
209 | ["ALPHA"]=>
210 | string(25) "ABCDEFGHIJKLMNOPQRSTUVWYZ"
211 | ["digit"]=>
212 | string(10) "0123456789"
213 | ["special"]=>
214 | string(31) "`1~!@#$%^&*()_+-={':[,]}|;.>?"
215 | ["hex"]=>
216 | string(17) "ģ䕧覫췯ꯍ"
217 | ["true"]=>
218 | bool(true)
219 | ["false"]=>
220 | bool(false)
221 | ["null"]=>
222 | NULL
223 | ["array"]=>
224 | array(0) {
225 | }
226 | ["object"]=>
227 | object(stdClass)#%d (0) {
228 | }
229 | ["address"]=>
230 | string(19) "50 St. James Street"
231 | ["url"]=>
232 | string(20) "http://www.JSON.org/"
233 | ["comment"]=>
234 | string(13) "// /* */"]=>
236 | string(1) " "
237 | [" s p a c e d "]=>
238 | array(7) {
239 | [0]=>
240 | int(1)
241 | [1]=>
242 | int(2)
243 | [2]=>
244 | int(3)
245 | [3]=>
246 | int(4)
247 | [4]=>
248 | int(5)
249 | [5]=>
250 | int(6)
251 | [6]=>
252 | int(7)
253 | }
254 | ["compact"]=>
255 | array(7) {
256 | [0]=>
257 | int(1)
258 | [1]=>
259 | int(2)
260 | [2]=>
261 | int(3)
262 | [3]=>
263 | int(4)
264 | [4]=>
265 | int(5)
266 | [5]=>
267 | int(6)
268 | [6]=>
269 | int(7)
270 | }
271 | ["jsondtext"]=>
272 | string(49) "{"object with 1 member":["array with 1 element"]}"
273 | ["quotes"]=>
274 | string(27) "" " %22 0x22 034 ""
275 | ["/\"쫾몾ꮘﳞ볚
276 |
`1~!@#$%^&*()_+-=[]{}|;:',./<>?"]=>
277 | string(23) "A key can be any string"
278 | }
279 | [9]=>
280 | float(0.5)
281 | [10]=>
282 | float(98.6)
283 | [11]=>
284 | float(99.44)
285 | [12]=>
286 | int(1066)
287 | [13]=>
288 | string(7) "rosebud"
289 | }
290 | DECODE: AS ARRAY
291 | array(14) {
292 | [0]=>
293 | string(23) "JSON Test Pattern pass1"
294 | [1]=>
295 | array(1) {
296 | ["object with 1 member"]=>
297 | array(1) {
298 | [0]=>
299 | string(20) "array with 1 element"
300 | }
301 | }
302 | [2]=>
303 | array(0) {
304 | }
305 | [3]=>
306 | array(0) {
307 | }
308 | [4]=>
309 | int(-42)
310 | [5]=>
311 | bool(true)
312 | [6]=>
313 | bool(false)
314 | [7]=>
315 | NULL
316 | [8]=>
317 | array(31) {
318 | ["integer"]=>
319 | int(1234567890)
320 | ["real"]=>
321 | float(-9876.54321)
322 | ["e"]=>
323 | float(1.23456789E-13)
324 | ["E"]=>
325 | float(1.23456789E+34)
326 | [""]=>
327 | float(INF)
328 | ["zero"]=>
329 | int(0)
330 | ["one"]=>
331 | int(1)
332 | ["space"]=>
333 | string(1) " "
334 | ["quote"]=>
335 | string(1) """
336 | ["backslash"]=>
337 | string(1) "\"
338 | ["controls"]=>
339 | string(5) "
340 |
"
341 | ["slash"]=>
342 | string(5) "/ & /"
343 | ["alpha"]=>
344 | string(25) "abcdefghijklmnopqrstuvwyz"
345 | ["ALPHA"]=>
346 | string(25) "ABCDEFGHIJKLMNOPQRSTUVWYZ"
347 | ["digit"]=>
348 | string(10) "0123456789"
349 | ["special"]=>
350 | string(31) "`1~!@#$%^&*()_+-={':[,]}|;.>?"
351 | ["hex"]=>
352 | string(17) "ģ䕧覫췯ꯍ"
353 | ["true"]=>
354 | bool(true)
355 | ["false"]=>
356 | bool(false)
357 | ["null"]=>
358 | NULL
359 | ["array"]=>
360 | array(0) {
361 | }
362 | ["object"]=>
363 | array(0) {
364 | }
365 | ["address"]=>
366 | string(19) "50 St. James Street"
367 | ["url"]=>
368 | string(20) "http://www.JSON.org/"
369 | ["comment"]=>
370 | string(13) "// /* */"]=>
372 | string(1) " "
373 | [" s p a c e d "]=>
374 | array(7) {
375 | [0]=>
376 | int(1)
377 | [1]=>
378 | int(2)
379 | [2]=>
380 | int(3)
381 | [3]=>
382 | int(4)
383 | [4]=>
384 | int(5)
385 | [5]=>
386 | int(6)
387 | [6]=>
388 | int(7)
389 | }
390 | ["compact"]=>
391 | array(7) {
392 | [0]=>
393 | int(1)
394 | [1]=>
395 | int(2)
396 | [2]=>
397 | int(3)
398 | [3]=>
399 | int(4)
400 | [4]=>
401 | int(5)
402 | [5]=>
403 | int(6)
404 | [6]=>
405 | int(7)
406 | }
407 | ["jsondtext"]=>
408 | string(49) "{"object with 1 member":["array with 1 element"]}"
409 | ["quotes"]=>
410 | string(27) "" " %22 0x22 034 ""
411 | ["/\"쫾몾ꮘﳞ볚
412 |
`1~!@#$%^&*()_+-=[]{}|;:',./<>?"]=>
413 | string(23) "A key can be any string"
414 | }
415 | [9]=>
416 | float(0.5)
417 | [10]=>
418 | float(98.6)
419 | [11]=>
420 | float(99.44)
421 | [12]=>
422 | int(1066)
423 | [13]=>
424 | string(7) "rosebud"
425 | }
426 | ENCODE: FROM OBJECT
427 | ["JSON Test Pattern pass1",{"object with 1 member":["array with 1 element"]},{},[],-42,true,false,null,{"integer":1234567890,"real":-9876.54321,"e":1.23456789e-13,"E":1.23456789e+34,"":0,"zero":0,"one":1,"space":" ","quote":"\"","backslash":"\\","controls":"\b\f\n\r\t","slash":"\/ & \/","alpha":"abcdefghijklmnopqrstuvwyz","ALPHA":"ABCDEFGHIJKLMNOPQRSTUVWYZ","digit":"0123456789","special":"`1~!@#$%^&*()_+-={':[,]}|;.<\/>?","hex":"\u0123\u4567\u89ab\ucdef\uabcd\uef4a","true":true,"false":false,"null":null,"array":[],"object":{},"address":"50 St. James Street","url":"http:\/\/www.JSON.org\/","comment":"\/\/ \/* *\/":" "," s p a c e d ":[1,2,3,4,5,6,7],"compact":[1,2,3,4,5,6,7],"jsondtext":"{\"object with 1 member\":[\"array with 1 element\"]}","quotes":"" \" %22 0x22 034 "","\/\\\"\ucafe\ubabe\uab98\ufcde\ubcda\uef4a\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',.\/<>?":"A key can be any string"},0.5,98.6,99.44,1066,"rosebud"]
428 | ENCODE: FROM ARRAY
429 | ["JSON Test Pattern pass1",{"object with 1 member":["array with 1 element"]},[],[],-42,true,false,null,{"integer":1234567890,"real":-9876.54321,"e":1.23456789e-13,"E":1.23456789e+34,"":0,"zero":0,"one":1,"space":" ","quote":"\"","backslash":"\\","controls":"\b\f\n\r\t","slash":"\/ & \/","alpha":"abcdefghijklmnopqrstuvwyz","ALPHA":"ABCDEFGHIJKLMNOPQRSTUVWYZ","digit":"0123456789","special":"`1~!@#$%^&*()_+-={':[,]}|;.<\/>?","hex":"\u0123\u4567\u89ab\ucdef\uabcd\uef4a","true":true,"false":false,"null":null,"array":[],"object":[],"address":"50 St. James Street","url":"http:\/\/www.JSON.org\/","comment":"\/\/ \/* *\/":" "," s p a c e d ":[1,2,3,4,5,6,7],"compact":[1,2,3,4,5,6,7],"jsondtext":"{\"object with 1 member\":[\"array with 1 element\"]}","quotes":"" \" %22 0x22 034 "","\/\\\"\ucafe\ubabe\uab98\ufcde\ubcda\uef4a\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',.\/<>?":"A key can be any string"},0.5,98.6,99.44,1066,"rosebud"]
430 | DECODE AGAIN: AS OBJECT
431 | array(14) {
432 | [0]=>
433 | string(23) "JSON Test Pattern pass1"
434 | [1]=>
435 | object(stdClass)#%d (1) {
436 | ["object with 1 member"]=>
437 | array(1) {
438 | [0]=>
439 | string(20) "array with 1 element"
440 | }
441 | }
442 | [2]=>
443 | object(stdClass)#%d (0) {
444 | }
445 | [3]=>
446 | array(0) {
447 | }
448 | [4]=>
449 | int(-42)
450 | [5]=>
451 | bool(true)
452 | [6]=>
453 | bool(false)
454 | [7]=>
455 | NULL
456 | [8]=>
457 | object(stdClass)#%d (31) {
458 | ["integer"]=>
459 | int(1234567890)
460 | ["real"]=>
461 | float(-9876.54321)
462 | ["e"]=>
463 | float(1.23456789E-13)
464 | ["E"]=>
465 | float(1.23456789E+34)
466 | [""]=>
467 | int(0)
468 | ["zero"]=>
469 | int(0)
470 | ["one"]=>
471 | int(1)
472 | ["space"]=>
473 | string(1) " "
474 | ["quote"]=>
475 | string(1) """
476 | ["backslash"]=>
477 | string(1) "\"
478 | ["controls"]=>
479 | string(5) "
480 |
"
481 | ["slash"]=>
482 | string(5) "/ & /"
483 | ["alpha"]=>
484 | string(25) "abcdefghijklmnopqrstuvwyz"
485 | ["ALPHA"]=>
486 | string(25) "ABCDEFGHIJKLMNOPQRSTUVWYZ"
487 | ["digit"]=>
488 | string(10) "0123456789"
489 | ["special"]=>
490 | string(31) "`1~!@#$%^&*()_+-={':[,]}|;.>?"
491 | ["hex"]=>
492 | string(17) "ģ䕧覫췯ꯍ"
493 | ["true"]=>
494 | bool(true)
495 | ["false"]=>
496 | bool(false)
497 | ["null"]=>
498 | NULL
499 | ["array"]=>
500 | array(0) {
501 | }
502 | ["object"]=>
503 | object(stdClass)#%d (0) {
504 | }
505 | ["address"]=>
506 | string(19) "50 St. James Street"
507 | ["url"]=>
508 | string(20) "http://www.JSON.org/"
509 | ["comment"]=>
510 | string(13) "// /* */"]=>
512 | string(1) " "
513 | [" s p a c e d "]=>
514 | array(7) {
515 | [0]=>
516 | int(1)
517 | [1]=>
518 | int(2)
519 | [2]=>
520 | int(3)
521 | [3]=>
522 | int(4)
523 | [4]=>
524 | int(5)
525 | [5]=>
526 | int(6)
527 | [6]=>
528 | int(7)
529 | }
530 | ["compact"]=>
531 | array(7) {
532 | [0]=>
533 | int(1)
534 | [1]=>
535 | int(2)
536 | [2]=>
537 | int(3)
538 | [3]=>
539 | int(4)
540 | [4]=>
541 | int(5)
542 | [5]=>
543 | int(6)
544 | [6]=>
545 | int(7)
546 | }
547 | ["jsondtext"]=>
548 | string(49) "{"object with 1 member":["array with 1 element"]}"
549 | ["quotes"]=>
550 | string(27) "" " %22 0x22 034 ""
551 | ["/\"쫾몾ꮘﳞ볚
552 |
`1~!@#$%^&*()_+-=[]{}|;:',./<>?"]=>
553 | string(23) "A key can be any string"
554 | }
555 | [9]=>
556 | float(0.5)
557 | [10]=>
558 | float(98.6)
559 | [11]=>
560 | float(99.44)
561 | [12]=>
562 | int(1066)
563 | [13]=>
564 | string(7) "rosebud"
565 | }
566 | DECODE AGAIN: AS ARRAY
567 | array(14) {
568 | [0]=>
569 | string(23) "JSON Test Pattern pass1"
570 | [1]=>
571 | array(1) {
572 | ["object with 1 member"]=>
573 | array(1) {
574 | [0]=>
575 | string(20) "array with 1 element"
576 | }
577 | }
578 | [2]=>
579 | array(0) {
580 | }
581 | [3]=>
582 | array(0) {
583 | }
584 | [4]=>
585 | int(-42)
586 | [5]=>
587 | bool(true)
588 | [6]=>
589 | bool(false)
590 | [7]=>
591 | NULL
592 | [8]=>
593 | array(31) {
594 | ["integer"]=>
595 | int(1234567890)
596 | ["real"]=>
597 | float(-9876.54321)
598 | ["e"]=>
599 | float(1.23456789E-13)
600 | ["E"]=>
601 | float(1.23456789E+34)
602 | [""]=>
603 | int(0)
604 | ["zero"]=>
605 | int(0)
606 | ["one"]=>
607 | int(1)
608 | ["space"]=>
609 | string(1) " "
610 | ["quote"]=>
611 | string(1) """
612 | ["backslash"]=>
613 | string(1) "\"
614 | ["controls"]=>
615 | string(5) "
616 |
"
617 | ["slash"]=>
618 | string(5) "/ & /"
619 | ["alpha"]=>
620 | string(25) "abcdefghijklmnopqrstuvwyz"
621 | ["ALPHA"]=>
622 | string(25) "ABCDEFGHIJKLMNOPQRSTUVWYZ"
623 | ["digit"]=>
624 | string(10) "0123456789"
625 | ["special"]=>
626 | string(31) "`1~!@#$%^&*()_+-={':[,]}|;.>?"
627 | ["hex"]=>
628 | string(17) "ģ䕧覫췯ꯍ"
629 | ["true"]=>
630 | bool(true)
631 | ["false"]=>
632 | bool(false)
633 | ["null"]=>
634 | NULL
635 | ["array"]=>
636 | array(0) {
637 | }
638 | ["object"]=>
639 | array(0) {
640 | }
641 | ["address"]=>
642 | string(19) "50 St. James Street"
643 | ["url"]=>
644 | string(20) "http://www.JSON.org/"
645 | ["comment"]=>
646 | string(13) "// /* */"]=>
648 | string(1) " "
649 | [" s p a c e d "]=>
650 | array(7) {
651 | [0]=>
652 | int(1)
653 | [1]=>
654 | int(2)
655 | [2]=>
656 | int(3)
657 | [3]=>
658 | int(4)
659 | [4]=>
660 | int(5)
661 | [5]=>
662 | int(6)
663 | [6]=>
664 | int(7)
665 | }
666 | ["compact"]=>
667 | array(7) {
668 | [0]=>
669 | int(1)
670 | [1]=>
671 | int(2)
672 | [2]=>
673 | int(3)
674 | [3]=>
675 | int(4)
676 | [4]=>
677 | int(5)
678 | [5]=>
679 | int(6)
680 | [6]=>
681 | int(7)
682 | }
683 | ["jsondtext"]=>
684 | string(49) "{"object with 1 member":["array with 1 element"]}"
685 | ["quotes"]=>
686 | string(27) "" " %22 0x22 034 ""
687 | ["/\"쫾몾ꮘﳞ볚
688 |
`1~!@#$%^&*()_+-=[]{}|;:',./<>?"]=>
689 | string(23) "A key can be any string"
690 | }
691 | [9]=>
692 | float(0.5)
693 | [10]=>
694 | float(98.6)
695 | [11]=>
696 | float(99.44)
697 | [12]=>
698 | int(1066)
699 | [13]=>
700 | string(7) "rosebud"
701 | }
702 |
--------------------------------------------------------------------------------
/tests/pass002.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | JSON (http://www.crockford.com/JSON/JSON_checker/test/pass2.json)
3 | --SKIPIF--
4 |
7 | --FILE--
8 |
35 | --EXPECT--
36 | Testing: [[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]]
37 | DECODE: AS OBJECT
38 | array(1) {
39 | [0]=>
40 | array(1) {
41 | [0]=>
42 | array(1) {
43 | [0]=>
44 | array(1) {
45 | [0]=>
46 | array(1) {
47 | [0]=>
48 | array(1) {
49 | [0]=>
50 | array(1) {
51 | [0]=>
52 | array(1) {
53 | [0]=>
54 | array(1) {
55 | [0]=>
56 | array(1) {
57 | [0]=>
58 | array(1) {
59 | [0]=>
60 | array(1) {
61 | [0]=>
62 | array(1) {
63 | [0]=>
64 | array(1) {
65 | [0]=>
66 | array(1) {
67 | [0]=>
68 | array(1) {
69 | [0]=>
70 | array(1) {
71 | [0]=>
72 | array(1) {
73 | [0]=>
74 | array(1) {
75 | [0]=>
76 | string(12) "Not too deep"
77 | }
78 | }
79 | }
80 | }
81 | }
82 | }
83 | }
84 | }
85 | }
86 | }
87 | }
88 | }
89 | }
90 | }
91 | }
92 | }
93 | }
94 | }
95 | }
96 | DECODE: AS ARRAY
97 | array(1) {
98 | [0]=>
99 | array(1) {
100 | [0]=>
101 | array(1) {
102 | [0]=>
103 | array(1) {
104 | [0]=>
105 | array(1) {
106 | [0]=>
107 | array(1) {
108 | [0]=>
109 | array(1) {
110 | [0]=>
111 | array(1) {
112 | [0]=>
113 | array(1) {
114 | [0]=>
115 | array(1) {
116 | [0]=>
117 | array(1) {
118 | [0]=>
119 | array(1) {
120 | [0]=>
121 | array(1) {
122 | [0]=>
123 | array(1) {
124 | [0]=>
125 | array(1) {
126 | [0]=>
127 | array(1) {
128 | [0]=>
129 | array(1) {
130 | [0]=>
131 | array(1) {
132 | [0]=>
133 | array(1) {
134 | [0]=>
135 | string(12) "Not too deep"
136 | }
137 | }
138 | }
139 | }
140 | }
141 | }
142 | }
143 | }
144 | }
145 | }
146 | }
147 | }
148 | }
149 | }
150 | }
151 | }
152 | }
153 | }
154 | }
155 | ENCODE: FROM OBJECT
156 | [[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]]
157 | ENCODE: FROM ARRAY
158 | [[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]]
159 | DECODE AGAIN: AS OBJECT
160 | array(1) {
161 | [0]=>
162 | array(1) {
163 | [0]=>
164 | array(1) {
165 | [0]=>
166 | array(1) {
167 | [0]=>
168 | array(1) {
169 | [0]=>
170 | array(1) {
171 | [0]=>
172 | array(1) {
173 | [0]=>
174 | array(1) {
175 | [0]=>
176 | array(1) {
177 | [0]=>
178 | array(1) {
179 | [0]=>
180 | array(1) {
181 | [0]=>
182 | array(1) {
183 | [0]=>
184 | array(1) {
185 | [0]=>
186 | array(1) {
187 | [0]=>
188 | array(1) {
189 | [0]=>
190 | array(1) {
191 | [0]=>
192 | array(1) {
193 | [0]=>
194 | array(1) {
195 | [0]=>
196 | array(1) {
197 | [0]=>
198 | string(12) "Not too deep"
199 | }
200 | }
201 | }
202 | }
203 | }
204 | }
205 | }
206 | }
207 | }
208 | }
209 | }
210 | }
211 | }
212 | }
213 | }
214 | }
215 | }
216 | }
217 | }
218 | DECODE AGAIN: AS ARRAY
219 | array(1) {
220 | [0]=>
221 | array(1) {
222 | [0]=>
223 | array(1) {
224 | [0]=>
225 | array(1) {
226 | [0]=>
227 | array(1) {
228 | [0]=>
229 | array(1) {
230 | [0]=>
231 | array(1) {
232 | [0]=>
233 | array(1) {
234 | [0]=>
235 | array(1) {
236 | [0]=>
237 | array(1) {
238 | [0]=>
239 | array(1) {
240 | [0]=>
241 | array(1) {
242 | [0]=>
243 | array(1) {
244 | [0]=>
245 | array(1) {
246 | [0]=>
247 | array(1) {
248 | [0]=>
249 | array(1) {
250 | [0]=>
251 | array(1) {
252 | [0]=>
253 | array(1) {
254 | [0]=>
255 | array(1) {
256 | [0]=>
257 | string(12) "Not too deep"
258 | }
259 | }
260 | }
261 | }
262 | }
263 | }
264 | }
265 | }
266 | }
267 | }
268 | }
269 | }
270 | }
271 | }
272 | }
273 | }
274 | }
275 | }
276 | }
277 |
--------------------------------------------------------------------------------
/tests/pass003.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | JSON (http://www.crockford.com/JSON/JSON_checker/test/pass3.json)
3 | --SKIPIF--
4 |
7 | --FILE--
8 |
43 | --EXPECTF--
44 | Testing:
45 | {
46 | "JSON Test Pattern pass3": {
47 | "The outermost value": "must be an object or array.",
48 | "In this test": "It is an object."
49 | }
50 | }
51 |
52 | DECODE: AS OBJECT
53 | object(stdClass)#%d (1) {
54 | ["JSON Test Pattern pass3"]=>
55 | object(stdClass)#%d (2) {
56 | ["The outermost value"]=>
57 | string(27) "must be an object or array."
58 | ["In this test"]=>
59 | string(16) "It is an object."
60 | }
61 | }
62 | DECODE: AS ARRAY
63 | array(1) {
64 | ["JSON Test Pattern pass3"]=>
65 | array(2) {
66 | ["The outermost value"]=>
67 | string(27) "must be an object or array."
68 | ["In this test"]=>
69 | string(16) "It is an object."
70 | }
71 | }
72 | ENCODE: FROM OBJECT
73 | {"JSON Test Pattern pass3":{"The outermost value":"must be an object or array.","In this test":"It is an object."}}
74 | ENCODE: FROM ARRAY
75 | {"JSON Test Pattern pass3":{"The outermost value":"must be an object or array.","In this test":"It is an object."}}
76 | DECODE AGAIN: AS OBJECT
77 | object(stdClass)#%d (1) {
78 | ["JSON Test Pattern pass3"]=>
79 | object(stdClass)#%d (2) {
80 | ["The outermost value"]=>
81 | string(27) "must be an object or array."
82 | ["In this test"]=>
83 | string(16) "It is an object."
84 | }
85 | }
86 | DECODE AGAIN: AS ARRAY
87 | array(1) {
88 | ["JSON Test Pattern pass3"]=>
89 | array(2) {
90 | ["The outermost value"]=>
91 | string(27) "must be an object or array."
92 | ["In this test"]=>
93 | string(16) "It is an object."
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/tests/serialize.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | json_encode() Serialization tests
3 | --SKIPIF--
4 |
5 | --FILE--
6 | data = $data;
16 | }
17 | }
18 |
19 | if ($jsond_prefix === 'jsond') {
20 | class SerializingTest extends NonSerializingTest implements JsondSerializable
21 | {
22 | public function jsonSerialize()
23 | {
24 | return $this->data;
25 | }
26 | }
27 | } else {
28 | class SerializingTest extends NonSerializingTest implements JsonSerializable
29 | {
30 | public function jsonSerialize()
31 | {
32 | return $this->data;
33 | }
34 | }
35 | }
36 |
37 | class ValueSerializingTest extends SerializingTest
38 | {
39 | public function jsonSerialize()
40 | {
41 | return array_values(is_array($this->data) ? $this->data : get_object_vars($this->data));
42 | }
43 | }
44 |
45 | class SelfSerializingTest extends SerializingTest
46 | {
47 | public function jsonSerialize()
48 | {
49 | return $this;
50 | }
51 | }
52 |
53 | $adata = array(
54 | 'str' => 'foo',
55 | 'int' => 1,
56 | 'float' => 2.3,
57 | 'bool' => false,
58 | 'nil' => null,
59 | 'arr' => array(1,2,3),
60 | 'obj' => new StdClass,
61 | );
62 |
63 | $ndata = array_values($adata);
64 |
65 | $odata = (object)$adata;
66 |
67 | foreach(array('NonSerializingTest','SerializingTest','ValueSerializingTest','SelfSerializingTest') as $class) {
68 | echo "==$class==\n";
69 | echo $jsond_encode(new $class($adata)), "\n";
70 | echo $jsond_encode(new $class($ndata)), "\n";
71 | echo $jsond_encode(new $class($odata)), "\n";
72 | }
73 | ?>
74 | --EXPECT--
75 | ==NonSerializingTest==
76 | {"data":{"str":"foo","int":1,"float":2.3,"bool":false,"nil":null,"arr":[1,2,3],"obj":{}}}
77 | {"data":["foo",1,2.3,false,null,[1,2,3],{}]}
78 | {"data":{"str":"foo","int":1,"float":2.3,"bool":false,"nil":null,"arr":[1,2,3],"obj":{}}}
79 | ==SerializingTest==
80 | {"str":"foo","int":1,"float":2.3,"bool":false,"nil":null,"arr":[1,2,3],"obj":{}}
81 | ["foo",1,2.3,false,null,[1,2,3],{}]
82 | {"str":"foo","int":1,"float":2.3,"bool":false,"nil":null,"arr":[1,2,3],"obj":{}}
83 | ==ValueSerializingTest==
84 | ["foo",1,2.3,false,null,[1,2,3],{}]
85 | ["foo",1,2.3,false,null,[1,2,3],{}]
86 | ["foo",1,2.3,false,null,[1,2,3],{}]
87 | ==SelfSerializingTest==
88 | {"data":{"str":"foo","int":1,"float":2.3,"bool":false,"nil":null,"arr":[1,2,3],"obj":{}}}
89 | {"data":["foo",1,2.3,false,null,[1,2,3],{}]}
90 | {"data":{"str":"foo","int":1,"float":2.3,"bool":false,"nil":null,"arr":[1,2,3],"obj":{}}}
91 |
92 |
93 |
--------------------------------------------------------------------------------
/tests/unsupported_type_error.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | An error is thrown when an unsupported type is encoded
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
20 | --EXPECTF--
21 | resource(%d) of type (stream)
22 | bool(false)
23 | int(8)
24 | string(21) "Type is not supported"
25 | string(4) "null"
26 | int(8)
27 | string(21) "Type is not supported"
28 |
--------------------------------------------------------------------------------
/utils/jsond_auto_complete.php:
--------------------------------------------------------------------------------
1 | 'doc',
9 | 'pattern' => 'CREDITS',
10 | ),
11 | array(
12 | 'role' => 'doc',
13 | 'pattern' => 'LICENSE',
14 | ),
15 | array(
16 | 'role' => 'doc',
17 | 'pattern' => '*.md',
18 | ),
19 | array(
20 | 'role' => 'src',
21 | 'pattern' => 'config.m4',
22 | ),
23 | array(
24 | 'role' => 'src',
25 | 'pattern' => 'config.w32',
26 | ),
27 | array(
28 | 'role' => 'src',
29 | 'pattern' => 'Makefile.frag',
30 | ),
31 | array(
32 | 'role' => 'src',
33 | 'pattern' => 'php_jsond*.h',
34 | ),
35 | array(
36 | 'role' => 'src',
37 | 'pattern' => 'jsond*.h',
38 | ),
39 | array(
40 | 'role' => 'src',
41 | 'pattern' => 'jsond*.c',
42 | ),
43 | array(
44 | 'role' => 'src',
45 | 'pattern' => 'jsond*.y',
46 | ),
47 | array(
48 | 'role' => 'src',
49 | 'pattern' => 'jsond*.re',
50 | ),
51 | array(
52 | 'dir' => 'tests',
53 | 'role' => 'test',
54 | 'pattern' => '*.phpt',
55 | ),
56 | array(
57 | 'dir' => 'tests',
58 | 'role' => 'test',
59 | 'pattern' => '*.inc',
60 | ),
61 | );
62 |
63 | function print_files($indent_str, $role, $pattern, $rel_dir = "") {
64 | if ($rel_dir)
65 | $rel_dir .= "/";
66 | $abs_dir = BASE_DIR . "/" . $rel_dir;
67 | foreach (glob($abs_dir . $pattern) as $path) {
68 | printf('%s%s', $indent_str, $role, substr($path, strlen($abs_dir)), "\n");
69 | }
70 | }
71 |
72 | $indent_str = str_repeat(' ', $indent);
73 | foreach ($conf as $e) {
74 | if (!isset($e['dir']))
75 | $e['dir'] = '';
76 | if ($e['dir']) {
77 | printf('%s%s', $indent_str, $e['dir'], "\n");
78 | $indent_str .= ' ';
79 | }
80 | print_files($indent_str, $e['role'], $e['pattern'], $e['dir']);
81 | if ($e['dir']) {
82 | $indent_str = str_repeat(' ', $indent);
83 | printf('%s%s', $indent_str, "\n");
84 | }
85 | }
86 |
87 |
--------------------------------------------------------------------------------