├── .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) ""a‪b"" 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 | --------------------------------------------------------------------------------