summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS30
-rw-r--r--Zend/tests/bug64960.phpt40
-rw-r--r--Zend/zend_compile.c2
-rw-r--r--Zend/zend_execute_API.c6
-rwxr-xr-xconfigure2
-rw-r--r--configure.in2
-rw-r--r--ext/fileinfo/tests/resources/test.mp3bin4280555 -> 25801 bytes
-rw-r--r--ext/gd/gd.c8
-rw-r--r--ext/gd/libgd/gd_interpolation.c28
-rw-r--r--ext/hash/hash.c3
-rw-r--r--ext/hash/tests/bug64745.phpt17
-rw-r--r--ext/json/CREDITS2
-rw-r--r--ext/json/JSON_parser.c759
-rw-r--r--ext/json/JSON_parser.h43
-rw-r--r--ext/json/README76
-rw-r--r--ext/json/config.m415
-rw-r--r--ext/json/config.w3211
-rw-r--r--ext/json/json.c872
-rw-r--r--ext/json/json.dsp135
-rw-r--r--ext/json/package.xml152
-rw-r--r--ext/json/php_json.h92
-rw-r--r--ext/json/tests/001.phpt71
-rw-r--r--ext/json/tests/002.phpt38
-rw-r--r--ext/json/tests/003.phpt41
-rw-r--r--ext/json/tests/004.phpt38
-rw-r--r--ext/json/tests/005.phpt23
-rw-r--r--ext/json/tests/006.phpt23
-rw-r--r--ext/json/tests/007.phpt40
-rw-r--r--ext/json/tests/008.phpt17
-rw-r--r--ext/json/tests/bug40503.phpt21
-rw-r--r--ext/json/tests/bug41034.phpt12
-rw-r--r--ext/json/tests/bug41067.phpt23
-rw-r--r--ext/json/tests/bug41403.phpt44
-rw-r--r--ext/json/tests/bug41504.phpt31
-rw-r--r--ext/json/tests/bug41567.phpt17
-rw-r--r--ext/json/tests/bug42090.phpt24
-rw-r--r--ext/json/tests/bug42785.phpt26
-rw-r--r--ext/json/tests/bug43941.phpt20
-rw-r--r--ext/json/tests/bug45791.phpt15
-rw-r--r--ext/json/tests/bug46215.phpt29
-rw-r--r--ext/json/tests/bug46944.phpt35
-rw-r--r--ext/json/tests/bug47644.phpt43
-rw-r--r--ext/json/tests/bug53946.phpt16
-rw-r--r--ext/json/tests/bug54058.phpt40
-rw-r--r--ext/json/tests/bug54484.phpt25
-rw-r--r--ext/json/tests/bug55543.phpt13
-rw-r--r--ext/json/tests/bug61537.phpt39
-rw-r--r--ext/json/tests/bug61978.phpt43
-rw-r--r--ext/json/tests/bug62369.phpt34
-rw-r--r--ext/json/tests/bug63737.phpt32
-rw-r--r--ext/json/tests/fail001.phpt166
-rw-r--r--ext/json/tests/inf_nan_error.phpt45
-rw-r--r--ext/json/tests/json_decode_basic.phpt187
-rw-r--r--ext/json/tests/json_decode_error.phpt39
-rw-r--r--ext/json/tests/json_encode_basic.phpt156
-rw-r--r--ext/json/tests/json_encode_basic_utf8.phpt26
-rw-r--r--ext/json/tests/json_encode_error.phpt38
-rw-r--r--ext/json/tests/json_encode_numeric.phpt26
-rw-r--r--ext/json/tests/json_encode_pretty_print.phpt40
-rw-r--r--ext/json/tests/json_encode_unescaped_slashes.phpt12
-rw-r--r--ext/json/tests/pass001.1.phpt890
-rw-r--r--ext/json/tests/pass001.1_64bit.phpt890
-rw-r--r--ext/json/tests/pass001.phpt702
-rw-r--r--ext/json/tests/pass002.phpt275
-rw-r--r--ext/json/tests/pass003.phpt94
-rw-r--r--ext/json/tests/serialize.phpt80
-rw-r--r--ext/json/tests/unsupported_type_error.phpt26
-rw-r--r--ext/json/utf8_decode.c179
-rw-r--r--ext/json/utf8_decode.h18
-rw-r--r--ext/opcache/shared_alloc_shm.c2
-rw-r--r--ext/opcache/zend_persist.c6
-rw-r--r--ext/opcache/zend_shared_alloc.c4
-rw-r--r--ext/opcache/zend_shared_alloc.h2
-rw-r--r--ext/pdo/tests/bug61292.phpt9
-rw-r--r--ext/pdo_dblib/dblib_driver.c103
-rw-r--r--ext/pdo_dblib/dblib_stmt.c99
-rw-r--r--ext/pdo_dblib/pdo_dblib.c8
-rw-r--r--ext/pdo_dblib/php_pdo_dblib_int.h8
-rw-r--r--ext/pdo_firebird/firebird_statement.c11
-rw-r--r--ext/pdo_firebird/tests/bug_62024.phpt51
-rw-r--r--ext/pdo_firebird/tests/bug_64037.phpt45
-rw-r--r--ext/pdo_pgsql/pgsql_driver.c2
-rw-r--r--ext/pdo_pgsql/tests/copy_from.phpt8
-rw-r--r--ext/pgsql/pgsql.c41
-rw-r--r--ext/pgsql/tests/10pg_convert_85.phpt1
-rw-r--r--ext/pgsql/tests/12pg_insert_85.phpt2
-rw-r--r--ext/pgsql/tests/14pg_update_85.phpt2
-rw-r--r--ext/pgsql/tests/18pg_escape_bytea.phpt3
-rw-r--r--ext/pgsql/tests/bug64609.phpt30
-rw-r--r--ext/standard/quot_print.c4
-rw-r--r--ext/standard/tests/strings/bug64879.phpt12
-rw-r--r--main/php_version.h4
-rw-r--r--sapi/fpm/fpm/fpm_stdio.c4
93 files changed, 7411 insertions, 107 deletions
diff --git a/NEWS b/NEWS
index 543044f54..75f26b415 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,35 @@
PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+06 Jun 2013, PHP 5.5.0 Release Candidate 3
+
+- Core:
+ . Fixed bug #64960 (Segfault in gc_zval_possible_root). (Laruence)
+ . Fixed bug #64879 (Heap based buffer overflow in quoted_printable_encode,
+ CVE 2013-2110). (Stas)
+
+- FPM:
+ . Fixed Bug #64915 (error_log ignored when daemonize=0). (Remi)
+
+- GD:
+ . Fixed Bug #64962 (imagerotate produces corrupted image). (Remi)
+ . Fixed Bug #64961 (segfault in imagesetinterpolation). (Remi)
+
+- Hash:
+ . Fixed Bug #64745 (hash_pbkdf2() truncates data when using default length
+ and hex output). (Anthony Ferrara)
+
+- PDO_DBlib:
+ . Fixed bug #63638 (Cannot connect to SQL Server 2008 with PDO dblib).
+ (Stanley Sufficool)
+ . Fixed bug #64338 (pdo_dblib can't connect to Azure SQL). (Stanley
+ Sufficool)
+ . Fixed bug #64808 (FreeTDS PDO getColumnMeta on a prepared but not executed
+ statement crashes). (Stanley Sufficool)
+
+- PDO_pgsql:
+ . Fixed Bug #64949 (Buffer overflow in _pdo_pgsql_error). (Remi)
+
+
23 May 2013, PHP 5.5.0 Release Candidate 2
- Core:
diff --git a/Zend/tests/bug64960.phpt b/Zend/tests/bug64960.phpt
new file mode 100644
index 000000000..b31cca3dc
--- /dev/null
+++ b/Zend/tests/bug64960.phpt
@@ -0,0 +1,40 @@
+--TEST--
+Bug #64960 (Segfault in gc_zval_possible_root)
+--FILE--
+<?php
+// this makes ob_end_clean raise an error
+ob_end_flush();
+
+class ExceptionHandler {
+ public function __invoke (Exception $e)
+ {
+ // this triggers the custom error handler
+ ob_end_clean();
+ }
+}
+
+// this must be a class, closure does not trigger segfault
+set_exception_handler(new ExceptionHandler());
+
+// exception must be throwed from error handler.
+set_error_handler(function()
+{
+ $e = new Exception;
+ $e->_trace = debug_backtrace();
+
+ throw $e;
+});
+
+// trigger error handler
+$a['waa'];
+?>
+--EXPECTF--
+Notice: ob_end_flush(): failed to delete and flush buffer. No buffer to delete or flush in %sbug64960.php on line 3
+
+Fatal error: Uncaught exception 'Exception' in %sbug64960.php:19
+Stack trace:
+#0 [internal function]: {closure}(8, 'ob_end_clean():...', '%s', 9, Array)
+#1 %sbug64960.php(9): ob_end_clean()
+#2 [internal function]: ExceptionHandler->__invoke(Object(Exception))
+#3 {main}
+ thrown in %sbug64960.php on line 19
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index 862f82da0..8674f9247 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -5687,7 +5687,7 @@ void zend_do_shell_exec(znode *result, const znode *cmd TSRMLS_DC) /* {{{ */
break;
}
SET_NODE(opline->op1, cmd);
- opline->op2.opline_num = 0;
+ opline->op2.opline_num = 1;
opline->extended_value = ZEND_DO_FCALL;
SET_UNUSED(opline->op2);
diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c
index 8739e21c2..d831b107a 100644
--- a/Zend/zend_execute_API.c
+++ b/Zend/zend_execute_API.c
@@ -254,15 +254,13 @@ void shutdown_executor(TSRMLS_D) /* {{{ */
if (EG(user_error_handler)) {
zeh = EG(user_error_handler);
EG(user_error_handler) = NULL;
- zval_dtor(zeh);
- FREE_ZVAL(zeh);
+ zval_ptr_dtor(&zeh);
}
if (EG(user_exception_handler)) {
zeh = EG(user_exception_handler);
EG(user_exception_handler) = NULL;
- zval_dtor(zeh);
- FREE_ZVAL(zeh);
+ zval_ptr_dtor(&zeh);
}
zend_stack_destroy(&EG(user_error_handlers_error_reporting));
diff --git a/configure b/configure
index 7b0bb3e0f..5df7e5679 100755
--- a/configure
+++ b/configure
@@ -3687,7 +3687,7 @@ ac_config_headers="$ac_config_headers main/php_config.h"
PHP_MAJOR_VERSION=5
PHP_MINOR_VERSION=5
PHP_RELEASE_VERSION=0
-PHP_EXTRA_VERSION="RC2"
+PHP_EXTRA_VERSION="RC3"
PHP_VERSION="$PHP_MAJOR_VERSION.$PHP_MINOR_VERSION.$PHP_RELEASE_VERSION$PHP_EXTRA_VERSION"
PHP_VERSION_ID=`expr $PHP_MAJOR_VERSION \* 10000 + $PHP_MINOR_VERSION \* 100 + $PHP_RELEASE_VERSION`
diff --git a/configure.in b/configure.in
index 0a6bc5088..ed4afb9e4 100644
--- a/configure.in
+++ b/configure.in
@@ -120,7 +120,7 @@ int zend_sprintf(char *buffer, const char *format, ...);
PHP_MAJOR_VERSION=5
PHP_MINOR_VERSION=5
PHP_RELEASE_VERSION=0
-PHP_EXTRA_VERSION="RC2"
+PHP_EXTRA_VERSION="RC3"
PHP_VERSION="$PHP_MAJOR_VERSION.$PHP_MINOR_VERSION.$PHP_RELEASE_VERSION$PHP_EXTRA_VERSION"
PHP_VERSION_ID=`expr [$]PHP_MAJOR_VERSION \* 10000 + [$]PHP_MINOR_VERSION \* 100 + [$]PHP_RELEASE_VERSION`
diff --git a/ext/fileinfo/tests/resources/test.mp3 b/ext/fileinfo/tests/resources/test.mp3
index 0b534374b..ff6dc3ad7 100644
--- a/ext/fileinfo/tests/resources/test.mp3
+++ b/ext/fileinfo/tests/resources/test.mp3
Binary files differ
diff --git a/ext/gd/gd.c b/ext/gd/gd.c
index d6d2848d4..73434307c 100644
--- a/ext/gd/gd.c
+++ b/ext/gd/gd.c
@@ -5212,7 +5212,7 @@ PHP_FUNCTION(imageaffine)
PHP_FUNCTION(imageaffinematrixget)
{
double affine[6];
- gdAffineStandardMatrix type;
+ long type;
zval *options;
zval **tmp;
int res = GD_FALSE, i;
@@ -5221,7 +5221,7 @@ PHP_FUNCTION(imageaffinematrixget)
return;
}
- switch(type) {
+ switch((gdAffineStandardMatrix)type) {
case GD_AFFINE_TRANSLATE:
case GD_AFFINE_SCALE: {
double x, y;
@@ -5271,7 +5271,7 @@ PHP_FUNCTION(imageaffinematrixget)
}
default:
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid type for element %i", type);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid type for element %li", type);
RETURN_FALSE;
}
@@ -5361,7 +5361,7 @@ PHP_FUNCTION(imagesetinterpolation)
{
zval *IM;
gdImagePtr im;
- gdInterpolationMethod method = GD_BILINEAR_FIXED;
+ long method = GD_BILINEAR_FIXED;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &IM, &method) == FAILURE) {
return;
diff --git a/ext/gd/libgd/gd_interpolation.c b/ext/gd/libgd/gd_interpolation.c
index 6c5549eba..9652a3a18 100644
--- a/ext/gd/libgd/gd_interpolation.c
+++ b/ext/gd/libgd/gd_interpolation.c
@@ -1690,8 +1690,8 @@ gdImagePtr gdImageRotateNearestNeighbour(gdImagePtr src, const float degrees, co
unsigned int j;
dst_offset_x = 0;
for (j = 0; j < new_width; j++) {
- gdFixed f_i = gd_itofx(i - new_height/2);
- gdFixed f_j = gd_itofx(j-new_width/2);
+ gdFixed f_i = gd_itofx((int)i - (int)new_height/2);
+ gdFixed f_j = gd_itofx((int)j - (int)new_width/2);
gdFixed f_m = gd_mulfx(f_j,f_sin) + gd_mulfx(f_i,f_cos) + f_0_5 + f_H;
gdFixed f_n = gd_mulfx(f_j,f_cos) - gd_mulfx(f_i,f_sin) + f_0_5 + f_W;
long m = gd_fxtoi(f_m);
@@ -1753,8 +1753,8 @@ gdImagePtr gdImageRotateGeneric(gdImagePtr src, const float degrees, const int b
unsigned int j;
dst_offset_x = 0;
for (j = 0; j < new_width; j++) {
- gdFixed f_i = gd_itofx(i - new_height/ 2);
- gdFixed f_j = gd_itofx(j -new_width / 2);
+ gdFixed f_i = gd_itofx((int)i - (int)new_height/ 2);
+ gdFixed f_j = gd_itofx((int)j - (int)new_width / 2);
gdFixed f_m = gd_mulfx(f_j,f_sin) + gd_mulfx(f_i,f_cos) + f_0_5 + f_H;
gdFixed f_n = gd_mulfx(f_j,f_cos) - gd_mulfx(f_i,f_sin) + f_0_5 + f_W;
long m = gd_fxtoi(f_m);
@@ -1814,8 +1814,8 @@ gdImagePtr gdImageRotateBilinear(gdImagePtr src, const float degrees, const int
dst_offset_x = 0;
for (j=0; j < new_width; j++) {
- const gdFixed f_i = gd_itofx(i-new_height/2);
- const gdFixed f_j = gd_itofx(j-new_width/2);
+ const gdFixed f_i = gd_itofx((int)i - (int)new_height/2);
+ const gdFixed f_j = gd_itofx((int)j - (int)new_width/2);
const gdFixed f_m = gd_mulfx(f_j,f_sin) + gd_mulfx(f_i,f_cos) + f_0_5 + f_H;
const gdFixed f_n = gd_mulfx(f_j,f_cos) - gd_mulfx(f_i,f_sin) + f_0_5 + f_W;
const unsigned int m = gd_fxtoi(f_m);
@@ -1830,18 +1830,18 @@ gdImagePtr gdImageRotateBilinear(gdImagePtr src, const float degrees, const int
const gdFixed f_w4 = gd_mulfx(f_f, f_g);
if (n < src_w - 1) {
- src_offset_x = m + 1;
- src_offset_y = n;
+ src_offset_x = n + 1;
+ src_offset_y = m;
}
if (m < src_h-1) {
- src_offset_x = m;
- src_offset_y = n + 1;
+ src_offset_x = n;
+ src_offset_y = m + 1;
}
if (!((n >= src_w-1) || (m >= src_h-1))) {
- src_offset_x = m + 1;
- src_offset_y = n + 1;
+ src_offset_x = n + 1;
+ src_offset_y = m + 1;
}
{
const int pixel1 = src->tpixels[src_offset_y][src_offset_x];
@@ -1941,8 +1941,8 @@ gdImagePtr gdImageRotateBicubicFixed(gdImagePtr src, const float degrees, const
dst_offset_x = 0;
for (j=0; j < new_width; j++) {
- const gdFixed f_i = gd_itofx(i-new_height/2);
- const gdFixed f_j = gd_itofx(j-new_width/2);
+ const gdFixed f_i = gd_itofx((int)i - (int)new_height/2);
+ const gdFixed f_j = gd_itofx((int)j - (int)new_width/2);
const gdFixed f_m = gd_mulfx(f_j,f_sin) + gd_mulfx(f_i,f_cos) + f_0_5 + f_H;
const gdFixed f_n = gd_mulfx(f_j,f_cos) - gd_mulfx(f_i,f_sin) + f_0_5 + f_W;
const int m = gd_fxtoi(f_m);
diff --git a/ext/hash/hash.c b/ext/hash/hash.c
index 9492387db..9cede1412 100644
--- a/ext/hash/hash.c
+++ b/ext/hash/hash.c
@@ -659,6 +659,9 @@ PHP_FUNCTION(hash_pbkdf2)
/* Setup Main Loop to build a long enough result */
if (length == 0) {
length = ops->digest_size;
+ if (!raw_output) {
+ length = length * 2;
+ }
}
digest_length = length;
if (!raw_output) {
diff --git a/ext/hash/tests/bug64745.phpt b/ext/hash/tests/bug64745.phpt
new file mode 100644
index 000000000..427f89b72
--- /dev/null
+++ b/ext/hash/tests/bug64745.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Bug #64745 hash_pbkdf2() truncates data when using default length and hex output
+--SKIPIF--
+<?php extension_loaded('hash') or die('skip'); ?>
+--FILE--
+<?php
+$hash = hash_pbkdf2('sha1', 'password', 'salt', 1, 0);
+$rawHash = hash_pbkdf2('sha1', 'password', 'salt', 1, 0, true);
+
+var_dump($hash);
+var_dump(bin2hex($rawHash));
+
+?>
+--EXPECT--
+string(40) "0c60c80f961f0e71f3a9b524af6012062fe037a6"
+string(40) "0c60c80f961f0e71f3a9b524af6012062fe037a6"
+
diff --git a/ext/json/CREDITS b/ext/json/CREDITS
new file mode 100644
index 000000000..9bd7f44f2
--- /dev/null
+++ b/ext/json/CREDITS
@@ -0,0 +1,2 @@
+JSON
+Omar Kilani, Scott MacVicar
diff --git a/ext/json/JSON_parser.c b/ext/json/JSON_parser.c
new file mode 100644
index 000000000..dd832a7cb
--- /dev/null
+++ b/ext/json/JSON_parser.c
@@ -0,0 +1,759 @@
+/* JSON_parser.c */
+
+/* 2005-12-30 */
+
+/*
+Copyright (c) 2005 JSON.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+#include <stdio.h>
+#include "JSON_parser.h"
+
+/* Windows defines IN for documentation */
+#undef IN
+
+#define true 1
+#define false 0
+#define __ -1 /* the universal error code */
+
+/*
+ Characters are mapped into these 31 character classes. This allows for
+ a significant reduction in the size of the state transition table.
+*/
+
+enum classes {
+ C_SPACE, /* space */
+ C_WHITE, /* other whitespace */
+ C_LCURB, /* { */
+ C_RCURB, /* } */
+ C_LSQRB, /* [ */
+ C_RSQRB, /* ] */
+ C_COLON, /* : */
+ C_COMMA, /* , */
+ C_QUOTE, /* " */
+ C_BACKS, /* \ */
+ C_SLASH, /* / */
+ C_PLUS, /* + */
+ C_MINUS, /* - */
+ C_POINT, /* . */
+ C_ZERO , /* 0 */
+ C_DIGIT, /* 123456789 */
+ C_LOW_A, /* a */
+ C_LOW_B, /* b */
+ C_LOW_C, /* c */
+ C_LOW_D, /* d */
+ C_LOW_E, /* e */
+ C_LOW_F, /* f */
+ C_LOW_L, /* l */
+ C_LOW_N, /* n */
+ C_LOW_R, /* r */
+ C_LOW_S, /* s */
+ C_LOW_T, /* t */
+ C_LOW_U, /* u */
+ C_ABCDF, /* ABCDF */
+ C_E, /* E */
+ C_ETC, /* everything else */
+ NR_CLASSES
+};
+
+static const int ascii_class[128] = {
+/*
+ This array maps the 128 ASCII characters into character classes.
+ The remaining Unicode characters should be mapped to C_ETC.
+ Non-whitespace control characters are errors.
+*/
+ __, __, __, __, __, __, __, __,
+ __, C_WHITE, C_WHITE, __, __, C_WHITE, __, __,
+ __, __, __, __, __, __, __, __,
+ __, __, __, __, __, __, __, __,
+
+ C_SPACE, C_ETC, C_QUOTE, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC,
+ C_ETC, C_ETC, C_ETC, C_PLUS, C_COMMA, C_MINUS, C_POINT, C_SLASH,
+ C_ZERO, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT,
+ C_DIGIT, C_DIGIT, C_COLON, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC,
+
+ C_ETC, C_ABCDF, C_ABCDF, C_ABCDF, C_ABCDF, C_E, C_ABCDF, C_ETC,
+ C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC,
+ C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC,
+ C_ETC, C_ETC, C_ETC, C_LSQRB, C_BACKS, C_RSQRB, C_ETC, C_ETC,
+
+ C_ETC, C_LOW_A, C_LOW_B, C_LOW_C, C_LOW_D, C_LOW_E, C_LOW_F, C_ETC,
+ C_ETC, C_ETC, C_ETC, C_ETC, C_LOW_L, C_ETC, C_LOW_N, C_ETC,
+ C_ETC, C_ETC, C_LOW_R, C_LOW_S, C_LOW_T, C_LOW_U, C_ETC, C_ETC,
+ C_ETC, C_ETC, C_ETC, C_LCURB, C_ETC, C_RCURB, C_ETC, C_ETC
+};
+
+
+/*
+ The state codes.
+*/
+enum states {
+ GO, /* start */
+ OK, /* ok */
+ OB, /* object */
+ KE, /* key */
+ CO, /* colon */
+ VA, /* value */
+ AR, /* array */
+ ST, /* string */
+ ES, /* escape */
+ U1, /* u1 */
+ U2, /* u2 */
+ U3, /* u3 */
+ U4, /* u4 */
+ MI, /* minus */
+ ZE, /* zero */
+ IN, /* integer */
+ FR, /* fraction */
+ E1, /* e */
+ E2, /* ex */
+ E3, /* exp */
+ T1, /* tr */
+ T2, /* tru */
+ T3, /* true */
+ F1, /* fa */
+ F2, /* fal */
+ F3, /* fals */
+ F4, /* false */
+ N1, /* nu */
+ N2, /* nul */
+ N3, /* null */
+ NR_STATES
+};
+
+
+static const int state_transition_table[NR_STATES][NR_CLASSES] = {
+/*
+ The state transition table takes the current state and the current symbol,
+ and returns either a new state or an action. An action is represented as a
+ negative number. A JSON text is accepted if at the end of the text the
+ state is OK and if the mode is MODE_DONE.
+
+ white 1-9 ABCDF etc
+ space | { } [ ] : , " \ / + - . 0 | a b c d e f l n r s t u | E |*/
+/*start GO*/ {GO,GO,-6,__,-5,__,__,__,ST,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
+/*ok OK*/ {OK,OK,__,-8,__,-7,__,-3,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
+/*object OB*/ {OB,OB,__,-9,__,__,__,__,ST,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
+/*key KE*/ {KE,KE,__,__,__,__,__,__,ST,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
+/*colon CO*/ {CO,CO,__,__,__,__,-2,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
+/*value VA*/ {VA,VA,-6,__,-5,__,__,__,ST,__,__,__,MI,__,ZE,IN,__,__,__,__,__,F1,__,N1,__,__,T1,__,__,__,__},
+/*array AR*/ {AR,AR,-6,__,-5,-7,__,__,ST,__,__,__,MI,__,ZE,IN,__,__,__,__,__,F1,__,N1,__,__,T1,__,__,__,__},
+/*string ST*/ {ST,__,ST,ST,ST,ST,ST,ST,-4,ES,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST},
+/*escape ES*/ {__,__,__,__,__,__,__,__,ST,ST,ST,__,__,__,__,__,__,ST,__,__,__,ST,__,ST,ST,__,ST,U1,__,__,__},
+/*u1 U1*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,U2,U2,U2,U2,U2,U2,U2,U2,__,__,__,__,__,__,U2,U2,__},
+/*u2 U2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,U3,U3,U3,U3,U3,U3,U3,U3,__,__,__,__,__,__,U3,U3,__},
+/*u3 U3*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,U4,U4,U4,U4,U4,U4,U4,U4,__,__,__,__,__,__,U4,U4,__},
+/*u4 U4*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,ST,ST,ST,ST,ST,ST,ST,ST,__,__,__,__,__,__,ST,ST,__},
+/*minus MI*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,ZE,IN,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
+/*zero ZE*/ {OK,OK,__,-8,__,-7,__,-3,__,__,__,__,__,FR,__,__,__,__,__,__,E1,__,__,__,__,__,__,__,__,E1,__},
+/*int IN*/ {OK,OK,__,-8,__,-7,__,-3,__,__,__,__,__,FR,IN,IN,__,__,__,__,E1,__,__,__,__,__,__,__,__,E1,__},
+/*frac FR*/ {OK,OK,__,-8,__,-7,__,-3,__,__,__,__,__,__,FR,FR,__,__,__,__,E1,__,__,__,__,__,__,__,__,E1,__},
+/*e E1*/ {__,__,__,__,__,__,__,__,__,__,__,E2,E2,__,E3,E3,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
+/*ex E2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,E3,E3,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
+/*exp E3*/ {OK,OK,__,-8,__,-7,__,-3,__,__,__,__,__,__,E3,E3,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
+/*tr T1*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,T2,__,__,__,__,__,__},
+/*tru T2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,T3,__,__,__},
+/*true T3*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,OK,__,__,__,__,__,__,__,__,__,__},
+/*fa F1*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,F2,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
+/*fal F2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,F3,__,__,__,__,__,__,__,__},
+/*fals F3*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,F4,__,__,__,__,__},
+/*false F4*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,OK,__,__,__,__,__,__,__,__,__,__},
+/*nu N1*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,N2,__,__,__},
+/*nul N2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,N3,__,__,__,__,__,__,__,__},
+/*null N3*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,OK,__,__,__,__,__,__,__,__},
+};
+
+
+/*
+ These modes can be pushed on the stack.
+*/
+enum modes {
+ MODE_ARRAY,
+ MODE_DONE,
+ MODE_KEY,
+ MODE_OBJECT,
+};
+
+
+/*
+ Push a mode onto the stack. Return false if there is overflow.
+*/
+static int
+push(JSON_parser jp, int mode)
+{
+ jp->top += 1;
+ if (jp->top >= jp->depth) {
+ jp->error_code = PHP_JSON_ERROR_DEPTH;
+ return false;
+ }
+ jp->stack[jp->top] = mode;
+ return true;
+}
+
+
+/*
+ Pop the stack, assuring that the current mode matches the expectation.
+ Return false if there is underflow or if the modes mismatch.
+*/
+static int
+pop(JSON_parser jp, int mode)
+{
+ if (jp->top < 0 || jp->stack[jp->top] != mode) {
+ jp->error_code = PHP_JSON_ERROR_STATE_MISMATCH;
+ return false;
+ }
+ jp->top -= 1;
+ return true;
+}
+
+/*
+ new_JSON_checker starts the checking process by constructing a JSON_checker
+ object. It takes a depth parameter that restricts the level of maximum
+ nesting.
+
+ To continue the process, call JSON_checker_char for each character in the
+ JSON text, and then call JSON_checker_done to obtain the final result.
+ These functions are fully reentrant.
+
+ The JSON_checker object will be deleted by JSON_checker_done.
+ JSON_checker_char will delete the JSON_checker object if it sees an error.
+*/
+JSON_parser
+new_JSON_parser(int depth)
+{
+ JSON_parser jp = (JSON_parser)emalloc(sizeof(struct JSON_parser_struct));
+ jp->state = GO;
+ jp->depth = depth;
+ jp->top = -1;
+ jp->error_code = PHP_JSON_ERROR_NONE;
+ jp->stack = (int*)ecalloc(depth, sizeof(int));
+ if (depth > JSON_PARSER_DEFAULT_DEPTH) {
+ jp->the_zstack = (zval **)safe_emalloc(depth, sizeof(zval), 0);
+ } else {
+ jp->the_zstack = &jp->the_static_zstack[0];
+ }
+ push(jp, MODE_DONE);
+ return jp;
+}
+
+/*
+ Delete the JSON_parser object.
+*/
+int
+free_JSON_parser(JSON_parser jp)
+{
+ efree((void*)jp->stack);
+ if (jp->the_zstack != &jp->the_static_zstack[0]) {
+ efree(jp->the_zstack);
+ }
+ efree((void*)jp);
+ return false;
+}
+
+static int dehexchar(char c)
+{
+ if (c >= '0' && c <= '9')
+ {
+ return c - '0';
+ }
+ else if (c >= 'A' && c <= 'F')
+ {
+ return c - ('A' - 10);
+ }
+ else if (c >= 'a' && c <= 'f')
+ {
+ return c - ('a' - 10);
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+
+static void json_create_zval(zval **z, smart_str *buf, int type, int options)
+{
+ ALLOC_INIT_ZVAL(*z);
+
+ if (type == IS_LONG)
+ {
+ zend_bool bigint = 0;
+
+ if (buf->c[0] == '-') {
+ buf->len--;
+ }
+
+ if (buf->len >= MAX_LENGTH_OF_LONG - 1) {
+ if (buf->len == MAX_LENGTH_OF_LONG - 1) {
+ int cmp = strcmp(buf->c + (buf->c[0] == '-'), long_min_digits);
+
+ if (!(cmp < 0 || (cmp == 0 && buf->c[0] == '-'))) {
+ bigint = 1;
+ }
+ } else {
+ bigint = 1;
+ }
+ }
+
+ if (bigint) {
+ /* value too large to represent as a long */
+ if (options & PHP_JSON_BIGINT_AS_STRING) {
+ if (buf->c[0] == '-') {
+ /* Restore last char consumed above */
+ buf->len++;
+ }
+ goto use_string;
+ } else {
+ goto use_double;
+ }
+ }
+
+ ZVAL_LONG(*z, strtol(buf->c, NULL, 10));
+ }
+ else if (type == IS_DOUBLE)
+ {
+use_double:
+ ZVAL_DOUBLE(*z, zend_strtod(buf->c, NULL));
+ }
+ else if (type == IS_STRING)
+ {
+use_string:
+ ZVAL_STRINGL(*z, buf->c, buf->len, 1);
+ }
+ else if (type == IS_BOOL)
+ {
+ ZVAL_BOOL(*z, (*(buf->c) == 't'));
+ }
+ else /* type == IS_NULL) || type unknown */
+ {
+ ZVAL_NULL(*z);
+ }
+}
+
+
+static void utf16_to_utf8(smart_str *buf, unsigned short utf16)
+{
+ if (utf16 < 0x80)
+ {
+ smart_str_appendc(buf, (unsigned char) utf16);
+ }
+ else if (utf16 < 0x800)
+ {
+ smart_str_appendc(buf, 0xc0 | (utf16 >> 6));
+ smart_str_appendc(buf, 0x80 | (utf16 & 0x3f));
+ }
+ else if ((utf16 & 0xfc00) == 0xdc00
+ && buf->len >= 3
+ && ((unsigned char) buf->c[buf->len - 3]) == 0xed
+ && ((unsigned char) buf->c[buf->len - 2] & 0xf0) == 0xa0
+ && ((unsigned char) buf->c[buf->len - 1] & 0xc0) == 0x80)
+ {
+ /* found surrogate pair */
+ unsigned long utf32;
+
+ utf32 = (((buf->c[buf->len - 2] & 0xf) << 16)
+ | ((buf->c[buf->len - 1] & 0x3f) << 10)
+ | (utf16 & 0x3ff)) + 0x10000;
+ buf->len -= 3;
+
+ smart_str_appendc(buf, (unsigned char) (0xf0 | (utf32 >> 18)));
+ smart_str_appendc(buf, 0x80 | ((utf32 >> 12) & 0x3f));
+ smart_str_appendc(buf, 0x80 | ((utf32 >> 6) & 0x3f));
+ smart_str_appendc(buf, 0x80 | (utf32 & 0x3f));
+ }
+ else
+ {
+ smart_str_appendc(buf, 0xe0 | (utf16 >> 12));
+ smart_str_appendc(buf, 0x80 | ((utf16 >> 6) & 0x3f));
+ smart_str_appendc(buf, 0x80 | (utf16 & 0x3f));
+ }
+}
+
+static void attach_zval(JSON_parser jp, int up, int cur, smart_str *key, int assoc TSRMLS_DC)
+{
+ zval *root = jp->the_zstack[up];
+ zval *child = jp->the_zstack[cur];
+ int up_mode = jp->stack[up];
+
+ if (up_mode == MODE_ARRAY)
+ {
+ add_next_index_zval(root, child);
+ }
+ else if (up_mode == MODE_OBJECT)
+ {
+ if (!assoc)
+ {
+ add_property_zval_ex(root, (key->len ? key->c : "_empty_"), (key->len ? (key->len + 1) : sizeof("_empty_")), child TSRMLS_CC);
+ Z_DELREF_P(child);
+ }
+ else
+ {
+ add_assoc_zval_ex(root, (key->len ? key->c : ""), (key->len ? (key->len + 1) : sizeof("")), child);
+ }
+ key->len = 0;
+ }
+}
+
+
+#define FREE_BUFFERS() smart_str_free(&buf); smart_str_free(&key);
+#define SWAP_BUFFERS(from, to) do { \
+ char *t1 = from.c; \
+ int t2 = from.a; \
+ from.c = to.c; \
+ from.a = to.a; \
+ to.c = t1; \
+ to.a = t2; \
+ to.len = from.len; \
+ from.len = 0; \
+ } while(0);
+#define JSON_RESET_TYPE() type = -1;
+
+/*
+ The JSON_parser takes a UTF-16 encoded string and determines if it is a
+ syntactically correct JSON text. Along the way, it creates a PHP variable.
+
+ It is implemented as a Pushdown Automaton; that means it is a finite state
+ machine with a stack.
+*/
+int
+parse_JSON_ex(JSON_parser jp, zval *z, unsigned short utf16_json[], int length, int options TSRMLS_DC)
+{
+ int next_char; /* the next character */
+ int next_class; /* the next character class */
+ int next_state; /* the next state */
+ int the_index;
+ int assoc = options & PHP_JSON_OBJECT_AS_ARRAY;
+
+ smart_str buf = {0};
+ smart_str key = {0};
+
+ unsigned short utf16 = 0;
+ int type;
+
+ JSON_RESET_TYPE();
+
+ for (the_index = 0; the_index < length; the_index += 1) {
+ next_char = utf16_json[the_index];
+ if (next_char >= 128) {
+ next_class = C_ETC;
+ } else {
+ next_class = ascii_class[next_char];
+ if (next_class <= __) {
+ jp->error_code = PHP_JSON_ERROR_CTRL_CHAR;
+ FREE_BUFFERS();
+ return false;
+ }
+ }
+/*
+ Get the next state from the transition table.
+*/
+ next_state = state_transition_table[jp->state][next_class];
+ if (next_state >= 0) {
+/*
+ Change the state and iterate
+*/
+ if (type == IS_STRING) {
+ if (next_state == ST && jp->state != U4) {
+ if (jp->state != ES) {
+ utf16_to_utf8(&buf, next_char);
+ } else {
+ switch (next_char) {
+ case 'b':
+ smart_str_appendc(&buf, '\b');
+ break;
+ case 't':
+ smart_str_appendc(&buf, '\t');
+ break;
+ case 'n':
+ smart_str_appendc(&buf, '\n');
+ break;
+ case 'f':
+ smart_str_appendc(&buf, '\f');
+ break;
+ case 'r':
+ smart_str_appendc(&buf, '\r');
+ break;
+ default:
+ utf16_to_utf8(&buf, next_char);
+ break;
+ }
+ }
+ } else if (next_state == U2) {
+ utf16 = dehexchar(next_char) << 12;
+ } else if (next_state == U3) {
+ utf16 += dehexchar(next_char) << 8;
+ } else if (next_state == U4) {
+ utf16 += dehexchar(next_char) << 4;
+ } else if (next_state == ST && jp->state == U4) {
+ utf16 += dehexchar(next_char);
+ utf16_to_utf8(&buf, utf16);
+ }
+ } else if (type < IS_LONG && (next_class == C_DIGIT || next_class == C_ZERO)) {
+ type = IS_LONG;
+ smart_str_appendc(&buf, next_char);
+ } else if (type == IS_LONG && next_state == E1) {
+ type = IS_DOUBLE;
+ smart_str_appendc(&buf, next_char);
+ } else if (type < IS_DOUBLE && next_class == C_POINT) {
+ type = IS_DOUBLE;
+ smart_str_appendc(&buf, next_char);
+ } else if (type < IS_STRING && next_class == C_QUOTE) {
+ type = IS_STRING;
+ } else if (type < IS_BOOL && ((jp->state == T3 && next_state == OK) || (jp->state == F4 && next_state == OK))) {
+ type = IS_BOOL;
+ } else if (type < IS_NULL && jp->state == N3 && next_state == OK) {
+ type = IS_NULL;
+ } else if (type != IS_STRING && next_class > C_WHITE) {
+ utf16_to_utf8(&buf, next_char);
+ }
+ jp->state = next_state;
+ } else {
+/*
+ Perform one of the predefined actions.
+*/
+ switch (next_state) {
+/* empty } */
+ case -9:
+ if (!pop(jp, MODE_KEY)) {
+ FREE_BUFFERS();
+ return false;
+ }
+ jp->state = OK;
+ break;
+/* } */
+ case -8:
+ if (type != -1 && jp->stack[jp->top] == MODE_OBJECT)
+ {
+ zval *mval;
+ smart_str_0(&buf);
+
+ json_create_zval(&mval, &buf, type, options);
+
+ if (!assoc) {
+ add_property_zval_ex(jp->the_zstack[jp->top], (key.len ? key.c : "_empty_"), (key.len ? (key.len + 1) : sizeof("_empty_")), mval TSRMLS_CC);
+ Z_DELREF_P(mval);
+ } else {
+ add_assoc_zval_ex(jp->the_zstack[jp->top], (key.len ? key.c : ""), (key.len ? (key.len + 1) : sizeof("")), mval);
+ }
+ key.len = 0;
+ buf.len = 0;
+ JSON_RESET_TYPE();
+ }
+
+
+ if (!pop(jp, MODE_OBJECT)) {
+ FREE_BUFFERS();
+ return false;
+ }
+ jp->state = OK;
+ break;
+/* ] */
+ case -7:
+ {
+ if (type != -1 && jp->stack[jp->top] == MODE_ARRAY)
+ {
+ zval *mval;
+ smart_str_0(&buf);
+
+ json_create_zval(&mval, &buf, type, options);
+ add_next_index_zval(jp->the_zstack[jp->top], mval);
+ buf.len = 0;
+ JSON_RESET_TYPE();
+ }
+
+ if (!pop(jp, MODE_ARRAY)) {
+ FREE_BUFFERS();
+ return false;
+ }
+ jp->state = OK;
+ }
+ break;
+/* { */
+ case -6:
+ if (!push(jp, MODE_KEY)) {
+ FREE_BUFFERS();
+ return false;
+ }
+
+ jp->state = OB;
+ if (jp->top > 0) {
+ zval *obj;
+
+ if (jp->top == 1) {
+ obj = z;
+ } else {
+ ALLOC_INIT_ZVAL(obj);
+ }
+
+ if (!assoc) {
+ object_init(obj);
+ } else {
+ array_init(obj);
+ }
+
+ jp->the_zstack[jp->top] = obj;
+
+ if (jp->top > 1) {
+ attach_zval(jp, jp->top - 1, jp->top, &key, assoc TSRMLS_CC);
+ }
+
+ JSON_RESET_TYPE();
+ }
+
+ break;
+/* [ */
+ case -5:
+ if (!push(jp, MODE_ARRAY)) {
+ FREE_BUFFERS();
+ return false;
+ }
+ jp->state = AR;
+
+ if (jp->top > 0) {
+ zval *arr;
+
+ if (jp->top == 1) {
+ arr = z;
+ } else {
+ ALLOC_INIT_ZVAL(arr);
+ }
+
+ array_init(arr);
+ jp->the_zstack[jp->top] = arr;
+
+ if (jp->top > 1) {
+ attach_zval(jp, jp->top - 1, jp->top, &key, assoc TSRMLS_CC);
+ }
+
+ JSON_RESET_TYPE();
+ }
+
+ break;
+
+/* " */
+ case -4:
+ switch (jp->stack[jp->top]) {
+ case MODE_KEY:
+ jp->state = CO;
+ smart_str_0(&buf);
+ SWAP_BUFFERS(buf, key);
+ JSON_RESET_TYPE();
+ break;
+ case MODE_ARRAY:
+ case MODE_OBJECT:
+ jp->state = OK;
+ break;
+ case MODE_DONE:
+ if (type == IS_STRING) {
+ smart_str_0(&buf);
+ ZVAL_STRINGL(z, buf.c, buf.len, 1);
+ jp->state = OK;
+ break;
+ }
+ /* fall through if not IS_STRING */
+ default:
+ FREE_BUFFERS();
+ jp->error_code = PHP_JSON_ERROR_SYNTAX;
+ return false;
+ }
+ break;
+/* , */
+ case -3:
+ {
+ zval *mval;
+
+ if (type != -1 &&
+ (jp->stack[jp->top] == MODE_OBJECT ||
+ jp->stack[jp->top] == MODE_ARRAY))
+ {
+ smart_str_0(&buf);
+ json_create_zval(&mval, &buf, type, options);
+ }
+
+ switch (jp->stack[jp->top]) {
+ case MODE_OBJECT:
+ if (pop(jp, MODE_OBJECT) && push(jp, MODE_KEY)) {
+ if (type != -1) {
+ if (!assoc) {
+ add_property_zval_ex(jp->the_zstack[jp->top], (key.len ? key.c : "_empty_"), (key.len ? (key.len + 1) : sizeof("_empty_")), mval TSRMLS_CC);
+ Z_DELREF_P(mval);
+ } else {
+ add_assoc_zval_ex(jp->the_zstack[jp->top], (key.len ? key.c : ""), (key.len ? (key.len + 1) : sizeof("")), mval);
+ }
+ key.len = 0;
+ }
+ jp->state = KE;
+ }
+ break;
+ case MODE_ARRAY:
+ if (type != -1) {
+ add_next_index_zval(jp->the_zstack[jp->top], mval);
+ }
+ jp->state = VA;
+ break;
+ default:
+ FREE_BUFFERS();
+ jp->error_code = PHP_JSON_ERROR_SYNTAX;
+ return false;
+ }
+ buf.len = 0;
+ JSON_RESET_TYPE();
+ }
+ break;
+/* : */
+ case -2:
+ if (pop(jp, MODE_KEY) && push(jp, MODE_OBJECT)) {
+ jp->state = VA;
+ break;
+ }
+/*
+ syntax error
+*/
+ default:
+ {
+ jp->error_code = PHP_JSON_ERROR_SYNTAX;
+ FREE_BUFFERS();
+ return false;
+ }
+ }
+ }
+ }
+
+ FREE_BUFFERS();
+ if (jp->state == OK && pop(jp, MODE_DONE)) {
+ return true;
+ }
+
+ jp->error_code = PHP_JSON_ERROR_SYNTAX;
+ return false;
+}
+
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/ext/json/JSON_parser.h b/ext/json/JSON_parser.h
new file mode 100644
index 000000000..8671765b4
--- /dev/null
+++ b/ext/json/JSON_parser.h
@@ -0,0 +1,43 @@
+/* JSON_parser.h */
+
+#ifndef JSON_PARSER_H
+#define JSON_PARSER_H
+
+#include "php.h"
+#include "ext/standard/php_smart_str.h"
+#include "php_json.h"
+
+#define JSON_PARSER_DEFAULT_DEPTH 512
+
+typedef struct JSON_parser_struct {
+ int state;
+ int depth;
+ int top;
+ int error_code;
+ int* stack;
+ zval **the_zstack;
+ zval *the_static_zstack[JSON_PARSER_DEFAULT_DEPTH];
+} * JSON_parser;
+
+enum error_codes {
+ PHP_JSON_ERROR_NONE = 0,
+ PHP_JSON_ERROR_DEPTH,
+ PHP_JSON_ERROR_STATE_MISMATCH,
+ PHP_JSON_ERROR_CTRL_CHAR,
+ PHP_JSON_ERROR_SYNTAX,
+ PHP_JSON_ERROR_UTF8,
+ PHP_JSON_ERROR_RECURSION,
+ PHP_JSON_ERROR_INF_OR_NAN,
+ PHP_JSON_ERROR_UNSUPPORTED_TYPE
+};
+
+extern JSON_parser new_JSON_parser(int depth);
+extern int parse_JSON_ex(JSON_parser jp, zval *z, unsigned short utf16_json[], int length, int options TSRMLS_DC);
+extern int free_JSON_parser(JSON_parser jp);
+
+static inline int parse_JSON(JSON_parser jp, zval *z, unsigned short utf16_json[], int length, int assoc TSRMLS_DC)
+{
+ return parse_JSON_ex(jp, z, utf16_json, length, assoc ? PHP_JSON_OBJECT_AS_ARRAY : 0 TSRMLS_CC);
+}
+
+#endif
diff --git a/ext/json/README b/ext/json/README
new file mode 100644
index 000000000..d680b0c59
--- /dev/null
+++ b/ext/json/README
@@ -0,0 +1,76 @@
+json 1.2.0
+==========
+
+This extension implements the JavaScript Object Notation (JSON)
+data-interchange format as specified in [0].
+
+Two functions are implemented: encoding and decoding. The decoding
+is handled by a parser based on JSON_checker[1] by Douglas Crockford.
+
+
+Function overview
+-----------------
+
+ string json_encode ( mixed value )
+
+json_encode returns a string containing the JSON representation of value.
+value can be any type except a resource.
+
+ mixed json_decode ( string json, [bool assoc] )
+
+json_decode takes a JSON string and converts it into a PHP variable.
+When assoc is given, and evaluates to TRUE, json_decode() will return
+any objects as associative arrays.
+
+
+Example usage
+-------------
+
+$arr = array("a"=>1,"b"=>2,"c"=>3,"d"=>4,"e"=>5);
+echo json_encode($arr);
+
+---> {"a":1,"b":2,"c":3,"d":4,"e":5}
+
+$json = '{"a":1,"b":2,"c":3,"d":4,"e":5}';
+var_dump(json_decode($json));
+
+---> object(stdClass)#1 (5) {
+ ["a"]=>
+ int(1)
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["d"]=>
+ int(4)
+ ["e"]=>
+ int(5)
+ }
+
+$json = '{"a":1,"b":2,"c":3,"d":4,"e":5}';
+var_dump(json_decode($json, true));
+
+---> array(5) {
+ ["a"]=>
+ int(1)
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["d"]=>
+ int(4)
+ ["e"]=>
+ int(5)
+ }
+
+
+Authors
+-------
+
+Omar Kilani <omar@php.net>
+
+
+---
+
+[0] http://www.crockford.com/JSON/draft-jsonorg-json-00.txt
+[1] http://www.crockford.com/JSON/JSON_checker/
diff --git a/ext/json/config.m4 b/ext/json/config.m4
new file mode 100644
index 000000000..26c43a0e3
--- /dev/null
+++ b/ext/json/config.m4
@@ -0,0 +1,15 @@
+dnl
+dnl $Id$
+dnl
+
+PHP_ARG_ENABLE(json, whether to enable JavaScript Object Serialization support,
+[ --disable-json Disable JavaScript Object Serialization support], yes)
+
+if test "$PHP_JSON" != "no"; then
+ AC_DEFINE([HAVE_JSON],1 ,[whether to enable JavaScript Object Serialization support])
+ AC_HEADER_STDC
+
+ PHP_NEW_EXTENSION(json, json.c utf8_decode.c JSON_parser.c, $ext_shared)
+ PHP_INSTALL_HEADERS([ext/json], [php_json.h])
+ PHP_SUBST(JSON_SHARED_LIBADD)
+fi
diff --git a/ext/json/config.w32 b/ext/json/config.w32
new file mode 100644
index 000000000..cedbf4282
--- /dev/null
+++ b/ext/json/config.w32
@@ -0,0 +1,11 @@
+// $Id$
+// vim:ft=javascript
+
+ARG_ENABLE("json", "JavaScript Object Serialization support", "yes");
+
+if (PHP_JSON != "no") {
+ EXTENSION('json', 'json.c', PHP_JSON_SHARED, "");
+ ADD_SOURCES(configure_module_dirname, "JSON_parser.c utf8_decode.c", "json");
+ PHP_INSTALL_HEADERS("ext/json/", "php_json.h");
+}
+
diff --git a/ext/json/json.c b/ext/json/json.c
new file mode 100644
index 000000000..53608412f
--- /dev/null
+++ b/ext/json/json.c
@@ -0,0 +1,872 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Omar Kilani <omar@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php.h"
+#include "php_ini.h"
+#include "ext/standard/info.h"
+#include "ext/standard/html.h"
+#include "ext/standard/php_smart_str.h"
+#include "JSON_parser.h"
+#include "php_json.h"
+#include <zend_exceptions.h>
+
+static PHP_MINFO_FUNCTION(json);
+static PHP_FUNCTION(json_encode);
+static PHP_FUNCTION(json_decode);
+static PHP_FUNCTION(json_last_error);
+static PHP_FUNCTION(json_last_error_msg);
+
+static const char digits[] = "0123456789abcdef";
+
+zend_class_entry *php_json_serializable_ce;
+
+ZEND_DECLARE_MODULE_GLOBALS(json)
+
+/* {{{ arginfo */
+ZEND_BEGIN_ARG_INFO_EX(arginfo_json_encode, 0, 0, 1)
+ ZEND_ARG_INFO(0, value)
+ ZEND_ARG_INFO(0, options)
+ ZEND_ARG_INFO(0, depth)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_json_decode, 0, 0, 1)
+ ZEND_ARG_INFO(0, json)
+ ZEND_ARG_INFO(0, assoc)
+ ZEND_ARG_INFO(0, depth)
+ ZEND_ARG_INFO(0, options)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_json_last_error, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_json_last_error_msg, 0)
+ZEND_END_ARG_INFO()
+/* }}} */
+
+/* {{{ json_functions[] */
+static const zend_function_entry json_functions[] = {
+ PHP_FE(json_encode, arginfo_json_encode)
+ PHP_FE(json_decode, arginfo_json_decode)
+ PHP_FE(json_last_error, arginfo_json_last_error)
+ PHP_FE(json_last_error_msg, arginfo_json_last_error_msg)
+ PHP_FE_END
+};
+/* }}} */
+
+/* {{{ JsonSerializable methods */
+ZEND_BEGIN_ARG_INFO(json_serialize_arginfo, 0)
+ /* No arguments */
+ZEND_END_ARG_INFO();
+
+static const zend_function_entry json_serializable_interface[] = {
+ PHP_ABSTRACT_ME(JsonSerializable, jsonSerialize, json_serialize_arginfo)
+ PHP_FE_END
+};
+/* }}} */
+
+/* {{{ MINIT */
+static PHP_MINIT_FUNCTION(json)
+{
+ zend_class_entry ce;
+
+ INIT_CLASS_ENTRY(ce, "JsonSerializable", json_serializable_interface);
+ php_json_serializable_ce = zend_register_internal_interface(&ce TSRMLS_CC);
+
+ REGISTER_LONG_CONSTANT("JSON_HEX_TAG", PHP_JSON_HEX_TAG, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("JSON_HEX_AMP", PHP_JSON_HEX_AMP, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("JSON_HEX_APOS", PHP_JSON_HEX_APOS, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("JSON_HEX_QUOT", PHP_JSON_HEX_QUOT, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("JSON_FORCE_OBJECT", PHP_JSON_FORCE_OBJECT, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("JSON_NUMERIC_CHECK", PHP_JSON_NUMERIC_CHECK, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("JSON_UNESCAPED_SLASHES", PHP_JSON_UNESCAPED_SLASHES, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("JSON_PRETTY_PRINT", PHP_JSON_PRETTY_PRINT, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("JSON_UNESCAPED_UNICODE", PHP_JSON_UNESCAPED_UNICODE, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("JSON_PARTIAL_OUTPUT_ON_ERROR", PHP_JSON_PARTIAL_OUTPUT_ON_ERROR, CONST_CS | CONST_PERSISTENT);
+
+ REGISTER_LONG_CONSTANT("JSON_ERROR_NONE", PHP_JSON_ERROR_NONE, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("JSON_ERROR_DEPTH", PHP_JSON_ERROR_DEPTH, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("JSON_ERROR_STATE_MISMATCH", PHP_JSON_ERROR_STATE_MISMATCH, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("JSON_ERROR_CTRL_CHAR", PHP_JSON_ERROR_CTRL_CHAR, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("JSON_ERROR_SYNTAX", PHP_JSON_ERROR_SYNTAX, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("JSON_ERROR_UTF8", PHP_JSON_ERROR_UTF8, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("JSON_ERROR_RECURSION", PHP_JSON_ERROR_RECURSION, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("JSON_ERROR_INF_OR_NAN", PHP_JSON_ERROR_INF_OR_NAN, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("JSON_ERROR_UNSUPPORTED_TYPE", PHP_JSON_ERROR_UNSUPPORTED_TYPE, CONST_CS | CONST_PERSISTENT);
+
+ REGISTER_LONG_CONSTANT("JSON_OBJECT_AS_ARRAY", PHP_JSON_OBJECT_AS_ARRAY, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("JSON_BIGINT_AS_STRING", PHP_JSON_BIGINT_AS_STRING, CONST_CS | CONST_PERSISTENT);
+
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ PHP_GINIT_FUNCTION
+*/
+static PHP_GINIT_FUNCTION(json)
+{
+ json_globals->encoder_depth = 0;
+ json_globals->error_code = 0;
+ json_globals->encode_max_depth = 0;
+}
+/* }}} */
+
+
+/* {{{ json_module_entry
+ */
+zend_module_entry json_module_entry = {
+ STANDARD_MODULE_HEADER,
+ "json",
+ json_functions,
+ PHP_MINIT(json),
+ NULL,
+ NULL,
+ NULL,
+ PHP_MINFO(json),
+ PHP_JSON_VERSION,
+ PHP_MODULE_GLOBALS(json),
+ PHP_GINIT(json),
+ NULL,
+ NULL,
+ STANDARD_MODULE_PROPERTIES_EX
+};
+/* }}} */
+
+#ifdef COMPILE_DL_JSON
+ZEND_GET_MODULE(json)
+#endif
+
+/* {{{ PHP_MINFO_FUNCTION
+ */
+static PHP_MINFO_FUNCTION(json)
+{
+ php_info_print_table_start();
+ php_info_print_table_row(2, "json support", "enabled");
+ php_info_print_table_row(2, "json version", PHP_JSON_VERSION);
+ php_info_print_table_end();
+}
+/* }}} */
+
+static void json_escape_string(smart_str *buf, char *s, int len, int options TSRMLS_DC);
+
+static int json_determine_array_type(zval **val TSRMLS_DC) /* {{{ */
+{
+ int i;
+ HashTable *myht = HASH_OF(*val);
+
+ i = myht ? zend_hash_num_elements(myht) : 0;
+ if (i > 0) {
+ char *key;
+ ulong index, idx;
+ uint key_len;
+ HashPosition pos;
+
+ zend_hash_internal_pointer_reset_ex(myht, &pos);
+ idx = 0;
+ for (;; zend_hash_move_forward_ex(myht, &pos)) {
+ i = zend_hash_get_current_key_ex(myht, &key, &key_len, &index, 0, &pos);
+ if (i == HASH_KEY_NON_EXISTANT) {
+ break;
+ }
+
+ if (i == HASH_KEY_IS_STRING) {
+ return 1;
+ } else {
+ if (index != idx) {
+ return 1;
+ }
+ }
+ idx++;
+ }
+ }
+
+ return PHP_JSON_OUTPUT_ARRAY;
+}
+/* }}} */
+
+/* {{{ Pretty printing support functions */
+
+static inline void json_pretty_print_char(smart_str *buf, int options, char c TSRMLS_DC) /* {{{ */
+{
+ if (options & PHP_JSON_PRETTY_PRINT) {
+ smart_str_appendc(buf, c);
+ }
+}
+/* }}} */
+
+static inline void json_pretty_print_indent(smart_str *buf, int options TSRMLS_DC) /* {{{ */
+{
+ int i;
+
+ if (options & PHP_JSON_PRETTY_PRINT) {
+ for (i = 0; i < JSON_G(encoder_depth); ++i) {
+ smart_str_appendl(buf, " ", 4);
+ }
+ }
+}
+/* }}} */
+
+/* }}} */
+
+static void json_encode_array(smart_str *buf, zval **val, int options TSRMLS_DC) /* {{{ */
+{
+ int i, r;
+ HashTable *myht;
+
+ if (Z_TYPE_PP(val) == IS_ARRAY) {
+ myht = HASH_OF(*val);
+ r = (options & PHP_JSON_FORCE_OBJECT) ? PHP_JSON_OUTPUT_OBJECT : json_determine_array_type(val TSRMLS_CC);
+ } else {
+ myht = Z_OBJPROP_PP(val);
+ r = PHP_JSON_OUTPUT_OBJECT;
+ }
+
+ if (myht && myht->nApplyCount > 1) {
+ JSON_G(error_code) = PHP_JSON_ERROR_RECURSION;
+ smart_str_appendl(buf, "null", 4);
+ return;
+ }
+
+ if (r == PHP_JSON_OUTPUT_ARRAY) {
+ smart_str_appendc(buf, '[');
+ } else {
+ smart_str_appendc(buf, '{');
+ }
+
+ json_pretty_print_char(buf, options, '\n' TSRMLS_CC);
+ ++JSON_G(encoder_depth);
+
+ i = myht ? zend_hash_num_elements(myht) : 0;
+
+ if (i > 0)
+ {
+ char *key;
+ zval **data;
+ ulong index;
+ uint key_len;
+ HashPosition pos;
+ HashTable *tmp_ht;
+ int need_comma = 0;
+
+ zend_hash_internal_pointer_reset_ex(myht, &pos);
+ for (;; zend_hash_move_forward_ex(myht, &pos)) {
+ i = zend_hash_get_current_key_ex(myht, &key, &key_len, &index, 0, &pos);
+ if (i == HASH_KEY_NON_EXISTANT)
+ break;
+
+ if (zend_hash_get_current_data_ex(myht, (void **) &data, &pos) == SUCCESS) {
+ tmp_ht = HASH_OF(*data);
+ if (tmp_ht) {
+ tmp_ht->nApplyCount++;
+ }
+
+ if (r == PHP_JSON_OUTPUT_ARRAY) {
+ if (need_comma) {
+ smart_str_appendc(buf, ',');
+ json_pretty_print_char(buf, options, '\n' TSRMLS_CC);
+ } else {
+ need_comma = 1;
+ }
+
+ json_pretty_print_indent(buf, options TSRMLS_CC);
+ php_json_encode(buf, *data, options TSRMLS_CC);
+ } else if (r == PHP_JSON_OUTPUT_OBJECT) {
+ if (i == HASH_KEY_IS_STRING) {
+ if (key[0] == '\0' && Z_TYPE_PP(val) == IS_OBJECT) {
+ /* Skip protected and private members. */
+ if (tmp_ht) {
+ tmp_ht->nApplyCount--;
+ }
+ continue;
+ }
+
+ if (need_comma) {
+ smart_str_appendc(buf, ',');
+ json_pretty_print_char(buf, options, '\n' TSRMLS_CC);
+ } else {
+ need_comma = 1;
+ }
+
+ json_pretty_print_indent(buf, options TSRMLS_CC);
+
+ json_escape_string(buf, key, key_len - 1, options & ~PHP_JSON_NUMERIC_CHECK TSRMLS_CC);
+ smart_str_appendc(buf, ':');
+
+ json_pretty_print_char(buf, options, ' ' TSRMLS_CC);
+
+ php_json_encode(buf, *data, options TSRMLS_CC);
+ } else {
+ if (need_comma) {
+ smart_str_appendc(buf, ',');
+ json_pretty_print_char(buf, options, '\n' TSRMLS_CC);
+ } else {
+ need_comma = 1;
+ }
+
+ json_pretty_print_indent(buf, options TSRMLS_CC);
+
+ smart_str_appendc(buf, '"');
+ smart_str_append_long(buf, (long) index);
+ smart_str_appendc(buf, '"');
+ smart_str_appendc(buf, ':');
+
+ json_pretty_print_char(buf, options, ' ' TSRMLS_CC);
+
+ php_json_encode(buf, *data, options TSRMLS_CC);
+ }
+ }
+
+ if (tmp_ht) {
+ tmp_ht->nApplyCount--;
+ }
+ }
+ }
+ }
+
+ if (JSON_G(encoder_depth) > JSON_G(encode_max_depth)) {
+ JSON_G(error_code) = PHP_JSON_ERROR_DEPTH;
+ }
+ --JSON_G(encoder_depth);
+ json_pretty_print_char(buf, options, '\n' TSRMLS_CC);
+ json_pretty_print_indent(buf, options TSRMLS_CC);
+
+ if (r == PHP_JSON_OUTPUT_ARRAY) {
+ smart_str_appendc(buf, ']');
+ } else {
+ smart_str_appendc(buf, '}');
+ }
+}
+/* }}} */
+
+static int json_utf8_to_utf16(unsigned short *utf16, char utf8[], int len) /* {{{ */
+{
+ size_t pos = 0, us;
+ int j, status;
+
+ if (utf16) {
+ /* really convert the utf8 string */
+ for (j=0 ; pos < len ; j++) {
+ us = php_next_utf8_char((const unsigned char *)utf8, len, &pos, &status);
+ if (status != SUCCESS) {
+ return -1;
+ }
+ /* From http://en.wikipedia.org/wiki/UTF16 */
+ if (us >= 0x10000) {
+ us -= 0x10000;
+ utf16[j++] = (unsigned short)((us >> 10) | 0xd800);
+ utf16[j] = (unsigned short)((us & 0x3ff) | 0xdc00);
+ } else {
+ utf16[j] = (unsigned short)us;
+ }
+ }
+ } else {
+ /* Only check if utf8 string is valid, and compute utf16 lenght */
+ for (j=0 ; pos < len ; j++) {
+ us = php_next_utf8_char((const unsigned char *)utf8, len, &pos, &status);
+ if (status != SUCCESS) {
+ return -1;
+ }
+ if (us >= 0x10000) {
+ j++;
+ }
+ }
+ }
+ return j;
+}
+/* }}} */
+
+
+static void json_escape_string(smart_str *buf, char *s, int len, int options TSRMLS_DC) /* {{{ */
+{
+ int pos = 0, ulen = 0;
+ unsigned short us;
+ unsigned short *utf16;
+ size_t newlen;
+
+ if (len == 0) {
+ smart_str_appendl(buf, "\"\"", 2);
+ return;
+ }
+
+ if (options & PHP_JSON_NUMERIC_CHECK) {
+ double d;
+ int type;
+ long p;
+
+ if ((type = is_numeric_string(s, len, &p, &d, 0)) != 0) {
+ if (type == IS_LONG) {
+ smart_str_append_long(buf, p);
+ } else if (type == IS_DOUBLE) {
+ if (!zend_isinf(d) && !zend_isnan(d)) {
+ char *tmp;
+ int l = spprintf(&tmp, 0, "%.*k", (int) EG(precision), d);
+ smart_str_appendl(buf, tmp, l);
+ efree(tmp);
+ } else {
+ JSON_G(error_code) = PHP_JSON_ERROR_INF_OR_NAN;
+ smart_str_appendc(buf, '0');
+ }
+ }
+ return;
+ }
+
+ }
+
+ utf16 = (options & PHP_JSON_UNESCAPED_UNICODE) ? NULL : (unsigned short *) safe_emalloc(len, sizeof(unsigned short), 0);
+ ulen = json_utf8_to_utf16(utf16, s, len);
+ if (ulen <= 0) {
+ if (utf16) {
+ efree(utf16);
+ }
+ if (ulen < 0) {
+ JSON_G(error_code) = PHP_JSON_ERROR_UTF8;
+ smart_str_appendl(buf, "null", 4);
+ } else {
+ smart_str_appendl(buf, "\"\"", 2);
+ }
+ return;
+ }
+ if (!(options & PHP_JSON_UNESCAPED_UNICODE)) {
+ len = ulen;
+ }
+
+ /* pre-allocate for string length plus 2 quotes */
+ smart_str_alloc(buf, len+2, 0);
+ smart_str_appendc(buf, '"');
+
+ while (pos < len)
+ {
+ us = (options & PHP_JSON_UNESCAPED_UNICODE) ? s[pos++] : utf16[pos++];
+
+ switch (us)
+ {
+ case '"':
+ if (options & PHP_JSON_HEX_QUOT) {
+ smart_str_appendl(buf, "\\u0022", 6);
+ } else {
+ smart_str_appendl(buf, "\\\"", 2);
+ }
+ break;
+
+ case '\\':
+ smart_str_appendl(buf, "\\\\", 2);
+ break;
+
+ case '/':
+ if (options & PHP_JSON_UNESCAPED_SLASHES) {
+ smart_str_appendc(buf, '/');
+ } else {
+ smart_str_appendl(buf, "\\/", 2);
+ }
+ break;
+
+ case '\b':
+ smart_str_appendl(buf, "\\b", 2);
+ break;
+
+ case '\f':
+ smart_str_appendl(buf, "\\f", 2);
+ break;
+
+ case '\n':
+ smart_str_appendl(buf, "\\n", 2);
+ break;
+
+ case '\r':
+ smart_str_appendl(buf, "\\r", 2);
+ break;
+
+ case '\t':
+ smart_str_appendl(buf, "\\t", 2);
+ break;
+
+ case '<':
+ if (options & PHP_JSON_HEX_TAG) {
+ smart_str_appendl(buf, "\\u003C", 6);
+ } else {
+ smart_str_appendc(buf, '<');
+ }
+ break;
+
+ case '>':
+ if (options & PHP_JSON_HEX_TAG) {
+ smart_str_appendl(buf, "\\u003E", 6);
+ } else {
+ smart_str_appendc(buf, '>');
+ }
+ break;
+
+ case '&':
+ if (options & PHP_JSON_HEX_AMP) {
+ smart_str_appendl(buf, "\\u0026", 6);
+ } else {
+ smart_str_appendc(buf, '&');
+ }
+ break;
+
+ case '\'':
+ if (options & PHP_JSON_HEX_APOS) {
+ smart_str_appendl(buf, "\\u0027", 6);
+ } else {
+ smart_str_appendc(buf, '\'');
+ }
+ break;
+
+ default:
+ if (us >= ' ' && ((options & PHP_JSON_UNESCAPED_UNICODE) || (us & 127) == us)) {
+ smart_str_appendc(buf, (unsigned char) us);
+ } else {
+ smart_str_appendl(buf, "\\u", 2);
+ smart_str_appendc(buf, digits[(us & 0xf000) >> 12]);
+ smart_str_appendc(buf, digits[(us & 0xf00) >> 8]);
+ smart_str_appendc(buf, digits[(us & 0xf0) >> 4]);
+ smart_str_appendc(buf, digits[(us & 0xf)]);
+ }
+ break;
+ }
+ }
+
+ smart_str_appendc(buf, '"');
+ if (utf16) {
+ efree(utf16);
+ }
+}
+/* }}} */
+
+
+static void json_encode_serializable_object(smart_str *buf, zval *val, int options TSRMLS_DC) /* {{{ */
+{
+ zend_class_entry *ce = Z_OBJCE_P(val);
+ zval *retval = NULL, fname;
+ HashTable* myht;
+
+ if (Z_TYPE_P(val) == IS_ARRAY) {
+ myht = HASH_OF(val);
+ } else {
+ myht = Z_OBJPROP_P(val);
+ }
+
+ if (myht && myht->nApplyCount > 1) {
+ JSON_G(error_code) = PHP_JSON_ERROR_RECURSION;
+ smart_str_appendl(buf, "null", 4);
+ return;
+ }
+
+ ZVAL_STRING(&fname, "jsonSerialize", 0);
+
+ if (FAILURE == call_user_function_ex(EG(function_table), &val, &fname, &retval, 0, NULL, 1, NULL TSRMLS_CC) || !retval) {
+ zend_throw_exception_ex(NULL, 0 TSRMLS_CC, "Failed calling %s::jsonSerialize()", ce->name);
+ smart_str_appendl(buf, "null", sizeof("null") - 1);
+ return;
+ }
+
+ if (EG(exception)) {
+ /* Error already raised */
+ zval_ptr_dtor(&retval);
+ smart_str_appendl(buf, "null", sizeof("null") - 1);
+ return;
+ }
+
+ if ((Z_TYPE_P(retval) == IS_OBJECT) &&
+ (Z_OBJ_HANDLE_P(retval) == Z_OBJ_HANDLE_P(val))) {
+ /* Handle the case where jsonSerialize does: return $this; by going straight to encode array */
+ json_encode_array(buf, &retval, options TSRMLS_CC);
+ } else {
+ /* All other types, encode as normal */
+ php_json_encode(buf, retval, options TSRMLS_CC);
+ }
+
+ zval_ptr_dtor(&retval);
+}
+/* }}} */
+
+PHP_JSON_API void php_json_encode(smart_str *buf, zval *val, int options TSRMLS_DC) /* {{{ */
+{
+ switch (Z_TYPE_P(val))
+ {
+ case IS_NULL:
+ smart_str_appendl(buf, "null", 4);
+ break;
+
+ case IS_BOOL:
+ if (Z_BVAL_P(val)) {
+ smart_str_appendl(buf, "true", 4);
+ } else {
+ smart_str_appendl(buf, "false", 5);
+ }
+ break;
+
+ case IS_LONG:
+ smart_str_append_long(buf, Z_LVAL_P(val));
+ break;
+
+ case IS_DOUBLE:
+ {
+ char *d = NULL;
+ int len;
+ double dbl = Z_DVAL_P(val);
+
+ if (!zend_isinf(dbl) && !zend_isnan(dbl)) {
+ len = spprintf(&d, 0, "%.*k", (int) EG(precision), dbl);
+ smart_str_appendl(buf, d, len);
+ efree(d);
+ } else {
+ JSON_G(error_code) = PHP_JSON_ERROR_INF_OR_NAN;
+ smart_str_appendc(buf, '0');
+ }
+ }
+ break;
+
+ case IS_STRING:
+ json_escape_string(buf, Z_STRVAL_P(val), Z_STRLEN_P(val), options TSRMLS_CC);
+ break;
+
+ case IS_OBJECT:
+ if (instanceof_function(Z_OBJCE_P(val), php_json_serializable_ce TSRMLS_CC)) {
+ json_encode_serializable_object(buf, val, options TSRMLS_CC);
+ break;
+ }
+ /* fallthrough -- Non-serializable object */
+ case IS_ARRAY:
+ json_encode_array(buf, &val, options TSRMLS_CC);
+ break;
+
+ default:
+ JSON_G(error_code) = PHP_JSON_ERROR_UNSUPPORTED_TYPE;
+ smart_str_appendl(buf, "null", 4);
+ break;
+ }
+
+ return;
+}
+/* }}} */
+
+PHP_JSON_API void php_json_decode_ex(zval *return_value, char *str, int str_len, int options, long depth TSRMLS_DC) /* {{{ */
+{
+ int utf16_len;
+ zval *z;
+ unsigned short *utf16;
+ JSON_parser jp;
+
+ utf16 = (unsigned short *) safe_emalloc((str_len+1), sizeof(unsigned short), 1);
+
+ utf16_len = json_utf8_to_utf16(utf16, str, str_len);
+ if (utf16_len <= 0) {
+ if (utf16) {
+ efree(utf16);
+ }
+ JSON_G(error_code) = PHP_JSON_ERROR_UTF8;
+ RETURN_NULL();
+ }
+
+ if (depth <= 0) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Depth must be greater than zero");
+ efree(utf16);
+ RETURN_NULL();
+ }
+
+ ALLOC_INIT_ZVAL(z);
+ jp = new_JSON_parser(depth);
+ if (parse_JSON_ex(jp, z, utf16, utf16_len, options TSRMLS_CC)) {
+ *return_value = *z;
+ }
+ else
+ {
+ double d;
+ int type, overflow_info;
+ long p;
+
+ RETVAL_NULL();
+ if (str_len == 4) {
+ if (!strcasecmp(str, "null")) {
+ /* We need to explicitly clear the error because its an actual NULL and not an error */
+ jp->error_code = PHP_JSON_ERROR_NONE;
+ RETVAL_NULL();
+ } else if (!strcasecmp(str, "true")) {
+ RETVAL_BOOL(1);
+ }
+ } else if (str_len == 5 && !strcasecmp(str, "false")) {
+ RETVAL_BOOL(0);
+ }
+
+ if ((type = is_numeric_string_ex(str, str_len, &p, &d, 0, &overflow_info)) != 0) {
+ if (type == IS_LONG) {
+ RETVAL_LONG(p);
+ } else if (type == IS_DOUBLE) {
+ if (options & PHP_JSON_BIGINT_AS_STRING && overflow_info) {
+ /* Within an object or array, a numeric literal is assumed
+ * to be an integer if and only if it's entirely made up of
+ * digits (exponent notation will result in the number
+ * being treated as a double). We'll match that behaviour
+ * here. */
+ int i;
+ zend_bool is_float = 0;
+
+ for (i = (str[0] == '-' ? 1 : 0); i < str_len; i++) {
+ /* Not using isdigit() because it's locale specific,
+ * but we expect JSON input to always be UTF-8. */
+ if (str[i] < '0' || str[i] > '9') {
+ is_float = 1;
+ break;
+ }
+ }
+
+ if (is_float) {
+ RETVAL_DOUBLE(d);
+ } else {
+ RETVAL_STRINGL(str, str_len, 1);
+ }
+ } else {
+ RETVAL_DOUBLE(d);
+ }
+ }
+ }
+
+ if (Z_TYPE_P(return_value) != IS_NULL) {
+ jp->error_code = PHP_JSON_ERROR_NONE;
+ }
+
+ zval_dtor(z);
+ }
+ FREE_ZVAL(z);
+ efree(utf16);
+ JSON_G(error_code) = jp->error_code;
+ free_JSON_parser(jp);
+}
+/* }}} */
+
+
+/* {{{ proto string json_encode(mixed data [, int options[, int depth]])
+ Returns the JSON representation of a value */
+static PHP_FUNCTION(json_encode)
+{
+ zval *parameter;
+ smart_str buf = {0};
+ long options = 0;
+ long depth = JSON_PARSER_DEFAULT_DEPTH;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|ll", &parameter, &options, &depth) == FAILURE) {
+ return;
+ }
+
+ JSON_G(error_code) = PHP_JSON_ERROR_NONE;
+
+ JSON_G(encode_max_depth) = depth;
+
+ php_json_encode(&buf, parameter, options TSRMLS_CC);
+
+ if (JSON_G(error_code) != PHP_JSON_ERROR_NONE && !(options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR)) {
+ ZVAL_FALSE(return_value);
+ } else {
+ ZVAL_STRINGL(return_value, buf.c, buf.len, 1);
+ }
+
+ smart_str_free(&buf);
+}
+/* }}} */
+
+/* {{{ proto mixed json_decode(string json [, bool assoc [, long depth]])
+ Decodes the JSON representation into a PHP value */
+static PHP_FUNCTION(json_decode)
+{
+ char *str;
+ int str_len;
+ zend_bool assoc = 0; /* return JS objects as PHP objects by default */
+ long depth = JSON_PARSER_DEFAULT_DEPTH;
+ long options = 0;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|bll", &str, &str_len, &assoc, &depth, &options) == FAILURE) {
+ return;
+ }
+
+ JSON_G(error_code) = 0;
+
+ if (!str_len) {
+ RETURN_NULL();
+ }
+
+ /* For BC reasons, the bool $assoc overrides the long $options bit for PHP_JSON_OBJECT_AS_ARRAY */
+ if (assoc) {
+ options |= PHP_JSON_OBJECT_AS_ARRAY;
+ } else {
+ options &= ~PHP_JSON_OBJECT_AS_ARRAY;
+ }
+
+ php_json_decode_ex(return_value, str, str_len, options, depth TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ proto int json_last_error()
+ Returns the error code of the last json_encode() or json_decode() call. */
+static PHP_FUNCTION(json_last_error)
+{
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ RETURN_LONG(JSON_G(error_code));
+}
+/* }}} */
+
+/* {{{ proto string json_last_error_msg()
+ Returns the error string of the last json_encode() or json_decode() call. */
+static PHP_FUNCTION(json_last_error_msg)
+{
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ switch(JSON_G(error_code)) {
+ case PHP_JSON_ERROR_NONE:
+ RETURN_STRING("No error", 1);
+ case PHP_JSON_ERROR_DEPTH:
+ RETURN_STRING("Maximum stack depth exceeded", 1);
+ case PHP_JSON_ERROR_STATE_MISMATCH:
+ RETURN_STRING("State mismatch (invalid or malformed JSON)", 1);
+ case PHP_JSON_ERROR_CTRL_CHAR:
+ RETURN_STRING("Control character error, possibly incorrectly encoded", 1);
+ case PHP_JSON_ERROR_SYNTAX:
+ RETURN_STRING("Syntax error", 1);
+ case PHP_JSON_ERROR_UTF8:
+ RETURN_STRING("Malformed UTF-8 characters, possibly incorrectly encoded", 1);
+ case PHP_JSON_ERROR_RECURSION:
+ RETURN_STRING("Recursion detected", 1);
+ case PHP_JSON_ERROR_INF_OR_NAN:
+ RETURN_STRING("Inf and NaN cannot be JSON encoded", 1);
+ case PHP_JSON_ERROR_UNSUPPORTED_TYPE:
+ RETURN_STRING("Type is not supported", 1);
+ default:
+ RETURN_STRING("Unknown error", 1);
+ }
+
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/ext/json/json.dsp b/ext/json/json.dsp
new file mode 100644
index 000000000..e5bb3767b
--- /dev/null
+++ b/ext/json/json.dsp
@@ -0,0 +1,135 @@
+# Microsoft Developer Studio Project File - Name="json" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=json - Win32 Debug_TS
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "json.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "json.mak" CFG="json - Win32 Debug_TS"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "json - Win32 Debug_TS" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "json - Win32 Release_TS" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "json - Win32 Debug_TS"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug_TS"
+# PROP BASE Intermediate_Dir "Debug_TS"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug_TS"
+# PROP Intermediate_Dir "Debug_TS"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "JSON_EXPORTS" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\.." /I "..\..\main" /I "..\..\Zend" /I "..\..\TSRM" /I "json_c" /D HAVE_JSON=1 /D "ZEND_WIN32" /D "PHP_WIN32" /D ZEND_DEBUG=1 /D ZTS=1 /D COMPILE_DL_JSON=1 /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "JSON_EXPORTS" /YX /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x1009 /d "_DEBUG"
+# ADD RSC /l 0x1009 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 iconv.lib php4ts_debug.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"..\..\Debug_TS/php_json.dll" /pdbtype:sept /libpath:"..\..\Debug_TS"
+
+!ELSEIF "$(CFG)" == "json - Win32 Release_TS"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release_TS"
+# PROP BASE Intermediate_Dir "Release_TS"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release_TS"
+# PROP Intermediate_Dir "Release_TS"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "JSON_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\.." /I "..\..\main" /I "..\..\Zend" /I "..\..\TSRM" /I "json_c" /D HAVE_JSON=1 /D "ZEND_WIN32" /D ZEND_DEBUG=0 /D "PHP_WIN32" /D ZTS=1 /D COMPILE_DL_JSON=1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "JSON_EXPORTS" /D "HAVE_FCNTL_H" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x1009 /d "NDEBUG"
+# ADD RSC /l 0x1009 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
+# ADD LINK32 iconv.lib php4ts.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"..\..\Release_TS/php_json.dll" /libpath:"..\..\Release_TS"
+
+!ENDIF
+
+# Begin Target
+
+# Name "json - Win32 Debug_TS"
+# Name "json - Win32 Release_TS"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=".\json.c"
+# End Source File
+# Begin Source File
+
+SOURCE=.\JSON_parser.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\JSON_parser.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\utf8_decode.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\utf8_decode.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\utf8_to_utf16.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\utf8_to_utf16.h
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\php_json.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/ext/json/package.xml b/ext/json/package.xml
new file mode 100644
index 000000000..0651de736
--- /dev/null
+++ b/ext/json/package.xml
@@ -0,0 +1,152 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE package SYSTEM "../pear/package.dtd">
+<package>
+ <dep type="php" rel="ge" version="4.3.0" optional="no"/>
+ <name>json</name>
+ <summary>JavaScript Object Notation</summary>
+ <maintainers>
+ <maintainer>
+ <user>omar</user>
+ <name>Omar Kilani</name>
+ <email>omar@php.net</email>
+ <role>lead</role>
+ </maintainer>
+ </maintainers>
+ <description>
+ Support for JSON (JavaScript Object Notation) serialization.
+ </description>
+ <license>PHP 3.01</license>
+ <release>
+ <state>stable</state>
+ <version>1.2.1</version>
+ <date>2006-03-18</date>
+ <notes>
+ Fix PECL bug #7147 - rework handling of comma insertion while encoding.
+ Add tests to package.xml
+ </notes>
+ </release>
+ <configureoptions>
+ </configureoptions>
+ <filelist>
+ <file role="doc" name="README" />
+ <file role="src" name="config.m4" />
+ <file role="src" name="config.w32" />
+ <file role="src" name="json.dsp" />
+ <file role="src" name="json.c" />
+ <file role="src" name="JSON_parser.c" />
+ <file role="src" name="JSON_parser.h" />
+ <file role="src" name="php_json.h" />
+ <file role="src" name="utf8_decode.c" />
+ <file role="src" name="utf8_decode.h" />
+ <file role="src" name="utf8_to_utf16.c" />
+ <file role="src" name="utf8_to_utf16.h" />
+ <dir role="test" name="tests">
+ <file role="test" name="fail001.phpt" />
+ <file role="test" name="pass001.phpt" />
+ <file role="test" name="pass001.1.phpt" />
+ <file role="test" name="pass002.phpt" />
+ <file role="test" name="pass003.phpt" />
+ </dir>
+ </filelist>
+ <changelog>
+ <release>
+ <state>stable</state>
+ <version>1.0.0</version>
+ <date>2005-04-01</date>
+ <notes>
+ Initial release.
+ </notes>
+ </release>
+ <release>
+ <state>stable</state>
+ <version>1.0.1</version>
+ <date>2005-06-10</date>
+ <notes>
+ Fixed non-linear and mixed type array index issues, fixed issues with escaping \\, forked json-c and added Unicode support.
+ </notes>
+ </release>
+ <release>
+ <state>stable</state>
+ <version>1.0.2</version>
+ <date>2005-06-11</date>
+ <notes>
+ Fixed issues with object reference counts under PHP4.
+ </notes>
+ </release>
+ <release>
+ <state>stable</state>
+ <version>1.0.3</version>
+ <date>2005-06-15</date>
+ <notes>
+ Fixed json-c string corruption issues under Mac OS X and FreeBSD.
+ </notes>
+ </release>
+ <release>
+ <state>stable</state>
+ <version>1.0.4</version>
+ <date>2005-06-15</date>
+ <notes>
+ Changes in 1.0.4 released with 1.0.5.
+ </notes>
+ </release>
+ <release>
+ <state>stable</state>
+ <version>1.0.5</version>
+ <date>2005-06-16</date>
+ <notes>
+ Changed spacing in json-c encoding, added optional assoc (boolean) parameter to json_decode to decode as associative array instead of object, fixed issues with escaping /.
+ </notes>
+ </release>
+ <release>
+ <state>stable</state>
+ <version>1.0.6</version>
+ <date>2005-08-05</date>
+ <notes>
+ Fixed issues with exporting private and protected class members.
+ </notes>
+ </release>
+ <release>
+ <state>stable</state>
+ <version>1.0.7</version>
+ <date>2005-09-07</date>
+ <notes>
+ Fixed issues with negative array keys, modified json-c to return an error on unquoted object key names instead of going into an infinite loop.
+ </notes>
+ </release>
+ <release>
+ <state>stable</state>
+ <version>1.0.8</version>
+ <date>2005-12-01</date>
+ <notes>
+ Changed license to LGPL, modified build system to allow static compilation into PHP, added strndup check for json-c.
+ </notes>
+ </release>
+ <release>
+ <state>stable</state>
+ <version>1.1.0</version>
+ <date>2005-12-04</date>
+ <notes>
+ Port to Win32.
+ </notes>
+ </release>
+ <release>
+ <state>stable</state>
+ <version>1.1.1</version>
+ <date>2006-01-12</date>
+ <notes>
+ Cleanup and TSRM performance fixes by rasmus.
+ </notes>
+ </release>
+ <release>
+ <state>stable</state>
+ <version>1.2.0</version>
+ <date>2006-03-15</date>
+ <notes>
+ Complete rewrite using JSON_checker as the base for the parser. Implements the JSON specification. 3-8x faster on encodes and 1.2x-4x faster on decodes.
+ </notes>
+ </release>
+ </changelog>
+</package>
+<!--
+vim:et:ts=1:sw=1
+-->
diff --git a/ext/json/php_json.h b/ext/json/php_json.h
new file mode 100644
index 000000000..ec707ce34
--- /dev/null
+++ b/ext/json/php_json.h
@@ -0,0 +1,92 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Omar Kilani <omar@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef PHP_JSON_H
+#define PHP_JSON_H
+
+#define PHP_JSON_VERSION "1.2.1"
+#include "ext/standard/php_smart_str.h"
+
+extern zend_module_entry json_module_entry;
+#define phpext_json_ptr &json_module_entry
+
+#if defined(PHP_WIN32) && defined(JSON_EXPORTS)
+#define PHP_JSON_API __declspec(dllexport)
+#else
+#define PHP_JSON_API PHPAPI
+#endif
+
+#ifdef ZTS
+#include "TSRM.h"
+#endif
+
+ZEND_BEGIN_MODULE_GLOBALS(json)
+ int encoder_depth;
+ int error_code;
+ int encode_max_depth;
+ZEND_END_MODULE_GLOBALS(json)
+
+#ifdef ZTS
+# define JSON_G(v) TSRMG(json_globals_id, zend_json_globals *, v)
+#else
+# define JSON_G(v) (json_globals.v)
+#endif
+
+PHP_JSON_API void php_json_encode(smart_str *buf, zval *val, int options TSRMLS_DC);
+PHP_JSON_API void php_json_decode_ex(zval *return_value, char *str, int str_len, int options, long depth TSRMLS_DC);
+extern zend_class_entry *php_json_serializable_ce;
+
+
+/* json_encode() options */
+#define PHP_JSON_HEX_TAG (1<<0)
+#define PHP_JSON_HEX_AMP (1<<1)
+#define PHP_JSON_HEX_APOS (1<<2)
+#define PHP_JSON_HEX_QUOT (1<<3)
+#define PHP_JSON_FORCE_OBJECT (1<<4)
+#define PHP_JSON_NUMERIC_CHECK (1<<5)
+#define PHP_JSON_UNESCAPED_SLASHES (1<<6)
+#define PHP_JSON_PRETTY_PRINT (1<<7)
+#define PHP_JSON_UNESCAPED_UNICODE (1<<8)
+#define PHP_JSON_PARTIAL_OUTPUT_ON_ERROR (1<<9)
+
+/* Internal flags */
+#define PHP_JSON_OUTPUT_ARRAY 0
+#define PHP_JSON_OUTPUT_OBJECT 1
+
+/* json_decode() options */
+#define PHP_JSON_OBJECT_AS_ARRAY (1<<0)
+#define PHP_JSON_BIGINT_AS_STRING (1<<1)
+
+static inline void php_json_decode(zval *return_value, char *str, int str_len, zend_bool assoc, long depth TSRMLS_DC)
+{
+ php_json_decode_ex(return_value, str, str_len, assoc ? PHP_JSON_OBJECT_AS_ARRAY : 0, depth TSRMLS_CC);
+}
+
+
+#endif /* PHP_JSON_H */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/ext/json/tests/001.phpt b/ext/json/tests/001.phpt
new file mode 100644
index 000000000..02d43c424
--- /dev/null
+++ b/ext/json/tests/001.phpt
@@ -0,0 +1,71 @@
+--TEST--
+json_decode() tests
+--SKIPIF--
+<?php if (!extension_loaded("json")) print "skip"; ?>
+--FILE--
+<?php
+
+var_dump(json_decode());
+var_dump(json_decode(""));
+var_dump(json_decode("", 1));
+var_dump(json_decode("", 0));
+var_dump(json_decode(".", 1));
+var_dump(json_decode(".", 0));
+var_dump(json_decode("<?>"));
+var_dump(json_decode(";"));
+var_dump(json_decode("руссиш"));
+var_dump(json_decode("blah"));
+var_dump(json_decode(NULL));
+var_dump(json_decode('{ "test": { "foo": "bar" } }'));
+var_dump(json_decode('{ "test": { "foo": "" } }'));
+var_dump(json_decode('{ "": { "foo": "" } }'));
+var_dump(json_decode('{ "": { "": "" } }'));
+var_dump(json_decode('{ "": { "": "" }'));
+var_dump(json_decode('{ "": "": "" } }'));
+
+?>
+===DONE===
+--EXPECTF--
+Warning: json_decode() expects at least 1 parameter, 0 given in %s on line %d
+NULL
+NULL
+NULL
+NULL
+NULL
+NULL
+NULL
+NULL
+NULL
+NULL
+NULL
+object(stdClass)#%d (1) {
+ ["test"]=>
+ object(stdClass)#%d (1) {
+ ["foo"]=>
+ string(3) "bar"
+ }
+}
+object(stdClass)#%d (1) {
+ ["test"]=>
+ object(stdClass)#%d (1) {
+ ["foo"]=>
+ string(0) ""
+ }
+}
+object(stdClass)#%d (1) {
+ ["_empty_"]=>
+ object(stdClass)#%d (1) {
+ ["foo"]=>
+ string(0) ""
+ }
+}
+object(stdClass)#%d (1) {
+ ["_empty_"]=>
+ object(stdClass)#%d (1) {
+ ["_empty_"]=>
+ string(0) ""
+ }
+}
+NULL
+NULL
+===DONE===
diff --git a/ext/json/tests/002.phpt b/ext/json/tests/002.phpt
new file mode 100644
index 000000000..5959d4a5f
--- /dev/null
+++ b/ext/json/tests/002.phpt
@@ -0,0 +1,38 @@
+--TEST--
+json_encode() tests
+--SKIPIF--
+<?php if (!extension_loaded("json")) print "skip"; ?>
+--FILE--
+<?php
+
+var_dump(json_encode(""));
+var_dump(json_encode(NULL));
+var_dump(json_encode(TRUE));
+
+var_dump(json_encode(array(""=>"")));
+var_dump(json_encode(array(array(1))));
+var_dump(json_encode(array()));
+
+var_dump(json_encode(array(""=>""), JSON_FORCE_OBJECT));
+var_dump(json_encode(array(array(1)), JSON_FORCE_OBJECT));
+var_dump(json_encode(array(), JSON_FORCE_OBJECT));
+
+var_dump(json_encode(1));
+var_dump(json_encode("руссиш"));
+
+
+echo "Done\n";
+?>
+--EXPECTF--
+string(2) """"
+string(4) "null"
+string(4) "true"
+string(7) "{"":""}"
+string(5) "[[1]]"
+string(2) "[]"
+string(7) "{"":""}"
+string(13) "{"0":{"0":1}}"
+string(2) "{}"
+string(1) "1"
+string(38) ""\u0440\u0443\u0441\u0441\u0438\u0448""
+Done
diff --git a/ext/json/tests/003.phpt b/ext/json/tests/003.phpt
new file mode 100644
index 000000000..4ce5b0fde
--- /dev/null
+++ b/ext/json/tests/003.phpt
@@ -0,0 +1,41 @@
+--TEST--
+json_encode() & endless loop - 1
+--SKIPIF--
+<?php if (!extension_loaded("json")) print "skip"; ?>
+--FILE--
+<?php
+
+$a = array();
+$a[] = &$a;
+
+var_dump($a);
+
+echo "\n";
+
+var_dump(json_encode($a));
+var_dump(json_last_error(), json_last_error_msg());
+
+echo "\n";
+
+var_dump(json_encode($a, JSON_PARTIAL_OUTPUT_ON_ERROR));
+var_dump(json_last_error(), json_last_error_msg());
+
+echo "Done\n";
+?>
+--EXPECTF--
+array(1) {
+ [0]=>
+ &array(1) {
+ [0]=>
+ *RECURSION*
+ }
+}
+
+bool(false)
+int(6)
+string(%d) "Recursion detected"
+
+string(8) "[[null]]"
+int(6)
+string(%d) "Recursion detected"
+Done
diff --git a/ext/json/tests/004.phpt b/ext/json/tests/004.phpt
new file mode 100644
index 000000000..70ef3ffd1
--- /dev/null
+++ b/ext/json/tests/004.phpt
@@ -0,0 +1,38 @@
+--TEST--
+json_encode() & endless loop - 2
+--SKIPIF--
+<?php if (!extension_loaded("json")) print "skip"; ?>
+--FILE--
+<?php
+
+$a = new stdclass;
+$a->prop = $a;
+
+var_dump($a);
+
+echo "\n";
+
+var_dump(json_encode($a));
+var_dump(json_last_error(), json_last_error_msg());
+
+echo "\n";
+
+var_dump(json_encode($a, JSON_PARTIAL_OUTPUT_ON_ERROR));
+var_dump(json_last_error(), json_last_error_msg());
+
+echo "Done\n";
+?>
+--EXPECTF--
+object(stdClass)#%d (1) {
+ ["prop"]=>
+ *RECURSION*
+}
+
+bool(false)
+int(6)
+string(%d) "Recursion detected"
+
+string(22) "{"prop":{"prop":null}}"
+int(6)
+string(%d) "Recursion detected"
+Done
diff --git a/ext/json/tests/005.phpt b/ext/json/tests/005.phpt
new file mode 100644
index 000000000..01a307f4a
--- /dev/null
+++ b/ext/json/tests/005.phpt
@@ -0,0 +1,23 @@
+--TEST--
+json_encode() & endless loop - 3
+--SKIPIF--
+<?php if (!extension_loaded("json")) print "skip"; ?>
+--FILE--
+<?php
+
+$a = array();
+$a[] = $a;
+
+var_dump($a);
+var_dump(json_encode($a));
+
+echo "Done\n";
+?>
+--EXPECTF--
+array(1) {
+ [0]=>
+ array(0) {
+ }
+}
+string(4) "[[]]"
+Done
diff --git a/ext/json/tests/006.phpt b/ext/json/tests/006.phpt
new file mode 100644
index 000000000..e1d4b4688
--- /dev/null
+++ b/ext/json/tests/006.phpt
@@ -0,0 +1,23 @@
+--TEST--
+json_encode() & extended encoding
+--SKIPIF--
+<?php if (!extension_loaded("json")) print "skip"; ?>
+--FILE--
+<?php
+
+$a = array('<foo>',"'bar'",'"baz"','&blong&');
+
+echo "Normal: ", json_encode($a), "\n";
+echo "Tags: ", json_encode($a,JSON_HEX_TAG), "\n";
+echo "Apos: ", json_encode($a,JSON_HEX_APOS), "\n";
+echo "Quot: ", json_encode($a,JSON_HEX_QUOT), "\n";
+echo "Amp: ", json_encode($a,JSON_HEX_AMP), "\n";
+echo "All: ", json_encode($a,JSON_HEX_TAG|JSON_HEX_APOS|JSON_HEX_QUOT|JSON_HEX_AMP), "\n";
+?>
+--EXPECT--
+Normal: ["<foo>","'bar'","\"baz\"","&blong&"]
+Tags: ["\u003Cfoo\u003E","'bar'","\"baz\"","&blong&"]
+Apos: ["<foo>","\u0027bar\u0027","\"baz\"","&blong&"]
+Quot: ["<foo>","'bar'","\u0022baz\u0022","&blong&"]
+Amp: ["<foo>","'bar'","\"baz\"","\u0026blong\u0026"]
+All: ["\u003Cfoo\u003E","\u0027bar\u0027","\u0022baz\u0022","\u0026blong\u0026"]
diff --git a/ext/json/tests/007.phpt b/ext/json/tests/007.phpt
new file mode 100644
index 000000000..7557ac9ed
--- /dev/null
+++ b/ext/json/tests/007.phpt
@@ -0,0 +1,40 @@
+--TEST--
+json_last_error() tests
+--SKIPIF--
+<?php if (!extension_loaded("json")) print "skip"; ?>
+--FILE--
+<?php
+var_dump(json_decode("[1]"));
+var_dump(json_last_error(), json_last_error_msg());
+var_dump(json_decode("[[1]]", false, 2));
+var_dump(json_last_error(), json_last_error_msg());
+var_dump(json_decode("[1}"));
+var_dump(json_last_error(), json_last_error_msg());
+var_dump(json_decode('["' . chr(0) . 'abcd"]'));
+var_dump(json_last_error(), json_last_error_msg());
+var_dump(json_decode("[1"));
+var_dump(json_last_error(), json_last_error_msg());
+
+
+echo "Done\n";
+?>
+--EXPECT--
+array(1) {
+ [0]=>
+ int(1)
+}
+int(0)
+string(8) "No error"
+NULL
+int(1)
+string(28) "Maximum stack depth exceeded"
+NULL
+int(2)
+string(42) "State mismatch (invalid or malformed JSON)"
+NULL
+int(3)
+string(53) "Control character error, possibly incorrectly encoded"
+NULL
+int(4)
+string(12) "Syntax error"
+Done
diff --git a/ext/json/tests/008.phpt b/ext/json/tests/008.phpt
new file mode 100644
index 000000000..f2354d381
--- /dev/null
+++ b/ext/json/tests/008.phpt
@@ -0,0 +1,17 @@
+--TEST--
+json_decode() with large integers
+--SKIPIF--
+<?php if (!extension_loaded("json")) print "skip"; ?>
+--FILE--
+<?php
+$json = '{"largenum":123456789012345678901234567890}';
+$x = json_decode($json);
+var_dump($x->largenum);
+$x = json_decode($json, false, 512, JSON_BIGINT_AS_STRING);
+var_dump($x->largenum);
+echo "Done\n";
+?>
+--EXPECT--
+float(1.2345678901235E+29)
+string(30) "123456789012345678901234567890"
+Done
diff --git a/ext/json/tests/bug40503.phpt b/ext/json/tests/bug40503.phpt
new file mode 100644
index 000000000..48f18a4e0
--- /dev/null
+++ b/ext/json/tests/bug40503.phpt
@@ -0,0 +1,21 @@
+--TEST--
+Bug #40503 (json_encode() value corruption on 32bit systems with overflown values)
+--INI--
+precision=14
+--SKIPIF--
+<?php if (!extension_loaded("json")) print "skip"; ?>
+--FILE--
+<?php
+function show_eq($x,$y) {
+ echo "$x ". ($x==$y ? "==" : "!=") ." $y\n";
+}
+
+$value = 0x7FFFFFFF; #2147483647;
+show_eq("$value", json_encode($value));
+$value++;
+show_eq("$value", json_encode($value));
+
+?>
+--EXPECT--
+2147483647 == 2147483647
+2147483648 == 2147483648
diff --git a/ext/json/tests/bug41034.phpt b/ext/json/tests/bug41034.phpt
new file mode 100644
index 000000000..cc7704122
--- /dev/null
+++ b/ext/json/tests/bug41034.phpt
@@ -0,0 +1,12 @@
+--TEST--
+Bug #41034 (json_encode() ignores null byte started keys in arrays)
+--SKIPIF--
+<?php if (!extension_loaded("json")) print "skip"; ?>
+--FILE--
+<?php
+echo json_encode(array(0,"\0ab"=>1,"\0null-prefixed value"));
+echo "\nDone\n";
+?>
+--EXPECT--
+{"0":0,"\u0000ab":1,"1":"\u0000null-prefixed value"}
+Done
diff --git a/ext/json/tests/bug41067.phpt b/ext/json/tests/bug41067.phpt
new file mode 100644
index 000000000..b20e6e1b5
--- /dev/null
+++ b/ext/json/tests/bug41067.phpt
@@ -0,0 +1,23 @@
+--TEST--
+Bug #41067 (json_encode() problem with UTF-16 input)
+--SKIPIF--
+<?php if (!extension_loaded("json")) print "skip"; ?>
+--FILE--
+<?php
+$single_barline = "\360\235\204\200";
+$array = array($single_barline);
+print bin2hex($single_barline) . "\n";
+// print $single_barline . "\n\n";
+$json = json_encode($array);
+print $json . "\n\n";
+$json_decoded = json_decode($json, true);
+// print $json_decoded[0] . "\n";
+print bin2hex($json_decoded[0]) . "\n";
+print "END\n";
+?>
+--EXPECT--
+f09d8480
+["\ud834\udd00"]
+
+f09d8480
+END
diff --git a/ext/json/tests/bug41403.phpt b/ext/json/tests/bug41403.phpt
new file mode 100644
index 000000000..1a7343122
--- /dev/null
+++ b/ext/json/tests/bug41403.phpt
@@ -0,0 +1,44 @@
+--TEST--
+Bug #41403 (json_decode cannot decode floats if localeconv decimal_point is not '.')
+--SKIPIF--
+<?php
+
+if (!extension_loaded('json')) die('skip');
+
+if (setlocale(LC_NUMERIC, "de_DE") === false) {
+ die("skip no de_DE locale");
+}
+?>
+--INI--
+precision=14
+--FILE--
+<?php
+
+setlocale(LC_NUMERIC, 'de_DE');
+var_dump(json_decode('[2.1]'));
+var_dump(json_decode('[0.15]'));
+var_dump(json_decode('[123.13452345]'));
+var_dump(json_decode('[123,13452345]'));
+
+echo "Done\n";
+?>
+--EXPECTF--
+array(1) {
+ [0]=>
+ float(2,1)
+}
+array(1) {
+ [0]=>
+ float(0,15)
+}
+array(1) {
+ [0]=>
+ float(123,13452345)
+}
+array(2) {
+ [0]=>
+ int(123)
+ [1]=>
+ int(13452345)
+}
+Done
diff --git a/ext/json/tests/bug41504.phpt b/ext/json/tests/bug41504.phpt
new file mode 100644
index 000000000..bef497404
--- /dev/null
+++ b/ext/json/tests/bug41504.phpt
@@ -0,0 +1,31 @@
+--TEST--
+Bug #41504 (json_decode() converts empty array keys to "_empty_")
+--SKIPIF--
+<?php if (!extension_loaded('json')) print 'skip'; ?>
+--FILE--
+<?php
+
+var_dump(json_decode('{"":"value"}', true));
+var_dump(json_decode('{"":"value", "key":"value"}', true));
+var_dump(json_decode('{"key":"value", "":"value"}', true));
+
+echo "Done\n";
+?>
+--EXPECT--
+array(1) {
+ [""]=>
+ string(5) "value"
+}
+array(2) {
+ [""]=>
+ string(5) "value"
+ ["key"]=>
+ string(5) "value"
+}
+array(2) {
+ ["key"]=>
+ string(5) "value"
+ [""]=>
+ string(5) "value"
+}
+Done
diff --git a/ext/json/tests/bug41567.phpt b/ext/json/tests/bug41567.phpt
new file mode 100644
index 000000000..a253a47b7
--- /dev/null
+++ b/ext/json/tests/bug41567.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Bug #41567 (json_encode() double conversion is inconsistent with PHP)
+--INI--
+precision=14
+--SKIPIF--
+<?php if (!extension_loaded('json')) print 'skip'; ?>
+--FILE--
+<?php
+
+$a = json_encode(123456789.12345);
+var_dump(json_decode($a));
+
+echo "Done\n";
+?>
+--EXPECT--
+float(123456789.12345)
+Done
diff --git a/ext/json/tests/bug42090.phpt b/ext/json/tests/bug42090.phpt
new file mode 100644
index 000000000..9e5b3317e
--- /dev/null
+++ b/ext/json/tests/bug42090.phpt
@@ -0,0 +1,24 @@
+--TEST--
+Bug #42090 (json_decode causes segmentation fault)
+--SKIPIF--
+<?php if (!extension_loaded("json")) print "skip"; ?>
+--FILE--
+<?php
+var_dump(
+ json_decode('""'),
+ json_decode('"..".'),
+ json_decode('"'),
+ json_decode('""""'),
+ json_encode('"'),
+ json_decode(json_encode('"')),
+ json_decode(json_encode('""'))
+);
+?>
+--EXPECT--
+string(0) ""
+NULL
+NULL
+NULL
+string(4) ""\"""
+string(1) """
+string(2) """"
diff --git a/ext/json/tests/bug42785.phpt b/ext/json/tests/bug42785.phpt
new file mode 100644
index 000000000..7bdadbed1
--- /dev/null
+++ b/ext/json/tests/bug42785.phpt
@@ -0,0 +1,26 @@
+--TEST--
+Bug #42785 (Incorrect formatting of double values with non-english locales)
+--SKIPIF--
+<?php
+ if (!extension_loaded("json")) {
+ print "skip";
+ } else if (!setlocale(LC_CTYPE, "de_DE", "de", "german", "ge", "de_DE.ISO8859-1", "ISO8859-1")) {
+ die("skip locale needed for this test is not supported on this platform");
+ }
+?>
+--FILE--
+<?php
+setlocale(LC_ALL, "de_DE", "de", "german", "ge", "de_DE.ISO8859-1", "ISO8859-1");
+
+$foo = Array(100.10,"bar");
+var_dump(json_encode($foo));
+
+Class bar {}
+$bar1 = new bar;
+$bar1->a = 100.10;
+$bar1->b = "foo";
+var_dump(json_encode($bar1));
+?>
+--EXPECT--
+string(13) "[100.1,"bar"]"
+string(21) "{"a":100.1,"b":"foo"}"
diff --git a/ext/json/tests/bug43941.phpt b/ext/json/tests/bug43941.phpt
new file mode 100644
index 000000000..48bd7ad52
--- /dev/null
+++ b/ext/json/tests/bug43941.phpt
@@ -0,0 +1,20 @@
+--TEST--
+Bug #43941 (json_encode() invalid UTF-8)
+--SKIPIF--
+<?php if (!extension_loaded("json")) print "skip"; ?>
+--FILE--
+<?php
+
+var_dump(json_encode("abc"));
+var_dump(json_encode("ab\xE0"));
+var_dump(json_encode("ab\xE0", JSON_PARTIAL_OUTPUT_ON_ERROR));
+var_dump(json_encode(array("ab\xE0", "ab\xE0c", "abc"), JSON_PARTIAL_OUTPUT_ON_ERROR));
+
+echo "Done\n";
+?>
+--EXPECTF--
+string(5) ""abc""
+bool(false)
+string(4) "null"
+string(17) "[null,null,"abc"]"
+Done
diff --git a/ext/json/tests/bug45791.phpt b/ext/json/tests/bug45791.phpt
new file mode 100644
index 000000000..7d3706825
--- /dev/null
+++ b/ext/json/tests/bug45791.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Bug #45791 (json_decode() does not handle number 0e0)
+--SKIPIF--
+<?php if (!extension_loaded("json")) print "skip"; ?>
+--FILE--
+<?php
+
+var_dump(json_decode('{"zero": 0e0}'));
+
+?>
+--EXPECT--
+object(stdClass)#1 (1) {
+ ["zero"]=>
+ float(0)
+}
diff --git a/ext/json/tests/bug46215.phpt b/ext/json/tests/bug46215.phpt
new file mode 100644
index 000000000..0ac460cc1
--- /dev/null
+++ b/ext/json/tests/bug46215.phpt
@@ -0,0 +1,29 @@
+--TEST--
+Bug #46215 (json_encode mutates its parameter and has some class-specific state)
+--SKIPIF--
+<?php
+if (!extension_loaded("json")) {
+ die('skip JSON extension not available in this build');
+}
+?>
+--FILE--
+<?php
+
+class foo {
+ protected $a = array();
+}
+
+$a = new foo;
+$x = json_encode($a);
+
+print_r($a);
+
+?>
+--EXPECT--
+foo Object
+(
+ [a:protected] => Array
+ (
+ )
+
+)
diff --git a/ext/json/tests/bug46944.phpt b/ext/json/tests/bug46944.phpt
new file mode 100644
index 000000000..812a54887
--- /dev/null
+++ b/ext/json/tests/bug46944.phpt
@@ -0,0 +1,35 @@
+--TEST--
+Bug #46944 (json_encode() doesn't handle 3 byte utf8 correctly)
+--SKIPIF--
+<?php if (!extension_loaded('json')) print 'skip'; ?>
+--FILE--
+<?php
+
+for ($i = 1; $i <= 16; $i++) {
+ $first = 0xf0|($i >> 2);
+ $second = 0x8f|($i & 3) << 4;
+ $string = sprintf("aa%c%c\xbf\xbdzz", $first, $second);
+ echo json_encode($string) . "\n";
+}
+
+
+echo "Done\n";
+?>
+--EXPECT--
+"aa\ud83f\udffdzz"
+"aa\ud87f\udffdzz"
+"aa\ud8bf\udffdzz"
+"aa\ud8ff\udffdzz"
+"aa\ud93f\udffdzz"
+"aa\ud97f\udffdzz"
+"aa\ud9bf\udffdzz"
+"aa\ud9ff\udffdzz"
+"aa\uda3f\udffdzz"
+"aa\uda7f\udffdzz"
+"aa\udabf\udffdzz"
+"aa\udaff\udffdzz"
+"aa\udb3f\udffdzz"
+"aa\udb7f\udffdzz"
+"aa\udbbf\udffdzz"
+"aa\udbff\udffdzz"
+Done
diff --git a/ext/json/tests/bug47644.phpt b/ext/json/tests/bug47644.phpt
new file mode 100644
index 000000000..5e996b697
--- /dev/null
+++ b/ext/json/tests/bug47644.phpt
@@ -0,0 +1,43 @@
+--TEST--
+Bug #47644 (valid large integers are truncated)
+--SKIPIF--
+<?php
+ if (!extension_loaded('json')) die('skip: json extension not available');
+ if (PHP_INT_SIZE != 8) die("skip this test is for 64bit platform only");
+?>
+--FILE--
+<?php
+
+for ($i = 10000000000000000; $i < 10000000000000006; $i++) {
+ var_dump(json_decode("[$i]"));
+}
+
+
+echo "Done\n";
+?>
+--EXPECT--
+array(1) {
+ [0]=>
+ int(10000000000000000)
+}
+array(1) {
+ [0]=>
+ int(10000000000000001)
+}
+array(1) {
+ [0]=>
+ int(10000000000000002)
+}
+array(1) {
+ [0]=>
+ int(10000000000000003)
+}
+array(1) {
+ [0]=>
+ int(10000000000000004)
+}
+array(1) {
+ [0]=>
+ int(10000000000000005)
+}
+Done
diff --git a/ext/json/tests/bug53946.phpt b/ext/json/tests/bug53946.phpt
new file mode 100644
index 000000000..111438ddc
--- /dev/null
+++ b/ext/json/tests/bug53946.phpt
@@ -0,0 +1,16 @@
+--TEST--
+bug #53946 (json_encode() with JSON_UNESCAPED_UNICODE)
+--SKIPIF--
+<?php if (!extension_loaded("json")) print "skip"; ?>
+--FILE--
+<?php
+var_dump(json_encode("latin 1234 -/ russian мама мыла раму specialchars \x02 \x08 \n U+1D11E >𝄞<"));
+var_dump(json_encode("latin 1234 -/ russian мама мыла раму specialchars \x02 \x08 \n U+1D11E >𝄞<", JSON_UNESCAPED_UNICODE));
+var_dump(json_encode("ab\xE0"));
+var_dump(json_encode("ab\xE0", JSON_UNESCAPED_UNICODE));
+?>
+--EXPECTF--
+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<""
+string(100) ""latin 1234 -\/ russian мама мыла раму specialchars \u0002 \b \n U+1D11E >𝄞<""
+bool(false)
+bool(false)
diff --git a/ext/json/tests/bug54058.phpt b/ext/json/tests/bug54058.phpt
new file mode 100644
index 000000000..df1b3130f
--- /dev/null
+++ b/ext/json/tests/bug54058.phpt
@@ -0,0 +1,40 @@
+--TEST--
+Bug #54058 (json_last_error() invalid UTF-8 produces wrong error)
+--SKIPIF--
+<?php if (!extension_loaded("json")) print "skip"; ?>
+--FILE--
+<?php
+
+$bad_utf8 = quoted_printable_decode('=B0');
+
+json_encode($bad_utf8);
+var_dump(json_last_error(), json_last_error_msg());
+
+$a = new stdclass;
+$a->foo = quoted_printable_decode('=B0');
+json_encode($a);
+var_dump(json_last_error(), json_last_error_msg());
+
+$b = new stdclass;
+$b->foo = $bad_utf8;
+$b->bar = 1;
+json_encode($b);
+var_dump(json_last_error(), json_last_error_msg());
+
+$c = array(
+ 'foo' => $bad_utf8,
+ 'bar' => 1
+);
+json_encode($c);
+var_dump(json_last_error(), json_last_error_msg());
+
+?>
+--EXPECTF--
+int(5)
+string(56) "Malformed UTF-8 characters, possibly incorrectly encoded"
+int(5)
+string(56) "Malformed UTF-8 characters, possibly incorrectly encoded"
+int(5)
+string(56) "Malformed UTF-8 characters, possibly incorrectly encoded"
+int(5)
+string(56) "Malformed UTF-8 characters, possibly incorrectly encoded"
diff --git a/ext/json/tests/bug54484.phpt b/ext/json/tests/bug54484.phpt
new file mode 100644
index 000000000..d698ab541
--- /dev/null
+++ b/ext/json/tests/bug54484.phpt
@@ -0,0 +1,25 @@
+--TEST--
+Bug #54484 (Empty string in json_decode doesn't reset json_last_error)
+--SKIPIF--
+<?php if (!extension_loaded("json")) print "skip"; ?>
+--FILE--
+<?php
+json_decode('{"test":"test"}');
+var_dump(json_last_error());
+
+json_decode("");
+var_dump(json_last_error());
+
+
+json_decode("invalid json");
+var_dump(json_last_error());
+
+
+json_decode("");
+var_dump(json_last_error());
+?>
+--EXPECT--
+int(0)
+int(0)
+int(4)
+int(0)
diff --git a/ext/json/tests/bug55543.phpt b/ext/json/tests/bug55543.phpt
new file mode 100644
index 000000000..8657fe776
--- /dev/null
+++ b/ext/json/tests/bug55543.phpt
@@ -0,0 +1,13 @@
+--TEST--
+Bug #55543 (json_encode() with JSON_NUMERIC_CHECK & numeric string properties)
+--SKIPIF--
+<?php if (!extension_loaded("json")) print "skip"; ?>
+--FILE--
+<?php
+$a = new stdClass;
+$a->{"1"} = "5";
+
+var_dump(json_encode($a, JSON_NUMERIC_CHECK));
+?>
+--EXPECT--
+string(7) "{"1":5}"
diff --git a/ext/json/tests/bug61537.phpt b/ext/json/tests/bug61537.phpt
new file mode 100644
index 000000000..80ed051c9
--- /dev/null
+++ b/ext/json/tests/bug61537.phpt
@@ -0,0 +1,39 @@
+--TEST--
+Bug #61537 (json_encode() incorrectly truncates/discards information)
+--SKIPIF--
+<?php if (!extension_loaded("json")) print "skip"; ?>
+--FILE--
+<?php
+$invalid_utf8 = "\x9f";
+
+var_dump(json_encode($invalid_utf8));
+var_dump(json_last_error(), json_last_error_msg());
+
+var_dump(json_encode($invalid_utf8, JSON_PARTIAL_OUTPUT_ON_ERROR));
+var_dump(json_last_error(), json_last_error_msg());
+
+echo "\n";
+
+$invalid_utf8 = "an invalid sequen\xce in the middle of a string";
+
+var_dump(json_encode($invalid_utf8));
+var_dump(json_last_error(), json_last_error_msg());
+
+var_dump(json_encode($invalid_utf8, JSON_PARTIAL_OUTPUT_ON_ERROR));
+var_dump(json_last_error(), json_last_error_msg());
+
+?>
+--EXPECTF--
+bool(false)
+int(5)
+string(56) "Malformed UTF-8 characters, possibly incorrectly encoded"
+string(4) "null"
+int(5)
+string(56) "Malformed UTF-8 characters, possibly incorrectly encoded"
+
+bool(false)
+int(5)
+string(56) "Malformed UTF-8 characters, possibly incorrectly encoded"
+string(4) "null"
+int(5)
+string(56) "Malformed UTF-8 characters, possibly incorrectly encoded"
diff --git a/ext/json/tests/bug61978.phpt b/ext/json/tests/bug61978.phpt
new file mode 100644
index 000000000..c34b03f8f
--- /dev/null
+++ b/ext/json/tests/bug61978.phpt
@@ -0,0 +1,43 @@
+--TEST--
+Bug #61978 (Object recursion not detected for classes that implement JsonSerializable)
+--SKIPIF--
+<?php if (!extension_loaded("json")) print "skip"; ?>
+--FILE--
+<?php
+
+class JsonTest1 {
+ public $test;
+ public $me;
+ public function __construct() {
+ $this->test = '123';
+ $this->me = $this;
+ }
+}
+
+class JsonTest2 implements JsonSerializable {
+ public $test;
+ public function __construct() {
+ $this->test = '123';
+ }
+ public function jsonSerialize() {
+ return array(
+ 'test' => $this->test,
+ 'me' => $this
+ );
+ }
+}
+
+
+$obj1 = new JsonTest1();
+var_dump(json_encode($obj1, JSON_PARTIAL_OUTPUT_ON_ERROR));
+
+echo "==\n";
+
+$obj2 = new JsonTest2();
+var_dump(json_encode($obj2, JSON_PARTIAL_OUTPUT_ON_ERROR));
+
+?>
+--EXPECTF--
+string(44) "{"test":"123","me":{"test":"123","me":null}}"
+==
+string(44) "{"test":"123","me":{"test":"123","me":null}}"
diff --git a/ext/json/tests/bug62369.phpt b/ext/json/tests/bug62369.phpt
new file mode 100644
index 000000000..a5efd802c
--- /dev/null
+++ b/ext/json/tests/bug62369.phpt
@@ -0,0 +1,34 @@
+--TEST--
+FR #62369 (Segfault on json_encode(deeply_nested_array)
+--SKIPIF--
+<?php if (!extension_loaded("json")) print "skip"; ?>
+--FILE--
+<?php
+
+$array = array();
+for ($i=0; $i<550; $i++) {
+ $array = array($array);
+}
+
+json_encode($array, 0, 551);
+switch (json_last_error()) {
+ case JSON_ERROR_NONE:
+ echo 'OK'.PHP_EOL;
+ break;
+ case JSON_ERROR_DEPTH:
+ echo 'ERROR'.PHP_EOL;
+ break;
+}
+
+json_encode($array, 0, 540);
+switch (json_last_error()) {
+ case JSON_ERROR_NONE:
+ echo 'OK'.PHP_EOL;
+ break;
+ case JSON_ERROR_DEPTH:
+ echo 'ERROR'.PHP_EOL;
+ break;
+}
+--EXPECTF--
+OK
+ERROR
diff --git a/ext/json/tests/bug63737.phpt b/ext/json/tests/bug63737.phpt
new file mode 100644
index 000000000..1fb06d485
--- /dev/null
+++ b/ext/json/tests/bug63737.phpt
@@ -0,0 +1,32 @@
+--TEST--
+Bug #63737 (json_decode does not properly decode with options parameter)
+--SKIPIF--
+<?php if (!extension_loaded("json")) print "skip"; ?>
+--FILE--
+<?php
+function decode($json) {
+ $x = json_decode($json);
+ var_dump($x);
+ $x = json_decode($json, false, 512, JSON_BIGINT_AS_STRING);
+ var_dump($x);
+}
+
+decode('123456789012345678901234567890');
+decode('-123456789012345678901234567890');
+
+// This shouldn't affect floats, but let's check that.
+decode('123456789012345678901234567890.1');
+decode('-123456789012345678901234567890.1');
+
+echo "Done\n";
+?>
+--EXPECT--
+float(1.2345678901235E+29)
+string(30) "123456789012345678901234567890"
+float(-1.2345678901235E+29)
+string(31) "-123456789012345678901234567890"
+float(1.2345678901235E+29)
+float(1.2345678901235E+29)
+float(-1.2345678901235E+29)
+float(-1.2345678901235E+29)
+Done
diff --git a/ext/json/tests/fail001.phpt b/ext/json/tests/fail001.phpt
new file mode 100644
index 000000000..1bf9f1210
--- /dev/null
+++ b/ext/json/tests/fail001.phpt
@@ -0,0 +1,166 @@
+--TEST--
+JSON (http://www.crockford.com/JSON/JSON_checker/test/fail*.json)
+--SKIPIF--
+<?php
+ if (!extension_loaded('json')) die('skip: json extension not available');
+?>
+--FILE--
+<?php
+
+$tests = array('"A JSON payload should be an object or array, not a string."',
+ '["Unclosed array"',
+ '{unquoted_key: "keys must be quoted}',
+ '["extra comma",]',
+ '["double extra comma",,]',
+ '[ , "<-- missing value"]',
+ '["Comma after the close"],',
+ '["Extra close"]]',
+ '{"Extra comma": true,}',
+ '{"Extra value after close": true} "misplaced quoted value"',
+ '{"Illegal expression": 1 + 2}',
+ '{"Illegal invocation": alert()}',
+ '{"Numbers cannot have leading zeroes": 013}',
+ '{"Numbers cannot be hex": 0x14}',
+ '["Illegal backslash escape: \\x15"]',
+ '["Illegal backslash escape: \\\'"]',
+ '["Illegal backslash escape: \\017"]',
+ '[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]',
+ '{"Missing colon" null}',
+ '{"Double colon":: null}',
+ '{"Comma instead of colon", null}',
+ '["Colon instead of comma": false]',
+ '["Bad value", truth]',
+ "['single quote']");
+
+foreach ($tests as $test)
+{
+ echo 'Testing: ' . $test . "\n";
+ echo "AS OBJECT\n";
+ var_dump(json_decode($test));
+ echo "AS ARRAY\n";
+ var_dump(json_decode($test, true));
+}
+
+?>
+--EXPECT--
+Testing: "A JSON payload should be an object or array, not a string."
+AS OBJECT
+string(58) "A JSON payload should be an object or array, not a string."
+AS ARRAY
+string(58) "A JSON payload should be an object or array, not a string."
+Testing: ["Unclosed array"
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: {unquoted_key: "keys must be quoted}
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: ["extra comma",]
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: ["double extra comma",,]
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: [ , "<-- missing value"]
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: ["Comma after the close"],
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: ["Extra close"]]
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: {"Extra comma": true,}
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: {"Extra value after close": true} "misplaced quoted value"
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: {"Illegal expression": 1 + 2}
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: {"Illegal invocation": alert()}
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: {"Numbers cannot have leading zeroes": 013}
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: {"Numbers cannot be hex": 0x14}
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: ["Illegal backslash escape: \x15"]
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: ["Illegal backslash escape: \'"]
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: ["Illegal backslash escape: \017"]
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: {"Missing colon" null}
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: {"Double colon":: null}
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: {"Comma instead of colon", null}
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: ["Colon instead of comma": false]
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: ["Bad value", truth]
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: ['single quote']
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+
diff --git a/ext/json/tests/inf_nan_error.phpt b/ext/json/tests/inf_nan_error.phpt
new file mode 100644
index 000000000..f9deecc46
--- /dev/null
+++ b/ext/json/tests/inf_nan_error.phpt
@@ -0,0 +1,45 @@
+--TEST--
+An error is thrown when INF or NaN are encoded
+--SKIPIF--
+<?php if (!extension_loaded("json")) print "skip"; ?>
+--FILE--
+<?php
+
+$inf = INF;
+
+var_dump($inf);
+
+var_dump(json_encode($inf));
+var_dump(json_last_error(), json_last_error_msg());
+
+var_dump(json_encode($inf, JSON_PARTIAL_OUTPUT_ON_ERROR));
+var_dump(json_last_error(), json_last_error_msg());
+
+echo "\n";
+
+$nan = NAN;
+
+var_dump($nan);
+
+var_dump(json_encode($nan));
+var_dump(json_last_error(), json_last_error_msg());
+
+var_dump(json_encode($nan, JSON_PARTIAL_OUTPUT_ON_ERROR));
+var_dump(json_last_error(), json_last_error_msg());
+?>
+--EXPECTF--
+float(INF)
+bool(false)
+int(7)
+string(34) "Inf and NaN cannot be JSON encoded"
+string(1) "0"
+int(7)
+string(34) "Inf and NaN cannot be JSON encoded"
+
+float(NAN)
+bool(false)
+int(7)
+string(34) "Inf and NaN cannot be JSON encoded"
+string(1) "0"
+int(7)
+string(34) "Inf and NaN cannot be JSON encoded"
diff --git a/ext/json/tests/json_decode_basic.phpt b/ext/json/tests/json_decode_basic.phpt
new file mode 100644
index 000000000..6dbeadb36
--- /dev/null
+++ b/ext/json/tests/json_decode_basic.phpt
@@ -0,0 +1,187 @@
+--TEST--
+Test json_decode() function : basic functionality
+--SKIPIF--
+<?php
+if (!extension_loaded("json")) {
+ die('skip JSON extension not available in this build');
+}
+?>
+--FILE--
+<?php
+/* Prototype : mixed json_decode ( string $json [, bool $assoc ] )
+ * Description: Decodes a JSON string
+ * Source code: ext/json/php_json.c
+ * Alias to functions:
+ */
+echo "*** Testing json_decode() : basic functionality ***\n";
+
+// array with different values for $string
+$inputs = array (
+ '0',
+ '123',
+ '-123',
+ '2147483647',
+ '-2147483648',
+ '123.456',
+ '1230',
+ '-1230',
+ 'true',
+ 'false',
+ 'null',
+ '"abc"',
+ '"Hello World\r\n"',
+ '[]',
+ '[1,2,3,4,5]',
+ '{"myInt":99,"myFloat":123.45,"myNull":null,"myBool":true,"myString":"Hello World"}',
+ '{"Jan":31,"Feb":29,"Mar":31,"April":30,"May":31,"June":30}',
+ '""',
+ '{}'
+);
+
+// loop through with each element of the $inputs array to test json_decode() function
+$count = 1;
+foreach($inputs as $input) {
+ echo "-- Iteration $count --\n";
+ var_dump(json_decode($input));
+ var_dump(json_decode($input, TRUE));
+ $count ++;
+}
+
+?>
+===Done===
+--EXPECTF--
+*** Testing json_decode() : basic functionality ***
+-- Iteration 1 --
+int(0)
+int(0)
+-- Iteration 2 --
+int(123)
+int(123)
+-- Iteration 3 --
+int(-123)
+int(-123)
+-- Iteration 4 --
+int(2147483647)
+int(2147483647)
+-- Iteration 5 --
+int(-2147483648)
+int(-2147483648)
+-- Iteration 6 --
+float(123.456)
+float(123.456)
+-- Iteration 7 --
+int(1230)
+int(1230)
+-- Iteration 8 --
+int(-1230)
+int(-1230)
+-- Iteration 9 --
+bool(true)
+bool(true)
+-- Iteration 10 --
+bool(false)
+bool(false)
+-- Iteration 11 --
+NULL
+NULL
+-- Iteration 12 --
+string(3) "abc"
+string(3) "abc"
+-- Iteration 13 --
+string(13) "Hello World
+"
+string(13) "Hello World
+"
+-- Iteration 14 --
+array(0) {
+}
+array(0) {
+}
+-- Iteration 15 --
+array(5) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ [3]=>
+ int(4)
+ [4]=>
+ int(5)
+}
+array(5) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ [3]=>
+ int(4)
+ [4]=>
+ int(5)
+}
+-- Iteration 16 --
+object(stdClass)#%d (5) {
+ ["myInt"]=>
+ int(99)
+ ["myFloat"]=>
+ float(123.45)
+ ["myNull"]=>
+ NULL
+ ["myBool"]=>
+ bool(true)
+ ["myString"]=>
+ string(11) "Hello World"
+}
+array(5) {
+ ["myInt"]=>
+ int(99)
+ ["myFloat"]=>
+ float(123.45)
+ ["myNull"]=>
+ NULL
+ ["myBool"]=>
+ bool(true)
+ ["myString"]=>
+ string(11) "Hello World"
+}
+-- Iteration 17 --
+object(stdClass)#%d (6) {
+ ["Jan"]=>
+ int(31)
+ ["Feb"]=>
+ int(29)
+ ["Mar"]=>
+ int(31)
+ ["April"]=>
+ int(30)
+ ["May"]=>
+ int(31)
+ ["June"]=>
+ int(30)
+}
+array(6) {
+ ["Jan"]=>
+ int(31)
+ ["Feb"]=>
+ int(29)
+ ["Mar"]=>
+ int(31)
+ ["April"]=>
+ int(30)
+ ["May"]=>
+ int(31)
+ ["June"]=>
+ int(30)
+}
+-- Iteration 18 --
+string(0) ""
+string(0) ""
+-- Iteration 19 --
+object(stdClass)#%d (0) {
+}
+array(0) {
+}
+===Done===
diff --git a/ext/json/tests/json_decode_error.phpt b/ext/json/tests/json_decode_error.phpt
new file mode 100644
index 000000000..4d5d4e4be
--- /dev/null
+++ b/ext/json/tests/json_decode_error.phpt
@@ -0,0 +1,39 @@
+--TEST--
+Test json_decode() function : error conditions
+--SKIPIF--
+<?php
+if (!extension_loaded("json")) {
+ die('skip JSON extension not available in this build');
+}
+?>
+--FILE--
+<?php
+/* Prototype : mixed json_decode ( string $json [, bool $assoc=false [, int $depth=512 ]] )
+ * Description: Decodes a JSON string
+ * Source code: ext/json/php_json.c
+ * Alias to functions:
+ */
+echo "*** Testing json_decode() : error conditions ***\n";
+
+echo "\n-- Testing json_decode() function with no arguments --\n";
+var_dump( json_decode() );
+
+echo "\n-- Testing json_decode() function with more than expected no. of arguments --\n";
+$extra_arg = 10;
+var_dump( json_decode('"abc"', TRUE, 512, 0, $extra_arg) );
+
+?>
+===Done===
+--EXPECTF--
+*** Testing json_decode() : error conditions ***
+
+-- Testing json_decode() function with no arguments --
+
+Warning: json_decode() expects at least 1 parameter, 0 given in %s on line %d
+NULL
+
+-- Testing json_decode() function with more than expected no. of arguments --
+
+Warning: json_decode() expects at most 4 parameters, 5 given in %s on line %d
+NULL
+===Done===
diff --git a/ext/json/tests/json_encode_basic.phpt b/ext/json/tests/json_encode_basic.phpt
new file mode 100644
index 000000000..fc348eed8
--- /dev/null
+++ b/ext/json/tests/json_encode_basic.phpt
@@ -0,0 +1,156 @@
+--TEST--
+Test json_encode() function : basic functionality
+--SKIPIF--
+<?php
+if (!extension_loaded("json")) {
+ die('skip JSON extension not available in this build');
+}
+?>
+--FILE--
+<?php
+/* Prototype : string json_encode ( mixed $value )
+ * Description: Returns the JSON representation of a value
+ * Source code: ext/json/php_json.c
+ * Alias to functions:
+ */
+echo "*** Testing json_encode() : basic functionality ***\n";
+
+//get an unset variable
+$unset_var = 10;
+unset ($unset_var);
+
+// get a resource variable
+$fp = fopen(__FILE__, "r");
+
+// get an object
+class sample {
+}
+
+$obj = new sample();
+$obj->MyInt = 99;
+$obj->MyFloat = 123.45;
+$obj->MyBool = true;
+$obj->MyNull = null;
+$obj->MyString = "Hello World";
+
+// array with different values for $string
+$inputs = array (
+
+ // integers
+/*1*/ 0,
+ 123,
+ -123,
+ 2147483647,
+ -2147483648,
+
+ // floats
+/*6*/ 123.456,
+ 1.23E3,
+ -1.23E3,
+
+ // boolean
+/*9*/ TRUE,
+ true,
+ FALSE,
+ false,
+
+ // NULL
+/*13*/ NULL,
+ null,
+
+ // strings
+/*15*/ "abc",
+ 'abc',
+ "Hello\t\tWorld\n",
+
+ // arrays
+/*18*/ array(),
+ array(1,2,3,4,5),
+ array(1 => "Sun", 2=>"Mon", 3 => "Tue", 4 => "Wed", 5 => "Thur", 6 => "Fri", 7 => "Sat"),
+ array("Jan" => 31, "Feb" => 29, "Mar" => 31, "April" => 30, "May" => 31, "June" => 30),
+
+ // empty data
+/*22*/ "",
+ '',
+
+ // undefined data
+/*24*/ @$undefined_var,
+
+ // unset data
+/*25*/ @$unset_var,
+
+ // resource variable
+/*26*/ $fp,
+
+ // object variable
+/*27*/ $obj
+
+);
+
+// loop through with each element of the $inputs array to test json_encode() function
+$count = 1;
+foreach($inputs as $input) {
+ echo "-- Iteration $count --\n";
+ var_dump(json_encode($input));
+ $count ++;
+}
+
+?>
+===Done===
+--EXPECTF--
+*** Testing json_encode() : basic functionality ***
+-- Iteration 1 --
+string(1) "0"
+-- Iteration 2 --
+string(3) "123"
+-- Iteration 3 --
+string(4) "-123"
+-- Iteration 4 --
+string(10) "2147483647"
+-- Iteration 5 --
+string(11) "-2147483648"
+-- Iteration 6 --
+string(7) "123.456"
+-- Iteration 7 --
+string(4) "1230"
+-- Iteration 8 --
+string(5) "-1230"
+-- Iteration 9 --
+string(4) "true"
+-- Iteration 10 --
+string(4) "true"
+-- Iteration 11 --
+string(5) "false"
+-- Iteration 12 --
+string(5) "false"
+-- Iteration 13 --
+string(4) "null"
+-- Iteration 14 --
+string(4) "null"
+-- Iteration 15 --
+string(5) ""abc""
+-- Iteration 16 --
+string(5) ""abc""
+-- Iteration 17 --
+string(18) ""Hello\t\tWorld\n""
+-- Iteration 18 --
+string(2) "[]"
+-- Iteration 19 --
+string(11) "[1,2,3,4,5]"
+-- Iteration 20 --
+string(72) "{"1":"Sun","2":"Mon","3":"Tue","4":"Wed","5":"Thur","6":"Fri","7":"Sat"}"
+-- Iteration 21 --
+string(58) "{"Jan":31,"Feb":29,"Mar":31,"April":30,"May":31,"June":30}"
+-- Iteration 22 --
+string(2) """"
+-- Iteration 23 --
+string(2) """"
+-- Iteration 24 --
+string(4) "null"
+-- Iteration 25 --
+string(4) "null"
+-- Iteration 26 --
+bool(false)
+-- Iteration 27 --
+string(82) "{"MyInt":99,"MyFloat":123.45,"MyBool":true,"MyNull":null,"MyString":"Hello World"}"
+===Done===
diff --git a/ext/json/tests/json_encode_basic_utf8.phpt b/ext/json/tests/json_encode_basic_utf8.phpt
new file mode 100644
index 000000000..a8e8b425e
--- /dev/null
+++ b/ext/json/tests/json_encode_basic_utf8.phpt
@@ -0,0 +1,26 @@
+--TEST--
+Test json_encode() function : basic functionality with UTF8 string input
+--SKIPIF--
+<?php
+if (!extension_loaded("json")) {
+ die('skip JSON extension not available in this build');
+}
+?>
+--FILE--
+<?php
+/* Prototype : string json_encode ( mixed $value )
+ * Description: Returns the JSON representation of a value
+ * Source code: ext/json/php_json.c
+ * Alias to functions:
+ */
+echo "*** Testing json_encode() : basic functionality with UTF-8 input***\n";
+
+$utf8_string = base64_decode('5pel5pys6Kqe44OG44Kt44K544OI44Gn44GZ44CCMDEyMzTvvJXvvJbvvJfvvJjvvJnjgII=');
+var_dump(json_encode($utf8_string));
+
+?>
+===Done===
+--EXPECTF--
+*** Testing json_encode() : basic functionality with UTF-8 input***
+string(103) ""\u65e5\u672c\u8a9e\u30c6\u30ad\u30b9\u30c8\u3067\u3059\u300201234\uff15\uff16\uff17\uff18\uff19\u3002""
+===Done===
diff --git a/ext/json/tests/json_encode_error.phpt b/ext/json/tests/json_encode_error.phpt
new file mode 100644
index 000000000..547c8bef1
--- /dev/null
+++ b/ext/json/tests/json_encode_error.phpt
@@ -0,0 +1,38 @@
+--TEST--
+Test json_encode() function : error conditions
+--SKIPIF--
+<?php
+if (!extension_loaded("json")) {
+ die('skip JSON extension not available in this build');
+}
+?>
+--FILE--
+<?php
+/* Prototype : string json_encode ( mixed $value [, int $options=0 ] )
+ * Description: Returns the JSON representation of a value
+ * Source code: ext/json/php_json.c
+ * Alias to functions:
+ */
+
+echo "*** Testing json_encode() : error conditions ***\n";
+
+echo "\n-- Testing json_encode() function with no arguments --\n";
+var_dump( json_encode() );
+
+echo "\n-- Testing json_encode() function with more than expected no. of arguments --\n";
+$extra_arg = 10;
+var_dump( json_encode("abc", 0, $extra_arg) );
+
+?>
+===Done===
+--EXPECTF--
+*** Testing json_encode() : error conditions ***
+
+-- Testing json_encode() function with no arguments --
+
+Warning: json_encode() expects at least 1 parameter, 0 given in %s on line %d
+NULL
+
+-- Testing json_encode() function with more than expected no. of arguments --
+string(5) ""abc""
+===Done===
diff --git a/ext/json/tests/json_encode_numeric.phpt b/ext/json/tests/json_encode_numeric.phpt
new file mode 100644
index 000000000..539235019
--- /dev/null
+++ b/ext/json/tests/json_encode_numeric.phpt
@@ -0,0 +1,26 @@
+--TEST--
+Test json_encode() function with numeric flag
+--SKIPIF--
+<?php
+if (!extension_loaded("json")) {
+ die('skip JSON extension not available in this build');
+}
+?>
+--FILE--
+<?php
+var_dump(
+ json_encode("1", JSON_NUMERIC_CHECK),
+ json_encode("9.4324", JSON_NUMERIC_CHECK),
+ json_encode(array("122321", "3232595.33423"), JSON_NUMERIC_CHECK),
+ json_encode("1"),
+ json_encode("9.4324"),
+ json_encode(array("122321", "3232595.33423"))
+);
+?>
+--EXPECT--
+string(1) "1"
+string(6) "9.4324"
+string(22) "[122321,3232595.33423]"
+string(3) ""1""
+string(8) ""9.4324""
+string(26) "["122321","3232595.33423"]"
diff --git a/ext/json/tests/json_encode_pretty_print.phpt b/ext/json/tests/json_encode_pretty_print.phpt
new file mode 100644
index 000000000..43b93aafe
--- /dev/null
+++ b/ext/json/tests/json_encode_pretty_print.phpt
@@ -0,0 +1,40 @@
+--TEST--
+json_encode() with JSON_PRETTY_PRINT
+--SKIPIF--
+<?php if (!extension_loaded("json")) print "skip"; ?>
+--FILE--
+<?php
+function encode_decode($json) {
+ $struct = json_decode($json);
+ $pretty = json_encode($struct, JSON_PRETTY_PRINT);
+ echo "$pretty\n";
+ $pretty = json_decode($pretty);
+ printf("Match: %d\n", $pretty == $struct);
+}
+
+encode_decode('[1,2,3,[1,2,3]]');
+encode_decode('{"a":1,"b":[1,2],"c":{"d":42}}');
+?>
+--EXPECT--
+[
+ 1,
+ 2,
+ 3,
+ [
+ 1,
+ 2,
+ 3
+ ]
+]
+Match: 1
+{
+ "a": 1,
+ "b": [
+ 1,
+ 2
+ ],
+ "c": {
+ "d": 42
+ }
+}
+Match: 1
diff --git a/ext/json/tests/json_encode_unescaped_slashes.phpt b/ext/json/tests/json_encode_unescaped_slashes.phpt
new file mode 100644
index 000000000..72ebae927
--- /dev/null
+++ b/ext/json/tests/json_encode_unescaped_slashes.phpt
@@ -0,0 +1,12 @@
+--TEST--
+json_decode() tests
+--SKIPIF--
+<?php if (!extension_loaded("json")) print "skip"; ?>
+--FILE--
+<?php
+var_dump(json_encode('a/b'));
+var_dump(json_encode('a/b', JSON_UNESCAPED_SLASHES));
+?>
+--EXPECT--
+string(6) ""a\/b""
+string(5) ""a/b""
diff --git a/ext/json/tests/pass001.1.phpt b/ext/json/tests/pass001.1.phpt
new file mode 100644
index 000000000..a51f88578
--- /dev/null
+++ b/ext/json/tests/pass001.1.phpt
@@ -0,0 +1,890 @@
+--TEST--
+JSON (http://www.crockford.com/JSON/JSON_checker/test/pass1.json)
+--INI--
+precision=14
+--SKIPIF--
+<?php
+ if (!extension_loaded('json')) die('skip: json extension not available');
+ if (PHP_INT_SIZE != 4) die("skip this test is for 32bit platform only");
+?>
+--FILE--
+<?php
+/* Modified to test unescaped UNICODE as keys and values.
+ * Modified to test numbers with exponents without a decimal point.
+ * Modified to test empty string values.
+ * Modified to test a mix of integers and strings as keys.
+ */
+// Expect warnings about INF.
+ini_set("error_reporting", E_ALL & ~E_WARNING);
+
+$test = "
+[
+ \"JSON Test Pattern pass1\",
+ {\"object with 1 member\":[\"array with 1 element\"]},
+ {},
+ [],
+ -42,
+ true,
+ false,
+ null,
+ {
+ \"integer\": 1234567890,
+ \"real\": -9876.543210,
+ \"e\": 0.123456789e-12,
+ \"E\": 1.234567890E+34,
+ \"\": 23456789012E666,
+ \"E no .\": 4E12,
+ \"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\",
+ \"unicode\": \"\\u30d7\\u30ec\\u30b9\\u30ad\\u30c3\\u30c8\",
+ \"プレスキット\": \"プレスキット\",
+ \"empty_string\": \"\",
+ \"true\": true,
+ \"false\": false,
+ \"null\": null,
+ \"array\":[ ],
+ \"object\":{ },
+ \"123\":{\"456\":{\"abc\":{\"789\":\"def\",\"012\":[1,2,\"5\",500],\"ghi\":[1,2,\"five\",50,\"sixty\"]}}},
+ \"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],
+ \"jsontext\": \"{\\\"object with 1 member\\\":[\\\"array with 1 element\\\"]}\",
+ \"quotes\": \"&#34; \\u0022 %22 0x22 034 &#x22;\",
+ \"\\/\\\\\\\"\\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\"]
+";
+
+echo 'Testing: ' . $test . "\n";
+echo "DECODE: AS OBJECT\n";
+$obj = json_decode($test);
+var_dump($obj);
+echo "DECODE: AS ARRAY\n";
+$arr = json_decode($test, true);
+var_dump($arr);
+
+echo "ENCODE: FROM OBJECT\n";
+$obj_enc = json_encode($obj, JSON_PARTIAL_OUTPUT_ON_ERROR);
+echo $obj_enc . "\n";
+echo "ENCODE: FROM ARRAY\n";
+$arr_enc = json_encode($arr, JSON_PARTIAL_OUTPUT_ON_ERROR);
+echo $arr_enc . "\n";
+
+echo "DECODE AGAIN: AS OBJECT\n";
+$obj = json_decode($obj_enc);
+var_dump($obj);
+echo "DECODE AGAIN: AS ARRAY\n";
+$arr = json_decode($arr_enc, true);
+var_dump($arr);
+
+?>
+--EXPECTF--
+Testing:
+[
+ "JSON Test Pattern pass1",
+ {"object with 1 member":["array with 1 element"]},
+ {},
+ [],
+ -42,
+ true,
+ false,
+ null,
+ {
+ "integer": 1234567890,
+ "real": -9876.543210,
+ "e": 0.123456789e-12,
+ "E": 1.234567890E+34,
+ "": 23456789012E666,
+ "E no .": 4E12,
+ "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",
+ "unicode": "\u30d7\u30ec\u30b9\u30ad\u30c3\u30c8",
+ "プレスキット": "プレスキット",
+ "empty_string": "",
+ "true": true,
+ "false": false,
+ "null": null,
+ "array":[ ],
+ "object":{ },
+ "123":{"456":{"abc":{"789":"def","012":[1,2,"5",500],"ghi":[1,2,"five",50,"sixty"]}}},
+ "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],
+ "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}",
+ "quotes": "&#34; \u0022 %22 0x22 034 &#x22;",
+ "\/\\\"\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"]
+
+DECODE: AS OBJECT
+array(14) {
+ [0]=>
+ string(23) "JSON Test Pattern pass1"
+ [1]=>
+ object(stdClass)#%d (1) {
+ ["object with 1 member"]=>
+ array(1) {
+ [0]=>
+ string(20) "array with 1 element"
+ }
+ }
+ [2]=>
+ object(stdClass)#%d (0) {
+ }
+ [3]=>
+ array(0) {
+ }
+ [4]=>
+ int(-42)
+ [5]=>
+ bool(true)
+ [6]=>
+ bool(false)
+ [7]=>
+ NULL
+ [8]=>
+ object(stdClass)#%d (36) {
+ ["integer"]=>
+ int(1234567890)
+ ["real"]=>
+ float(-9876.54321)
+ ["e"]=>
+ float(1.23456789E-13)
+ ["E"]=>
+ float(1.23456789E+34)
+ ["_empty_"]=>
+ float(INF)
+ ["E no ."]=>
+ float(4000000000000)
+ ["zero"]=>
+ int(0)
+ ["one"]=>
+ int(1)
+ ["space"]=>
+ string(1) " "
+ ["quote"]=>
+ string(1) """
+ ["backslash"]=>
+ string(1) "\"
+ ["controls"]=>
+ string(5) "
+ "
+ ["slash"]=>
+ string(5) "/ & /"
+ ["alpha"]=>
+ string(25) "abcdefghijklmnopqrstuvwyz"
+ ["ALPHA"]=>
+ string(25) "ABCDEFGHIJKLMNOPQRSTUVWYZ"
+ ["digit"]=>
+ string(10) "0123456789"
+ ["special"]=>
+ string(31) "`1~!@#$%^&*()_+-={':[,]}|;.</>?"
+ ["hex"]=>
+ string(17) "ģ䕧覫췯ꯍ"
+ ["unicode"]=>
+ string(18) "プレスキット"
+ ["プレスキット"]=>
+ string(18) "プレスキット"
+ ["empty_string"]=>
+ string(0) ""
+ ["true"]=>
+ bool(true)
+ ["false"]=>
+ bool(false)
+ ["null"]=>
+ NULL
+ ["array"]=>
+ array(0) {
+ }
+ ["object"]=>
+ object(stdClass)#%d (0) {
+ }
+ ["123"]=>
+ object(stdClass)#%d (1) {
+ ["456"]=>
+ object(stdClass)#%d (1) {
+ ["abc"]=>
+ object(stdClass)#%d (3) {
+ ["789"]=>
+ string(3) "def"
+ ["012"]=>
+ array(4) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ string(1) "5"
+ [3]=>
+ int(500)
+ }
+ ["ghi"]=>
+ array(5) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ string(4) "five"
+ [3]=>
+ int(50)
+ [4]=>
+ string(5) "sixty"
+ }
+ }
+ }
+ }
+ ["address"]=>
+ string(19) "50 St. James Street"
+ ["url"]=>
+ string(20) "http://www.JSON.org/"
+ ["comment"]=>
+ string(13) "// /* <!-- --"
+ ["# -- --> */"]=>
+ string(1) " "
+ [" s p a c e d "]=>
+ array(7) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ [3]=>
+ int(4)
+ [4]=>
+ int(5)
+ [5]=>
+ int(6)
+ [6]=>
+ int(7)
+ }
+ ["compact"]=>
+ array(7) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ [3]=>
+ int(4)
+ [4]=>
+ int(5)
+ [5]=>
+ int(6)
+ [6]=>
+ int(7)
+ }
+ ["jsontext"]=>
+ string(49) "{"object with 1 member":["array with 1 element"]}"
+ ["quotes"]=>
+ string(27) "&#34; " %22 0x22 034 &#x22;"
+ ["/\"쫾몾ꮘﳞ볚
+ `1~!@#$%^&*()_+-=[]{}|;:',./<>?"]=>
+ string(23) "A key can be any string"
+ }
+ [9]=>
+ float(0.5)
+ [10]=>
+ float(98.6)
+ [11]=>
+ float(99.44)
+ [12]=>
+ int(1066)
+ [13]=>
+ string(7) "rosebud"
+}
+DECODE: AS ARRAY
+array(14) {
+ [0]=>
+ string(23) "JSON Test Pattern pass1"
+ [1]=>
+ array(1) {
+ ["object with 1 member"]=>
+ array(1) {
+ [0]=>
+ string(20) "array with 1 element"
+ }
+ }
+ [2]=>
+ array(0) {
+ }
+ [3]=>
+ array(0) {
+ }
+ [4]=>
+ int(-42)
+ [5]=>
+ bool(true)
+ [6]=>
+ bool(false)
+ [7]=>
+ NULL
+ [8]=>
+ array(36) {
+ ["integer"]=>
+ int(1234567890)
+ ["real"]=>
+ float(-9876.54321)
+ ["e"]=>
+ float(1.23456789E-13)
+ ["E"]=>
+ float(1.23456789E+34)
+ [""]=>
+ float(INF)
+ ["E no ."]=>
+ float(4000000000000)
+ ["zero"]=>
+ int(0)
+ ["one"]=>
+ int(1)
+ ["space"]=>
+ string(1) " "
+ ["quote"]=>
+ string(1) """
+ ["backslash"]=>
+ string(1) "\"
+ ["controls"]=>
+ string(5) "
+ "
+ ["slash"]=>
+ string(5) "/ & /"
+ ["alpha"]=>
+ string(25) "abcdefghijklmnopqrstuvwyz"
+ ["ALPHA"]=>
+ string(25) "ABCDEFGHIJKLMNOPQRSTUVWYZ"
+ ["digit"]=>
+ string(10) "0123456789"
+ ["special"]=>
+ string(31) "`1~!@#$%^&*()_+-={':[,]}|;.</>?"
+ ["hex"]=>
+ string(17) "ģ䕧覫췯ꯍ"
+ ["unicode"]=>
+ string(18) "プレスキット"
+ ["プレスキット"]=>
+ string(18) "プレスキット"
+ ["empty_string"]=>
+ string(0) ""
+ ["true"]=>
+ bool(true)
+ ["false"]=>
+ bool(false)
+ ["null"]=>
+ NULL
+ ["array"]=>
+ array(0) {
+ }
+ ["object"]=>
+ array(0) {
+ }
+ [123]=>
+ array(1) {
+ [456]=>
+ array(1) {
+ ["abc"]=>
+ array(3) {
+ [789]=>
+ string(3) "def"
+ ["012"]=>
+ array(4) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ string(1) "5"
+ [3]=>
+ int(500)
+ }
+ ["ghi"]=>
+ array(5) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ string(4) "five"
+ [3]=>
+ int(50)
+ [4]=>
+ string(5) "sixty"
+ }
+ }
+ }
+ }
+ ["address"]=>
+ string(19) "50 St. James Street"
+ ["url"]=>
+ string(20) "http://www.JSON.org/"
+ ["comment"]=>
+ string(13) "// /* <!-- --"
+ ["# -- --> */"]=>
+ string(1) " "
+ [" s p a c e d "]=>
+ array(7) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ [3]=>
+ int(4)
+ [4]=>
+ int(5)
+ [5]=>
+ int(6)
+ [6]=>
+ int(7)
+ }
+ ["compact"]=>
+ array(7) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ [3]=>
+ int(4)
+ [4]=>
+ int(5)
+ [5]=>
+ int(6)
+ [6]=>
+ int(7)
+ }
+ ["jsontext"]=>
+ string(49) "{"object with 1 member":["array with 1 element"]}"
+ ["quotes"]=>
+ string(27) "&#34; " %22 0x22 034 &#x22;"
+ ["/\"쫾몾ꮘﳞ볚
+ `1~!@#$%^&*()_+-=[]{}|;:',./<>?"]=>
+ string(23) "A key can be any string"
+ }
+ [9]=>
+ float(0.5)
+ [10]=>
+ float(98.6)
+ [11]=>
+ float(99.44)
+ [12]=>
+ int(1066)
+ [13]=>
+ string(7) "rosebud"
+}
+ENCODE: FROM OBJECT
+["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,"_empty_":0,"E no .":4000000000000,"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","unicode":"\u30d7\u30ec\u30b9\u30ad\u30c3\u30c8","\u30d7\u30ec\u30b9\u30ad\u30c3\u30c8":"\u30d7\u30ec\u30b9\u30ad\u30c3\u30c8","empty_string":"","true":true,"false":false,"null":null,"array":[],"object":{},"123":{"456":{"abc":{"789":"def","012":[1,2,"5",500],"ghi":[1,2,"five",50,"sixty"]}}},"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],"jsontext":"{\"object with 1 member\":[\"array with 1 element\"]}","quotes":"&#34; \" %22 0x22 034 &#x22;","\/\\\"\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"]
+ENCODE: FROM ARRAY
+["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,"E no .":4000000000000,"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","unicode":"\u30d7\u30ec\u30b9\u30ad\u30c3\u30c8","\u30d7\u30ec\u30b9\u30ad\u30c3\u30c8":"\u30d7\u30ec\u30b9\u30ad\u30c3\u30c8","empty_string":"","true":true,"false":false,"null":null,"array":[],"object":[],"123":{"456":{"abc":{"789":"def","012":[1,2,"5",500],"ghi":[1,2,"five",50,"sixty"]}}},"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],"jsontext":"{\"object with 1 member\":[\"array with 1 element\"]}","quotes":"&#34; \" %22 0x22 034 &#x22;","\/\\\"\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"]
+DECODE AGAIN: AS OBJECT
+array(14) {
+ [0]=>
+ string(23) "JSON Test Pattern pass1"
+ [1]=>
+ object(stdClass)#%d (1) {
+ ["object with 1 member"]=>
+ array(1) {
+ [0]=>
+ string(20) "array with 1 element"
+ }
+ }
+ [2]=>
+ object(stdClass)#%d (0) {
+ }
+ [3]=>
+ array(0) {
+ }
+ [4]=>
+ int(-42)
+ [5]=>
+ bool(true)
+ [6]=>
+ bool(false)
+ [7]=>
+ NULL
+ [8]=>
+ object(stdClass)#%d (36) {
+ ["integer"]=>
+ int(1234567890)
+ ["real"]=>
+ float(-9876.54321)
+ ["e"]=>
+ float(1.23456789E-13)
+ ["E"]=>
+ float(1.23456789E+34)
+ ["_empty_"]=>
+ int(0)
+ ["E no ."]=>
+ %s(4000000000000)
+ ["zero"]=>
+ int(0)
+ ["one"]=>
+ int(1)
+ ["space"]=>
+ string(1) " "
+ ["quote"]=>
+ string(1) """
+ ["backslash"]=>
+ string(1) "\"
+ ["controls"]=>
+ string(5) "
+ "
+ ["slash"]=>
+ string(5) "/ & /"
+ ["alpha"]=>
+ string(25) "abcdefghijklmnopqrstuvwyz"
+ ["ALPHA"]=>
+ string(25) "ABCDEFGHIJKLMNOPQRSTUVWYZ"
+ ["digit"]=>
+ string(10) "0123456789"
+ ["special"]=>
+ string(31) "`1~!@#$%^&*()_+-={':[,]}|;.</>?"
+ ["hex"]=>
+ string(17) "ģ䕧覫췯ꯍ"
+ ["unicode"]=>
+ string(18) "プレスキット"
+ ["プレスキット"]=>
+ string(18) "プレスキット"
+ ["empty_string"]=>
+ string(0) ""
+ ["true"]=>
+ bool(true)
+ ["false"]=>
+ bool(false)
+ ["null"]=>
+ NULL
+ ["array"]=>
+ array(0) {
+ }
+ ["object"]=>
+ object(stdClass)#%d (0) {
+ }
+ ["123"]=>
+ object(stdClass)#%d (1) {
+ ["456"]=>
+ object(stdClass)#%d (1) {
+ ["abc"]=>
+ object(stdClass)#%d (3) {
+ ["789"]=>
+ string(3) "def"
+ ["012"]=>
+ array(4) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ string(1) "5"
+ [3]=>
+ int(500)
+ }
+ ["ghi"]=>
+ array(5) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ string(4) "five"
+ [3]=>
+ int(50)
+ [4]=>
+ string(5) "sixty"
+ }
+ }
+ }
+ }
+ ["address"]=>
+ string(19) "50 St. James Street"
+ ["url"]=>
+ string(20) "http://www.JSON.org/"
+ ["comment"]=>
+ string(13) "// /* <!-- --"
+ ["# -- --> */"]=>
+ string(1) " "
+ [" s p a c e d "]=>
+ array(7) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ [3]=>
+ int(4)
+ [4]=>
+ int(5)
+ [5]=>
+ int(6)
+ [6]=>
+ int(7)
+ }
+ ["compact"]=>
+ array(7) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ [3]=>
+ int(4)
+ [4]=>
+ int(5)
+ [5]=>
+ int(6)
+ [6]=>
+ int(7)
+ }
+ ["jsontext"]=>
+ string(49) "{"object with 1 member":["array with 1 element"]}"
+ ["quotes"]=>
+ string(27) "&#34; " %22 0x22 034 &#x22;"
+ ["/\"쫾몾ꮘﳞ볚
+ `1~!@#$%^&*()_+-=[]{}|;:',./<>?"]=>
+ string(23) "A key can be any string"
+ }
+ [9]=>
+ float(0.5)
+ [10]=>
+ float(98.6)
+ [11]=>
+ float(99.44)
+ [12]=>
+ int(1066)
+ [13]=>
+ string(7) "rosebud"
+}
+DECODE AGAIN: AS ARRAY
+array(14) {
+ [0]=>
+ string(23) "JSON Test Pattern pass1"
+ [1]=>
+ array(1) {
+ ["object with 1 member"]=>
+ array(1) {
+ [0]=>
+ string(20) "array with 1 element"
+ }
+ }
+ [2]=>
+ array(0) {
+ }
+ [3]=>
+ array(0) {
+ }
+ [4]=>
+ int(-42)
+ [5]=>
+ bool(true)
+ [6]=>
+ bool(false)
+ [7]=>
+ NULL
+ [8]=>
+ array(36) {
+ ["integer"]=>
+ int(1234567890)
+ ["real"]=>
+ float(-9876.54321)
+ ["e"]=>
+ float(1.23456789E-13)
+ ["E"]=>
+ float(1.23456789E+34)
+ [""]=>
+ int(0)
+ ["E no ."]=>
+ %s(4000000000000)
+ ["zero"]=>
+ int(0)
+ ["one"]=>
+ int(1)
+ ["space"]=>
+ string(1) " "
+ ["quote"]=>
+ string(1) """
+ ["backslash"]=>
+ string(1) "\"
+ ["controls"]=>
+ string(5) "
+ "
+ ["slash"]=>
+ string(5) "/ & /"
+ ["alpha"]=>
+ string(25) "abcdefghijklmnopqrstuvwyz"
+ ["ALPHA"]=>
+ string(25) "ABCDEFGHIJKLMNOPQRSTUVWYZ"
+ ["digit"]=>
+ string(10) "0123456789"
+ ["special"]=>
+ string(31) "`1~!@#$%^&*()_+-={':[,]}|;.</>?"
+ ["hex"]=>
+ string(17) "ģ䕧覫췯ꯍ"
+ ["unicode"]=>
+ string(18) "プレスキット"
+ ["プレスキット"]=>
+ string(18) "プレスキット"
+ ["empty_string"]=>
+ string(0) ""
+ ["true"]=>
+ bool(true)
+ ["false"]=>
+ bool(false)
+ ["null"]=>
+ NULL
+ ["array"]=>
+ array(0) {
+ }
+ ["object"]=>
+ array(0) {
+ }
+ [123]=>
+ array(1) {
+ [456]=>
+ array(1) {
+ ["abc"]=>
+ array(3) {
+ [789]=>
+ string(3) "def"
+ ["012"]=>
+ array(4) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ string(1) "5"
+ [3]=>
+ int(500)
+ }
+ ["ghi"]=>
+ array(5) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ string(4) "five"
+ [3]=>
+ int(50)
+ [4]=>
+ string(5) "sixty"
+ }
+ }
+ }
+ }
+ ["address"]=>
+ string(19) "50 St. James Street"
+ ["url"]=>
+ string(20) "http://www.JSON.org/"
+ ["comment"]=>
+ string(13) "// /* <!-- --"
+ ["# -- --> */"]=>
+ string(1) " "
+ [" s p a c e d "]=>
+ array(7) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ [3]=>
+ int(4)
+ [4]=>
+ int(5)
+ [5]=>
+ int(6)
+ [6]=>
+ int(7)
+ }
+ ["compact"]=>
+ array(7) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ [3]=>
+ int(4)
+ [4]=>
+ int(5)
+ [5]=>
+ int(6)
+ [6]=>
+ int(7)
+ }
+ ["jsontext"]=>
+ string(49) "{"object with 1 member":["array with 1 element"]}"
+ ["quotes"]=>
+ string(27) "&#34; " %22 0x22 034 &#x22;"
+ ["/\"쫾몾ꮘﳞ볚
+ `1~!@#$%^&*()_+-=[]{}|;:',./<>?"]=>
+ string(23) "A key can be any string"
+ }
+ [9]=>
+ float(0.5)
+ [10]=>
+ float(98.6)
+ [11]=>
+ float(99.44)
+ [12]=>
+ int(1066)
+ [13]=>
+ string(7) "rosebud"
+}
diff --git a/ext/json/tests/pass001.1_64bit.phpt b/ext/json/tests/pass001.1_64bit.phpt
new file mode 100644
index 000000000..ff2714436
--- /dev/null
+++ b/ext/json/tests/pass001.1_64bit.phpt
@@ -0,0 +1,890 @@
+--TEST--
+JSON (http://www.crockford.com/JSON/JSON_checker/test/pass1.json)
+--INI--
+precision=14
+--SKIPIF--
+<?php
+ if (!extension_loaded('json')) die('skip: json extension not available');
+ if (PHP_INT_SIZE != 8) die("skip this test is for 64bit platform only");
+?>
+--FILE--
+<?php
+/* Modified to test unescaped UNICODE as keys and values.
+ * Modified to test numbers with exponents without a decimal point.
+ * Modified to test empty string values.
+ * Modified to test a mix of integers and strings as keys.
+ */
+// Expect warnings about INF.
+ini_set("error_reporting", E_ALL & ~E_WARNING);
+
+$test = "
+[
+ \"JSON Test Pattern pass1\",
+ {\"object with 1 member\":[\"array with 1 element\"]},
+ {},
+ [],
+ -42,
+ true,
+ false,
+ null,
+ {
+ \"integer\": 1234567890,
+ \"real\": -9876.543210,
+ \"e\": 0.123456789e-12,
+ \"E\": 1.234567890E+34,
+ \"\": 23456789012E666,
+ \"E no .\": 4E12,
+ \"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\",
+ \"unicode\": \"\\u30d7\\u30ec\\u30b9\\u30ad\\u30c3\\u30c8\",
+ \"プレスキット\": \"プレスキット\",
+ \"empty_string\": \"\",
+ \"true\": true,
+ \"false\": false,
+ \"null\": null,
+ \"array\":[ ],
+ \"object\":{ },
+ \"123\":{\"456\":{\"abc\":{\"789\":\"def\",\"012\":[1,2,\"5\",500],\"ghi\":[1,2,\"five\",50,\"sixty\"]}}},
+ \"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],
+ \"jsontext\": \"{\\\"object with 1 member\\\":[\\\"array with 1 element\\\"]}\",
+ \"quotes\": \"&#34; \\u0022 %22 0x22 034 &#x22;\",
+ \"\\/\\\\\\\"\\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\"]
+";
+
+echo 'Testing: ' . $test . "\n";
+echo "DECODE: AS OBJECT\n";
+$obj = json_decode($test);
+var_dump($obj);
+echo "DECODE: AS ARRAY\n";
+$arr = json_decode($test, true);
+var_dump($arr);
+
+echo "ENCODE: FROM OBJECT\n";
+$obj_enc = json_encode($obj, JSON_PARTIAL_OUTPUT_ON_ERROR);
+echo $obj_enc . "\n";
+echo "ENCODE: FROM ARRAY\n";
+$arr_enc = json_encode($arr, JSON_PARTIAL_OUTPUT_ON_ERROR);
+echo $arr_enc . "\n";
+
+echo "DECODE AGAIN: AS OBJECT\n";
+$obj = json_decode($obj_enc);
+var_dump($obj);
+echo "DECODE AGAIN: AS ARRAY\n";
+$arr = json_decode($arr_enc, true);
+var_dump($arr);
+
+?>
+--EXPECTF--
+Testing:
+[
+ "JSON Test Pattern pass1",
+ {"object with 1 member":["array with 1 element"]},
+ {},
+ [],
+ -42,
+ true,
+ false,
+ null,
+ {
+ "integer": 1234567890,
+ "real": -9876.543210,
+ "e": 0.123456789e-12,
+ "E": 1.234567890E+34,
+ "": 23456789012E666,
+ "E no .": 4E12,
+ "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",
+ "unicode": "\u30d7\u30ec\u30b9\u30ad\u30c3\u30c8",
+ "プレスキット": "プレスキット",
+ "empty_string": "",
+ "true": true,
+ "false": false,
+ "null": null,
+ "array":[ ],
+ "object":{ },
+ "123":{"456":{"abc":{"789":"def","012":[1,2,"5",500],"ghi":[1,2,"five",50,"sixty"]}}},
+ "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],
+ "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}",
+ "quotes": "&#34; \u0022 %22 0x22 034 &#x22;",
+ "\/\\\"\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"]
+
+DECODE: AS OBJECT
+array(14) {
+ [0]=>
+ string(23) "JSON Test Pattern pass1"
+ [1]=>
+ object(stdClass)#%d (1) {
+ ["object with 1 member"]=>
+ array(1) {
+ [0]=>
+ string(20) "array with 1 element"
+ }
+ }
+ [2]=>
+ object(stdClass)#%d (0) {
+ }
+ [3]=>
+ array(0) {
+ }
+ [4]=>
+ int(-42)
+ [5]=>
+ bool(true)
+ [6]=>
+ bool(false)
+ [7]=>
+ NULL
+ [8]=>
+ object(stdClass)#%d (36) {
+ ["integer"]=>
+ int(1234567890)
+ ["real"]=>
+ float(-9876.54321)
+ ["e"]=>
+ float(1.23456789E-13)
+ ["E"]=>
+ float(1.23456789E+34)
+ ["_empty_"]=>
+ float(INF)
+ ["E no ."]=>
+ float(4000000000000)
+ ["zero"]=>
+ int(0)
+ ["one"]=>
+ int(1)
+ ["space"]=>
+ string(1) " "
+ ["quote"]=>
+ string(1) """
+ ["backslash"]=>
+ string(1) "\"
+ ["controls"]=>
+ string(5) "
+ "
+ ["slash"]=>
+ string(5) "/ & /"
+ ["alpha"]=>
+ string(25) "abcdefghijklmnopqrstuvwyz"
+ ["ALPHA"]=>
+ string(25) "ABCDEFGHIJKLMNOPQRSTUVWYZ"
+ ["digit"]=>
+ string(10) "0123456789"
+ ["special"]=>
+ string(31) "`1~!@#$%^&*()_+-={':[,]}|;.</>?"
+ ["hex"]=>
+ string(17) "ģ䕧覫췯ꯍ"
+ ["unicode"]=>
+ string(18) "プレスキット"
+ ["プレスキット"]=>
+ string(18) "プレスキット"
+ ["empty_string"]=>
+ string(0) ""
+ ["true"]=>
+ bool(true)
+ ["false"]=>
+ bool(false)
+ ["null"]=>
+ NULL
+ ["array"]=>
+ array(0) {
+ }
+ ["object"]=>
+ object(stdClass)#%d (0) {
+ }
+ ["123"]=>
+ object(stdClass)#%d (1) {
+ ["456"]=>
+ object(stdClass)#%d (1) {
+ ["abc"]=>
+ object(stdClass)#%d (3) {
+ ["789"]=>
+ string(3) "def"
+ ["012"]=>
+ array(4) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ string(1) "5"
+ [3]=>
+ int(500)
+ }
+ ["ghi"]=>
+ array(5) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ string(4) "five"
+ [3]=>
+ int(50)
+ [4]=>
+ string(5) "sixty"
+ }
+ }
+ }
+ }
+ ["address"]=>
+ string(19) "50 St. James Street"
+ ["url"]=>
+ string(20) "http://www.JSON.org/"
+ ["comment"]=>
+ string(13) "// /* <!-- --"
+ ["# -- --> */"]=>
+ string(1) " "
+ [" s p a c e d "]=>
+ array(7) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ [3]=>
+ int(4)
+ [4]=>
+ int(5)
+ [5]=>
+ int(6)
+ [6]=>
+ int(7)
+ }
+ ["compact"]=>
+ array(7) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ [3]=>
+ int(4)
+ [4]=>
+ int(5)
+ [5]=>
+ int(6)
+ [6]=>
+ int(7)
+ }
+ ["jsontext"]=>
+ string(49) "{"object with 1 member":["array with 1 element"]}"
+ ["quotes"]=>
+ string(27) "&#34; " %22 0x22 034 &#x22;"
+ ["/\"쫾몾ꮘﳞ볚
+ `1~!@#$%^&*()_+-=[]{}|;:',./<>?"]=>
+ string(23) "A key can be any string"
+ }
+ [9]=>
+ float(0.5)
+ [10]=>
+ float(98.6)
+ [11]=>
+ float(99.44)
+ [12]=>
+ int(1066)
+ [13]=>
+ string(7) "rosebud"
+}
+DECODE: AS ARRAY
+array(14) {
+ [0]=>
+ string(23) "JSON Test Pattern pass1"
+ [1]=>
+ array(1) {
+ ["object with 1 member"]=>
+ array(1) {
+ [0]=>
+ string(20) "array with 1 element"
+ }
+ }
+ [2]=>
+ array(0) {
+ }
+ [3]=>
+ array(0) {
+ }
+ [4]=>
+ int(-42)
+ [5]=>
+ bool(true)
+ [6]=>
+ bool(false)
+ [7]=>
+ NULL
+ [8]=>
+ array(36) {
+ ["integer"]=>
+ int(1234567890)
+ ["real"]=>
+ float(-9876.54321)
+ ["e"]=>
+ float(1.23456789E-13)
+ ["E"]=>
+ float(1.23456789E+34)
+ [""]=>
+ float(INF)
+ ["E no ."]=>
+ float(4000000000000)
+ ["zero"]=>
+ int(0)
+ ["one"]=>
+ int(1)
+ ["space"]=>
+ string(1) " "
+ ["quote"]=>
+ string(1) """
+ ["backslash"]=>
+ string(1) "\"
+ ["controls"]=>
+ string(5) "
+ "
+ ["slash"]=>
+ string(5) "/ & /"
+ ["alpha"]=>
+ string(25) "abcdefghijklmnopqrstuvwyz"
+ ["ALPHA"]=>
+ string(25) "ABCDEFGHIJKLMNOPQRSTUVWYZ"
+ ["digit"]=>
+ string(10) "0123456789"
+ ["special"]=>
+ string(31) "`1~!@#$%^&*()_+-={':[,]}|;.</>?"
+ ["hex"]=>
+ string(17) "ģ䕧覫췯ꯍ"
+ ["unicode"]=>
+ string(18) "プレスキット"
+ ["プレスキット"]=>
+ string(18) "プレスキット"
+ ["empty_string"]=>
+ string(0) ""
+ ["true"]=>
+ bool(true)
+ ["false"]=>
+ bool(false)
+ ["null"]=>
+ NULL
+ ["array"]=>
+ array(0) {
+ }
+ ["object"]=>
+ array(0) {
+ }
+ [123]=>
+ array(1) {
+ [456]=>
+ array(1) {
+ ["abc"]=>
+ array(3) {
+ [789]=>
+ string(3) "def"
+ ["012"]=>
+ array(4) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ string(1) "5"
+ [3]=>
+ int(500)
+ }
+ ["ghi"]=>
+ array(5) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ string(4) "five"
+ [3]=>
+ int(50)
+ [4]=>
+ string(5) "sixty"
+ }
+ }
+ }
+ }
+ ["address"]=>
+ string(19) "50 St. James Street"
+ ["url"]=>
+ string(20) "http://www.JSON.org/"
+ ["comment"]=>
+ string(13) "// /* <!-- --"
+ ["# -- --> */"]=>
+ string(1) " "
+ [" s p a c e d "]=>
+ array(7) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ [3]=>
+ int(4)
+ [4]=>
+ int(5)
+ [5]=>
+ int(6)
+ [6]=>
+ int(7)
+ }
+ ["compact"]=>
+ array(7) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ [3]=>
+ int(4)
+ [4]=>
+ int(5)
+ [5]=>
+ int(6)
+ [6]=>
+ int(7)
+ }
+ ["jsontext"]=>
+ string(49) "{"object with 1 member":["array with 1 element"]}"
+ ["quotes"]=>
+ string(27) "&#34; " %22 0x22 034 &#x22;"
+ ["/\"쫾몾ꮘﳞ볚
+ `1~!@#$%^&*()_+-=[]{}|;:',./<>?"]=>
+ string(23) "A key can be any string"
+ }
+ [9]=>
+ float(0.5)
+ [10]=>
+ float(98.6)
+ [11]=>
+ float(99.44)
+ [12]=>
+ int(1066)
+ [13]=>
+ string(7) "rosebud"
+}
+ENCODE: FROM OBJECT
+["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,"_empty_":0,"E no .":4000000000000,"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","unicode":"\u30d7\u30ec\u30b9\u30ad\u30c3\u30c8","\u30d7\u30ec\u30b9\u30ad\u30c3\u30c8":"\u30d7\u30ec\u30b9\u30ad\u30c3\u30c8","empty_string":"","true":true,"false":false,"null":null,"array":[],"object":{},"123":{"456":{"abc":{"789":"def","012":[1,2,"5",500],"ghi":[1,2,"five",50,"sixty"]}}},"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],"jsontext":"{\"object with 1 member\":[\"array with 1 element\"]}","quotes":"&#34; \" %22 0x22 034 &#x22;","\/\\\"\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"]
+ENCODE: FROM ARRAY
+["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,"E no .":4000000000000,"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","unicode":"\u30d7\u30ec\u30b9\u30ad\u30c3\u30c8","\u30d7\u30ec\u30b9\u30ad\u30c3\u30c8":"\u30d7\u30ec\u30b9\u30ad\u30c3\u30c8","empty_string":"","true":true,"false":false,"null":null,"array":[],"object":[],"123":{"456":{"abc":{"789":"def","012":[1,2,"5",500],"ghi":[1,2,"five",50,"sixty"]}}},"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],"jsontext":"{\"object with 1 member\":[\"array with 1 element\"]}","quotes":"&#34; \" %22 0x22 034 &#x22;","\/\\\"\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"]
+DECODE AGAIN: AS OBJECT
+array(14) {
+ [0]=>
+ string(23) "JSON Test Pattern pass1"
+ [1]=>
+ object(stdClass)#%d (1) {
+ ["object with 1 member"]=>
+ array(1) {
+ [0]=>
+ string(20) "array with 1 element"
+ }
+ }
+ [2]=>
+ object(stdClass)#%d (0) {
+ }
+ [3]=>
+ array(0) {
+ }
+ [4]=>
+ int(-42)
+ [5]=>
+ bool(true)
+ [6]=>
+ bool(false)
+ [7]=>
+ NULL
+ [8]=>
+ object(stdClass)#%d (36) {
+ ["integer"]=>
+ int(1234567890)
+ ["real"]=>
+ float(-9876.54321)
+ ["e"]=>
+ float(1.23456789E-13)
+ ["E"]=>
+ float(1.23456789E+34)
+ ["_empty_"]=>
+ int(0)
+ ["E no ."]=>
+ int(4000000000000)
+ ["zero"]=>
+ int(0)
+ ["one"]=>
+ int(1)
+ ["space"]=>
+ string(1) " "
+ ["quote"]=>
+ string(1) """
+ ["backslash"]=>
+ string(1) "\"
+ ["controls"]=>
+ string(5) "
+ "
+ ["slash"]=>
+ string(5) "/ & /"
+ ["alpha"]=>
+ string(25) "abcdefghijklmnopqrstuvwyz"
+ ["ALPHA"]=>
+ string(25) "ABCDEFGHIJKLMNOPQRSTUVWYZ"
+ ["digit"]=>
+ string(10) "0123456789"
+ ["special"]=>
+ string(31) "`1~!@#$%^&*()_+-={':[,]}|;.</>?"
+ ["hex"]=>
+ string(17) "ģ䕧覫췯ꯍ"
+ ["unicode"]=>
+ string(18) "プレスキット"
+ ["プレスキット"]=>
+ string(18) "プレスキット"
+ ["empty_string"]=>
+ string(0) ""
+ ["true"]=>
+ bool(true)
+ ["false"]=>
+ bool(false)
+ ["null"]=>
+ NULL
+ ["array"]=>
+ array(0) {
+ }
+ ["object"]=>
+ object(stdClass)#%d (0) {
+ }
+ ["123"]=>
+ object(stdClass)#%d (1) {
+ ["456"]=>
+ object(stdClass)#%d (1) {
+ ["abc"]=>
+ object(stdClass)#%d (3) {
+ ["789"]=>
+ string(3) "def"
+ ["012"]=>
+ array(4) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ string(1) "5"
+ [3]=>
+ int(500)
+ }
+ ["ghi"]=>
+ array(5) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ string(4) "five"
+ [3]=>
+ int(50)
+ [4]=>
+ string(5) "sixty"
+ }
+ }
+ }
+ }
+ ["address"]=>
+ string(19) "50 St. James Street"
+ ["url"]=>
+ string(20) "http://www.JSON.org/"
+ ["comment"]=>
+ string(13) "// /* <!-- --"
+ ["# -- --> */"]=>
+ string(1) " "
+ [" s p a c e d "]=>
+ array(7) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ [3]=>
+ int(4)
+ [4]=>
+ int(5)
+ [5]=>
+ int(6)
+ [6]=>
+ int(7)
+ }
+ ["compact"]=>
+ array(7) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ [3]=>
+ int(4)
+ [4]=>
+ int(5)
+ [5]=>
+ int(6)
+ [6]=>
+ int(7)
+ }
+ ["jsontext"]=>
+ string(49) "{"object with 1 member":["array with 1 element"]}"
+ ["quotes"]=>
+ string(27) "&#34; " %22 0x22 034 &#x22;"
+ ["/\"쫾몾ꮘﳞ볚
+ `1~!@#$%^&*()_+-=[]{}|;:',./<>?"]=>
+ string(23) "A key can be any string"
+ }
+ [9]=>
+ float(0.5)
+ [10]=>
+ float(98.6)
+ [11]=>
+ float(99.44)
+ [12]=>
+ int(1066)
+ [13]=>
+ string(7) "rosebud"
+}
+DECODE AGAIN: AS ARRAY
+array(14) {
+ [0]=>
+ string(23) "JSON Test Pattern pass1"
+ [1]=>
+ array(1) {
+ ["object with 1 member"]=>
+ array(1) {
+ [0]=>
+ string(20) "array with 1 element"
+ }
+ }
+ [2]=>
+ array(0) {
+ }
+ [3]=>
+ array(0) {
+ }
+ [4]=>
+ int(-42)
+ [5]=>
+ bool(true)
+ [6]=>
+ bool(false)
+ [7]=>
+ NULL
+ [8]=>
+ array(36) {
+ ["integer"]=>
+ int(1234567890)
+ ["real"]=>
+ float(-9876.54321)
+ ["e"]=>
+ float(1.23456789E-13)
+ ["E"]=>
+ float(1.23456789E+34)
+ [""]=>
+ int(0)
+ ["E no ."]=>
+ int(4000000000000)
+ ["zero"]=>
+ int(0)
+ ["one"]=>
+ int(1)
+ ["space"]=>
+ string(1) " "
+ ["quote"]=>
+ string(1) """
+ ["backslash"]=>
+ string(1) "\"
+ ["controls"]=>
+ string(5) "
+ "
+ ["slash"]=>
+ string(5) "/ & /"
+ ["alpha"]=>
+ string(25) "abcdefghijklmnopqrstuvwyz"
+ ["ALPHA"]=>
+ string(25) "ABCDEFGHIJKLMNOPQRSTUVWYZ"
+ ["digit"]=>
+ string(10) "0123456789"
+ ["special"]=>
+ string(31) "`1~!@#$%^&*()_+-={':[,]}|;.</>?"
+ ["hex"]=>
+ string(17) "ģ䕧覫췯ꯍ"
+ ["unicode"]=>
+ string(18) "プレスキット"
+ ["プレスキット"]=>
+ string(18) "プレスキット"
+ ["empty_string"]=>
+ string(0) ""
+ ["true"]=>
+ bool(true)
+ ["false"]=>
+ bool(false)
+ ["null"]=>
+ NULL
+ ["array"]=>
+ array(0) {
+ }
+ ["object"]=>
+ array(0) {
+ }
+ [123]=>
+ array(1) {
+ [456]=>
+ array(1) {
+ ["abc"]=>
+ array(3) {
+ [789]=>
+ string(3) "def"
+ ["012"]=>
+ array(4) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ string(1) "5"
+ [3]=>
+ int(500)
+ }
+ ["ghi"]=>
+ array(5) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ string(4) "five"
+ [3]=>
+ int(50)
+ [4]=>
+ string(5) "sixty"
+ }
+ }
+ }
+ }
+ ["address"]=>
+ string(19) "50 St. James Street"
+ ["url"]=>
+ string(20) "http://www.JSON.org/"
+ ["comment"]=>
+ string(13) "// /* <!-- --"
+ ["# -- --> */"]=>
+ string(1) " "
+ [" s p a c e d "]=>
+ array(7) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ [3]=>
+ int(4)
+ [4]=>
+ int(5)
+ [5]=>
+ int(6)
+ [6]=>
+ int(7)
+ }
+ ["compact"]=>
+ array(7) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ [3]=>
+ int(4)
+ [4]=>
+ int(5)
+ [5]=>
+ int(6)
+ [6]=>
+ int(7)
+ }
+ ["jsontext"]=>
+ string(49) "{"object with 1 member":["array with 1 element"]}"
+ ["quotes"]=>
+ string(27) "&#34; " %22 0x22 034 &#x22;"
+ ["/\"쫾몾ꮘﳞ볚
+ `1~!@#$%^&*()_+-=[]{}|;:',./<>?"]=>
+ string(23) "A key can be any string"
+ }
+ [9]=>
+ float(0.5)
+ [10]=>
+ float(98.6)
+ [11]=>
+ float(99.44)
+ [12]=>
+ int(1066)
+ [13]=>
+ string(7) "rosebud"
+}
diff --git a/ext/json/tests/pass001.phpt b/ext/json/tests/pass001.phpt
new file mode 100644
index 000000000..1fd05fcdd
--- /dev/null
+++ b/ext/json/tests/pass001.phpt
@@ -0,0 +1,702 @@
+--TEST--
+JSON (http://www.crockford.com/JSON/JSON_checker/test/pass1.json)
+--INI--
+precision=14
+--SKIPIF--
+<?php
+ if (!extension_loaded('json')) die('skip: json extension not available');
+?>
+--FILE--
+<?php
+// Expect warnings about INF.
+ini_set("error_reporting", E_ALL & ~E_WARNING);
+
+$test = "
+[
+ \"JSON Test Pattern pass1\",
+ {\"object with 1 member\":[\"array with 1 element\"]},
+ {},
+ [],
+ -42,
+ true,
+ false,
+ null,
+ {
+ \"integer\": 1234567890,
+ \"real\": -9876.543210,
+ \"e\": 0.123456789e-12,
+ \"E\": 1.234567890E+34,
+ \"\": 23456789012E666,
+ \"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],
+ \"jsontext\": \"{\\\"object with 1 member\\\":[\\\"array with 1 element\\\"]}\",
+ \"quotes\": \"&#34; \\u0022 %22 0x22 034 &#x22;\",
+ \"\\/\\\\\\\"\\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\"]
+";
+
+echo 'Testing: ' . $test . "\n";
+echo "DECODE: AS OBJECT\n";
+$obj = json_decode($test);
+var_dump($obj);
+echo "DECODE: AS ARRAY\n";
+$arr = json_decode($test, true);
+var_dump($arr);
+
+echo "ENCODE: FROM OBJECT\n";
+$obj_enc = json_encode($obj, JSON_PARTIAL_OUTPUT_ON_ERROR);
+echo $obj_enc . "\n";
+echo "ENCODE: FROM ARRAY\n";
+$arr_enc = json_encode($arr, JSON_PARTIAL_OUTPUT_ON_ERROR);
+echo $arr_enc . "\n";
+
+echo "DECODE AGAIN: AS OBJECT\n";
+$obj = json_decode($obj_enc);
+var_dump($obj);
+echo "DECODE AGAIN: AS ARRAY\n";
+$arr = json_decode($arr_enc, true);
+var_dump($arr);
+
+?>
+--EXPECT--
+Testing:
+[
+ "JSON Test Pattern pass1",
+ {"object with 1 member":["array with 1 element"]},
+ {},
+ [],
+ -42,
+ true,
+ false,
+ null,
+ {
+ "integer": 1234567890,
+ "real": -9876.543210,
+ "e": 0.123456789e-12,
+ "E": 1.234567890E+34,
+ "": 23456789012E666,
+ "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],
+ "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}",
+ "quotes": "&#34; \u0022 %22 0x22 034 &#x22;",
+ "\/\\\"\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"]
+
+DECODE: AS OBJECT
+array(14) {
+ [0]=>
+ string(23) "JSON Test Pattern pass1"
+ [1]=>
+ object(stdClass)#1 (1) {
+ ["object with 1 member"]=>
+ array(1) {
+ [0]=>
+ string(20) "array with 1 element"
+ }
+ }
+ [2]=>
+ object(stdClass)#2 (0) {
+ }
+ [3]=>
+ array(0) {
+ }
+ [4]=>
+ int(-42)
+ [5]=>
+ bool(true)
+ [6]=>
+ bool(false)
+ [7]=>
+ NULL
+ [8]=>
+ object(stdClass)#3 (31) {
+ ["integer"]=>
+ int(1234567890)
+ ["real"]=>
+ float(-9876.54321)
+ ["e"]=>
+ float(1.23456789E-13)
+ ["E"]=>
+ float(1.23456789E+34)
+ ["_empty_"]=>
+ float(INF)
+ ["zero"]=>
+ int(0)
+ ["one"]=>
+ int(1)
+ ["space"]=>
+ string(1) " "
+ ["quote"]=>
+ string(1) """
+ ["backslash"]=>
+ string(1) "\"
+ ["controls"]=>
+ string(5) "
+ "
+ ["slash"]=>
+ string(5) "/ & /"
+ ["alpha"]=>
+ string(25) "abcdefghijklmnopqrstuvwyz"
+ ["ALPHA"]=>
+ string(25) "ABCDEFGHIJKLMNOPQRSTUVWYZ"
+ ["digit"]=>
+ string(10) "0123456789"
+ ["special"]=>
+ string(31) "`1~!@#$%^&*()_+-={':[,]}|;.</>?"
+ ["hex"]=>
+ string(17) "ģ䕧覫췯ꯍ"
+ ["true"]=>
+ bool(true)
+ ["false"]=>
+ bool(false)
+ ["null"]=>
+ NULL
+ ["array"]=>
+ array(0) {
+ }
+ ["object"]=>
+ object(stdClass)#4 (0) {
+ }
+ ["address"]=>
+ string(19) "50 St. James Street"
+ ["url"]=>
+ string(20) "http://www.JSON.org/"
+ ["comment"]=>
+ string(13) "// /* <!-- --"
+ ["# -- --> */"]=>
+ string(1) " "
+ [" s p a c e d "]=>
+ array(7) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ [3]=>
+ int(4)
+ [4]=>
+ int(5)
+ [5]=>
+ int(6)
+ [6]=>
+ int(7)
+ }
+ ["compact"]=>
+ array(7) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ [3]=>
+ int(4)
+ [4]=>
+ int(5)
+ [5]=>
+ int(6)
+ [6]=>
+ int(7)
+ }
+ ["jsontext"]=>
+ string(49) "{"object with 1 member":["array with 1 element"]}"
+ ["quotes"]=>
+ string(27) "&#34; " %22 0x22 034 &#x22;"
+ ["/\"쫾몾ꮘﳞ볚
+ `1~!@#$%^&*()_+-=[]{}|;:',./<>?"]=>
+ string(23) "A key can be any string"
+ }
+ [9]=>
+ float(0.5)
+ [10]=>
+ float(98.6)
+ [11]=>
+ float(99.44)
+ [12]=>
+ int(1066)
+ [13]=>
+ string(7) "rosebud"
+}
+DECODE: AS ARRAY
+array(14) {
+ [0]=>
+ string(23) "JSON Test Pattern pass1"
+ [1]=>
+ array(1) {
+ ["object with 1 member"]=>
+ array(1) {
+ [0]=>
+ string(20) "array with 1 element"
+ }
+ }
+ [2]=>
+ array(0) {
+ }
+ [3]=>
+ array(0) {
+ }
+ [4]=>
+ int(-42)
+ [5]=>
+ bool(true)
+ [6]=>
+ bool(false)
+ [7]=>
+ NULL
+ [8]=>
+ array(31) {
+ ["integer"]=>
+ int(1234567890)
+ ["real"]=>
+ float(-9876.54321)
+ ["e"]=>
+ float(1.23456789E-13)
+ ["E"]=>
+ float(1.23456789E+34)
+ [""]=>
+ float(INF)
+ ["zero"]=>
+ int(0)
+ ["one"]=>
+ int(1)
+ ["space"]=>
+ string(1) " "
+ ["quote"]=>
+ string(1) """
+ ["backslash"]=>
+ string(1) "\"
+ ["controls"]=>
+ string(5) "
+ "
+ ["slash"]=>
+ string(5) "/ & /"
+ ["alpha"]=>
+ string(25) "abcdefghijklmnopqrstuvwyz"
+ ["ALPHA"]=>
+ string(25) "ABCDEFGHIJKLMNOPQRSTUVWYZ"
+ ["digit"]=>
+ string(10) "0123456789"
+ ["special"]=>
+ string(31) "`1~!@#$%^&*()_+-={':[,]}|;.</>?"
+ ["hex"]=>
+ string(17) "ģ䕧覫췯ꯍ"
+ ["true"]=>
+ bool(true)
+ ["false"]=>
+ bool(false)
+ ["null"]=>
+ NULL
+ ["array"]=>
+ array(0) {
+ }
+ ["object"]=>
+ array(0) {
+ }
+ ["address"]=>
+ string(19) "50 St. James Street"
+ ["url"]=>
+ string(20) "http://www.JSON.org/"
+ ["comment"]=>
+ string(13) "// /* <!-- --"
+ ["# -- --> */"]=>
+ string(1) " "
+ [" s p a c e d "]=>
+ array(7) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ [3]=>
+ int(4)
+ [4]=>
+ int(5)
+ [5]=>
+ int(6)
+ [6]=>
+ int(7)
+ }
+ ["compact"]=>
+ array(7) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ [3]=>
+ int(4)
+ [4]=>
+ int(5)
+ [5]=>
+ int(6)
+ [6]=>
+ int(7)
+ }
+ ["jsontext"]=>
+ string(49) "{"object with 1 member":["array with 1 element"]}"
+ ["quotes"]=>
+ string(27) "&#34; " %22 0x22 034 &#x22;"
+ ["/\"쫾몾ꮘﳞ볚
+ `1~!@#$%^&*()_+-=[]{}|;:',./<>?"]=>
+ string(23) "A key can be any string"
+ }
+ [9]=>
+ float(0.5)
+ [10]=>
+ float(98.6)
+ [11]=>
+ float(99.44)
+ [12]=>
+ int(1066)
+ [13]=>
+ string(7) "rosebud"
+}
+ENCODE: FROM OBJECT
+["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,"_empty_":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],"jsontext":"{\"object with 1 member\":[\"array with 1 element\"]}","quotes":"&#34; \" %22 0x22 034 &#x22;","\/\\\"\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"]
+ENCODE: FROM ARRAY
+["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],"jsontext":"{\"object with 1 member\":[\"array with 1 element\"]}","quotes":"&#34; \" %22 0x22 034 &#x22;","\/\\\"\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"]
+DECODE AGAIN: AS OBJECT
+array(14) {
+ [0]=>
+ string(23) "JSON Test Pattern pass1"
+ [1]=>
+ object(stdClass)#5 (1) {
+ ["object with 1 member"]=>
+ array(1) {
+ [0]=>
+ string(20) "array with 1 element"
+ }
+ }
+ [2]=>
+ object(stdClass)#6 (0) {
+ }
+ [3]=>
+ array(0) {
+ }
+ [4]=>
+ int(-42)
+ [5]=>
+ bool(true)
+ [6]=>
+ bool(false)
+ [7]=>
+ NULL
+ [8]=>
+ object(stdClass)#7 (31) {
+ ["integer"]=>
+ int(1234567890)
+ ["real"]=>
+ float(-9876.54321)
+ ["e"]=>
+ float(1.23456789E-13)
+ ["E"]=>
+ float(1.23456789E+34)
+ ["_empty_"]=>
+ int(0)
+ ["zero"]=>
+ int(0)
+ ["one"]=>
+ int(1)
+ ["space"]=>
+ string(1) " "
+ ["quote"]=>
+ string(1) """
+ ["backslash"]=>
+ string(1) "\"
+ ["controls"]=>
+ string(5) "
+ "
+ ["slash"]=>
+ string(5) "/ & /"
+ ["alpha"]=>
+ string(25) "abcdefghijklmnopqrstuvwyz"
+ ["ALPHA"]=>
+ string(25) "ABCDEFGHIJKLMNOPQRSTUVWYZ"
+ ["digit"]=>
+ string(10) "0123456789"
+ ["special"]=>
+ string(31) "`1~!@#$%^&*()_+-={':[,]}|;.</>?"
+ ["hex"]=>
+ string(17) "ģ䕧覫췯ꯍ"
+ ["true"]=>
+ bool(true)
+ ["false"]=>
+ bool(false)
+ ["null"]=>
+ NULL
+ ["array"]=>
+ array(0) {
+ }
+ ["object"]=>
+ object(stdClass)#8 (0) {
+ }
+ ["address"]=>
+ string(19) "50 St. James Street"
+ ["url"]=>
+ string(20) "http://www.JSON.org/"
+ ["comment"]=>
+ string(13) "// /* <!-- --"
+ ["# -- --> */"]=>
+ string(1) " "
+ [" s p a c e d "]=>
+ array(7) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ [3]=>
+ int(4)
+ [4]=>
+ int(5)
+ [5]=>
+ int(6)
+ [6]=>
+ int(7)
+ }
+ ["compact"]=>
+ array(7) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ [3]=>
+ int(4)
+ [4]=>
+ int(5)
+ [5]=>
+ int(6)
+ [6]=>
+ int(7)
+ }
+ ["jsontext"]=>
+ string(49) "{"object with 1 member":["array with 1 element"]}"
+ ["quotes"]=>
+ string(27) "&#34; " %22 0x22 034 &#x22;"
+ ["/\"쫾몾ꮘﳞ볚
+ `1~!@#$%^&*()_+-=[]{}|;:',./<>?"]=>
+ string(23) "A key can be any string"
+ }
+ [9]=>
+ float(0.5)
+ [10]=>
+ float(98.6)
+ [11]=>
+ float(99.44)
+ [12]=>
+ int(1066)
+ [13]=>
+ string(7) "rosebud"
+}
+DECODE AGAIN: AS ARRAY
+array(14) {
+ [0]=>
+ string(23) "JSON Test Pattern pass1"
+ [1]=>
+ array(1) {
+ ["object with 1 member"]=>
+ array(1) {
+ [0]=>
+ string(20) "array with 1 element"
+ }
+ }
+ [2]=>
+ array(0) {
+ }
+ [3]=>
+ array(0) {
+ }
+ [4]=>
+ int(-42)
+ [5]=>
+ bool(true)
+ [6]=>
+ bool(false)
+ [7]=>
+ NULL
+ [8]=>
+ array(31) {
+ ["integer"]=>
+ int(1234567890)
+ ["real"]=>
+ float(-9876.54321)
+ ["e"]=>
+ float(1.23456789E-13)
+ ["E"]=>
+ float(1.23456789E+34)
+ [""]=>
+ int(0)
+ ["zero"]=>
+ int(0)
+ ["one"]=>
+ int(1)
+ ["space"]=>
+ string(1) " "
+ ["quote"]=>
+ string(1) """
+ ["backslash"]=>
+ string(1) "\"
+ ["controls"]=>
+ string(5) "
+ "
+ ["slash"]=>
+ string(5) "/ & /"
+ ["alpha"]=>
+ string(25) "abcdefghijklmnopqrstuvwyz"
+ ["ALPHA"]=>
+ string(25) "ABCDEFGHIJKLMNOPQRSTUVWYZ"
+ ["digit"]=>
+ string(10) "0123456789"
+ ["special"]=>
+ string(31) "`1~!@#$%^&*()_+-={':[,]}|;.</>?"
+ ["hex"]=>
+ string(17) "ģ䕧覫췯ꯍ"
+ ["true"]=>
+ bool(true)
+ ["false"]=>
+ bool(false)
+ ["null"]=>
+ NULL
+ ["array"]=>
+ array(0) {
+ }
+ ["object"]=>
+ array(0) {
+ }
+ ["address"]=>
+ string(19) "50 St. James Street"
+ ["url"]=>
+ string(20) "http://www.JSON.org/"
+ ["comment"]=>
+ string(13) "// /* <!-- --"
+ ["# -- --> */"]=>
+ string(1) " "
+ [" s p a c e d "]=>
+ array(7) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ [3]=>
+ int(4)
+ [4]=>
+ int(5)
+ [5]=>
+ int(6)
+ [6]=>
+ int(7)
+ }
+ ["compact"]=>
+ array(7) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ [3]=>
+ int(4)
+ [4]=>
+ int(5)
+ [5]=>
+ int(6)
+ [6]=>
+ int(7)
+ }
+ ["jsontext"]=>
+ string(49) "{"object with 1 member":["array with 1 element"]}"
+ ["quotes"]=>
+ string(27) "&#34; " %22 0x22 034 &#x22;"
+ ["/\"쫾몾ꮘﳞ볚
+ `1~!@#$%^&*()_+-=[]{}|;:',./<>?"]=>
+ string(23) "A key can be any string"
+ }
+ [9]=>
+ float(0.5)
+ [10]=>
+ float(98.6)
+ [11]=>
+ float(99.44)
+ [12]=>
+ int(1066)
+ [13]=>
+ string(7) "rosebud"
+}
diff --git a/ext/json/tests/pass002.phpt b/ext/json/tests/pass002.phpt
new file mode 100644
index 000000000..24c7e3358
--- /dev/null
+++ b/ext/json/tests/pass002.phpt
@@ -0,0 +1,275 @@
+--TEST--
+JSON (http://www.crockford.com/JSON/JSON_checker/test/pass2.json)
+--SKIPIF--
+<?php
+ if (!extension_loaded('json')) die('skip: json extension not available');
+?>
+--FILE--
+<?php
+
+$test = '[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]]';
+echo 'Testing: ' . $test . "\n";
+echo "DECODE: AS OBJECT\n";
+$obj = json_decode($test);
+var_dump($obj);
+echo "DECODE: AS ARRAY\n";
+$arr = json_decode($test, true);
+var_dump($arr);
+
+echo "ENCODE: FROM OBJECT\n";
+$obj_enc = json_encode($obj);
+echo $obj_enc . "\n";
+echo "ENCODE: FROM ARRAY\n";
+$arr_enc = json_encode($arr);
+echo $arr_enc . "\n";
+
+echo "DECODE AGAIN: AS OBJECT\n";
+$obj = json_decode($obj_enc);
+var_dump($obj);
+echo "DECODE AGAIN: AS ARRAY\n";
+$arr = json_decode($arr_enc, true);
+var_dump($arr);
+
+?>
+--EXPECT--
+Testing: [[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]]
+DECODE: AS OBJECT
+array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ string(12) "Not too deep"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+DECODE: AS ARRAY
+array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ string(12) "Not too deep"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+ENCODE: FROM OBJECT
+[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]]
+ENCODE: FROM ARRAY
+[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]]
+DECODE AGAIN: AS OBJECT
+array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ string(12) "Not too deep"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+DECODE AGAIN: AS ARRAY
+array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ string(12) "Not too deep"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/ext/json/tests/pass003.phpt b/ext/json/tests/pass003.phpt
new file mode 100644
index 000000000..36da4a1de
--- /dev/null
+++ b/ext/json/tests/pass003.phpt
@@ -0,0 +1,94 @@
+--TEST--
+JSON (http://www.crockford.com/JSON/JSON_checker/test/pass3.json)
+--SKIPIF--
+<?php
+ if (!extension_loaded('json')) die('skip: json extension not available');
+?>
+--FILE--
+<?php
+
+$test = '
+{
+ "JSON Test Pattern pass3": {
+ "The outermost value": "must be an object or array.",
+ "In this test": "It is an object."
+ }
+}
+';
+
+echo 'Testing: ' . $test . "\n";
+echo "DECODE: AS OBJECT\n";
+$obj = json_decode($test);
+var_dump($obj);
+echo "DECODE: AS ARRAY\n";
+$arr = json_decode($test, true);
+var_dump($arr);
+
+echo "ENCODE: FROM OBJECT\n";
+$obj_enc = json_encode($obj);
+echo $obj_enc . "\n";
+echo "ENCODE: FROM ARRAY\n";
+$arr_enc = json_encode($arr);
+echo $arr_enc . "\n";
+
+echo "DECODE AGAIN: AS OBJECT\n";
+$obj = json_decode($obj_enc);
+var_dump($obj);
+echo "DECODE AGAIN: AS ARRAY\n";
+$arr = json_decode($arr_enc, true);
+var_dump($arr);
+
+?>
+--EXPECT--
+Testing:
+{
+ "JSON Test Pattern pass3": {
+ "The outermost value": "must be an object or array.",
+ "In this test": "It is an object."
+ }
+}
+
+DECODE: AS OBJECT
+object(stdClass)#1 (1) {
+ ["JSON Test Pattern pass3"]=>
+ object(stdClass)#2 (2) {
+ ["The outermost value"]=>
+ string(27) "must be an object or array."
+ ["In this test"]=>
+ string(16) "It is an object."
+ }
+}
+DECODE: AS ARRAY
+array(1) {
+ ["JSON Test Pattern pass3"]=>
+ array(2) {
+ ["The outermost value"]=>
+ string(27) "must be an object or array."
+ ["In this test"]=>
+ string(16) "It is an object."
+ }
+}
+ENCODE: FROM OBJECT
+{"JSON Test Pattern pass3":{"The outermost value":"must be an object or array.","In this test":"It is an object."}}
+ENCODE: FROM ARRAY
+{"JSON Test Pattern pass3":{"The outermost value":"must be an object or array.","In this test":"It is an object."}}
+DECODE AGAIN: AS OBJECT
+object(stdClass)#3 (1) {
+ ["JSON Test Pattern pass3"]=>
+ object(stdClass)#4 (2) {
+ ["The outermost value"]=>
+ string(27) "must be an object or array."
+ ["In this test"]=>
+ string(16) "It is an object."
+ }
+}
+DECODE AGAIN: AS ARRAY
+array(1) {
+ ["JSON Test Pattern pass3"]=>
+ array(2) {
+ ["The outermost value"]=>
+ string(27) "must be an object or array."
+ ["In this test"]=>
+ string(16) "It is an object."
+ }
+}
diff --git a/ext/json/tests/serialize.phpt b/ext/json/tests/serialize.phpt
new file mode 100644
index 000000000..5c513d58a
--- /dev/null
+++ b/ext/json/tests/serialize.phpt
@@ -0,0 +1,80 @@
+--TEST--
+json_encode() Serialization tests
+--SKIPIF--
+<?php if (!extension_loaded("json")) print "skip"; ?>
+--FILE--
+<?php
+
+class NonSerializingTest
+{
+ public $data;
+
+ public function __construct($data)
+ {
+ $this->data = $data;
+ }
+}
+
+class SerializingTest extends NonSerializingTest implements JsonSerializable
+{
+ public function jsonSerialize()
+ {
+ return $this->data;
+ }
+}
+
+class ValueSerializingTest extends SerializingTest
+{
+ public function jsonSerialize()
+ {
+ return array_values(is_array($this->data) ? $this->data : get_object_vars($this->data));
+ }
+}
+
+class SelfSerializingTest extends SerializingTest
+{
+ public function jsonSerialize()
+ {
+ return $this;
+ }
+}
+
+$adata = array(
+ 'str' => 'foo',
+ 'int' => 1,
+ 'float' => 2.3,
+ 'bool' => false,
+ 'nil' => null,
+ 'arr' => array(1,2,3),
+ 'obj' => new StdClass,
+);
+
+$ndata = array_values($adata);
+
+$odata = (object)$adata;
+
+foreach(array('NonSerializingTest','SerializingTest','ValueSerializingTest','SelfSerializingTest') as $class) {
+ echo "==$class==\n";
+ echo json_encode(new $class($adata)), "\n";
+ echo json_encode(new $class($ndata)), "\n";
+ echo json_encode(new $class($odata)), "\n";
+}
+--EXPECT--
+==NonSerializingTest==
+{"data":{"str":"foo","int":1,"float":2.3,"bool":false,"nil":null,"arr":[1,2,3],"obj":{}}}
+{"data":["foo",1,2.3,false,null,[1,2,3],{}]}
+{"data":{"str":"foo","int":1,"float":2.3,"bool":false,"nil":null,"arr":[1,2,3],"obj":{}}}
+==SerializingTest==
+{"str":"foo","int":1,"float":2.3,"bool":false,"nil":null,"arr":[1,2,3],"obj":{}}
+["foo",1,2.3,false,null,[1,2,3],{}]
+{"str":"foo","int":1,"float":2.3,"bool":false,"nil":null,"arr":[1,2,3],"obj":{}}
+==ValueSerializingTest==
+["foo",1,2.3,false,null,[1,2,3],{}]
+["foo",1,2.3,false,null,[1,2,3],{}]
+["foo",1,2.3,false,null,[1,2,3],{}]
+==SelfSerializingTest==
+{"data":{"str":"foo","int":1,"float":2.3,"bool":false,"nil":null,"arr":[1,2,3],"obj":{}}}
+{"data":["foo",1,2.3,false,null,[1,2,3],{}]}
+{"data":{"str":"foo","int":1,"float":2.3,"bool":false,"nil":null,"arr":[1,2,3],"obj":{}}}
+
+
diff --git a/ext/json/tests/unsupported_type_error.phpt b/ext/json/tests/unsupported_type_error.phpt
new file mode 100644
index 000000000..45a167a5a
--- /dev/null
+++ b/ext/json/tests/unsupported_type_error.phpt
@@ -0,0 +1,26 @@
+--TEST--
+An error is thrown when an unsupported type is encoded
+--SKIPIF--
+<?php if (!extension_loaded("json")) print "skip"; ?>
+--FILE--
+<?php
+
+$resource = fopen(__FILE__, "r");
+
+var_dump($resource);
+
+var_dump(json_encode($resource));
+var_dump(json_last_error(), json_last_error_msg());
+
+var_dump(json_encode($resource, JSON_PARTIAL_OUTPUT_ON_ERROR));
+var_dump(json_last_error(), json_last_error_msg());
+
+?>
+--EXPECTF--
+resource(5) of type (stream)
+bool(false)
+int(8)
+string(21) "Type is not supported"
+string(4) "null"
+int(8)
+string(21) "Type is not supported"
diff --git a/ext/json/utf8_decode.c b/ext/json/utf8_decode.c
new file mode 100644
index 000000000..2d0422bed
--- /dev/null
+++ b/ext/json/utf8_decode.c
@@ -0,0 +1,179 @@
+/* utf8_decode.c */
+
+/* 2005-12-25 */
+
+/*
+Copyright (c) 2005 JSON.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+#include "utf8_decode.h"
+
+/*
+ Very Strict UTF-8 Decoder
+
+ UTF-8 is a multibyte character encoding of Unicode. A character can be
+ represented by 1-4 bytes. The bit pattern of the first byte indicates the
+ number of continuation bytes.
+
+ Most UTF-8 decoders tend to be lenient, attempting to recover as much
+ information as possible, even from badly encoded input. This UTF-8
+ decoder is not lenient. It will reject input which does not include
+ proper continuation bytes. It will reject aliases (or suboptimal
+ codings). It will reject surrogates. (Surrogate encoding should only be
+ used with UTF-16.)
+
+ Code Contination Minimum Maximum
+ 0xxxxxxx 0 0 127
+ 10xxxxxx error
+ 110xxxxx 1 128 2047
+ 1110xxxx 2 2048 65535 excluding 55296 - 57343
+ 11110xxx 3 65536 1114111
+ 11111xxx error
+*/
+
+
+/*
+ Get the next byte. It returns UTF8_END if there are no more bytes.
+*/
+static int
+get(json_utf8_decode *utf8)
+{
+ int c;
+ if (utf8->the_index >= utf8->the_length) {
+ return UTF8_END;
+ }
+ c = utf8->the_input[utf8->the_index] & 0xFF;
+ utf8->the_index += 1;
+ return c;
+}
+
+
+/*
+ Get the 6-bit payload of the next continuation byte.
+ Return UTF8_ERROR if it is not a contination byte.
+*/
+static int
+cont(json_utf8_decode *utf8)
+{
+ int c = get(utf8);
+ return ((c & 0xC0) == 0x80) ? (c & 0x3F) : UTF8_ERROR;
+}
+
+
+/*
+ Initialize the UTF-8 decoder. The decoder is not reentrant,
+*/
+void
+utf8_decode_init(json_utf8_decode *utf8, char p[], int length)
+{
+ utf8->the_index = 0;
+ utf8->the_input = p;
+ utf8->the_length = length;
+ utf8->the_char = 0;
+ utf8->the_byte = 0;
+}
+
+
+/*
+ Get the current byte offset. This is generally used in error reporting.
+*/
+int
+utf8_decode_at_byte(json_utf8_decode *utf8)
+{
+ return utf8->the_byte;
+}
+
+
+/*
+ Get the current character offset. This is generally used in error reporting.
+ The character offset matches the byte offset if the text is strictly ASCII.
+*/
+int
+utf8_decode_at_character(json_utf8_decode *utf8)
+{
+ return utf8->the_char > 0 ? utf8->the_char - 1 : 0;
+}
+
+
+/*
+ Extract the next character.
+ Returns: the character (between 0 and 1114111)
+ or UTF8_END (the end)
+ or UTF8_ERROR (error)
+*/
+int
+utf8_decode_next(json_utf8_decode *utf8)
+{
+ int c; /* the first byte of the character */
+ int r; /* the result */
+
+ if (utf8->the_index >= utf8->the_length) {
+ return utf8->the_index == utf8->the_length ? UTF8_END : UTF8_ERROR;
+ }
+ utf8->the_byte = utf8->the_index;
+ utf8->the_char += 1;
+ c = get(utf8);
+/*
+ Zero continuation (0 to 127)
+*/
+ if ((c & 0x80) == 0) {
+ return c;
+ }
+/*
+ One contination (128 to 2047)
+*/
+ if ((c & 0xE0) == 0xC0) {
+ int c1 = cont(utf8);
+ if (c1 < 0) {
+ return UTF8_ERROR;
+ }
+ r = ((c & 0x1F) << 6) | c1;
+ return r >= 128 ? r : UTF8_ERROR;
+ }
+/*
+ Two continuation (2048 to 55295 and 57344 to 65535)
+*/
+ if ((c & 0xF0) == 0xE0) {
+ int c1 = cont(utf8);
+ int c2 = cont(utf8);
+ if (c1 < 0 || c2 < 0) {
+ return UTF8_ERROR;
+ }
+ r = ((c & 0x0F) << 12) | (c1 << 6) | c2;
+ return r >= 2048 && (r < 55296 || r > 57343) ? r : UTF8_ERROR;
+ }
+/*
+ Three continuation (65536 to 1114111)
+*/
+ if ((c & 0xF8) == 0xF0) {
+ int c1 = cont(utf8);
+ int c2 = cont(utf8);
+ int c3 = cont(utf8);
+ if (c1 < 0 || c2 < 0 || c3 < 0) {
+ return UTF8_ERROR;
+ }
+ r = ((c & 0x0F) << 18) | (c1 << 12) | (c2 << 6) | c3;
+ return r >= 65536 && r <= 1114111 ? r : UTF8_ERROR;
+ }
+ return UTF8_ERROR;
+}
diff --git a/ext/json/utf8_decode.h b/ext/json/utf8_decode.h
new file mode 100644
index 000000000..cc0fc79f6
--- /dev/null
+++ b/ext/json/utf8_decode.h
@@ -0,0 +1,18 @@
+/* utf8_decode.h */
+
+#define UTF8_END -1
+#define UTF8_ERROR -2
+
+typedef struct json_utf8_decode
+{
+ int the_index;
+ char *the_input;
+ int the_length;
+ int the_char;
+ int the_byte;
+} json_utf8_decode;
+
+extern int utf8_decode_at_byte(json_utf8_decode *utf8);
+extern int utf8_decode_at_character(json_utf8_decode *utf8);
+extern void utf8_decode_init(json_utf8_decode *utf8, char p[], int length);
+extern int utf8_decode_next(json_utf8_decode *utf8);
diff --git a/ext/opcache/shared_alloc_shm.c b/ext/opcache/shared_alloc_shm.c
index d53236b3b..a88cc2e19 100644
--- a/ext/opcache/shared_alloc_shm.c
+++ b/ext/opcache/shared_alloc_shm.c
@@ -54,7 +54,7 @@ typedef struct {
static int create_segments(size_t requested_size, zend_shared_segment_shm ***shared_segments_p, int *shared_segments_count, char **error_in)
{
int i;
- unsigned int allocate_size = 0, remaining_bytes = requested_size, seg_allocate_size;
+ size_t allocate_size = 0, remaining_bytes = requested_size, seg_allocate_size;
int first_segment_id = -1;
key_t first_segment_key = -1;
struct shmid_ds sds;
diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c
index 0bffae4d0..9f1940e06 100644
--- a/ext/opcache/zend_persist.c
+++ b/ext/opcache/zend_persist.c
@@ -52,6 +52,10 @@ typedef void (*zend_persist_func_t)(void * TSRMLS_DC);
static void zend_persist_zval_ptr(zval **zp TSRMLS_DC);
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+static const Bucket *uninitialized_bucket = NULL;
+#endif
+
static void zend_hash_persist(HashTable *ht, void (*pPersistElement)(void *pElement TSRMLS_DC), size_t el_size TSRMLS_DC)
{
Bucket *p = ht->pListHead;
@@ -129,7 +133,7 @@ static void zend_hash_persist(HashTable *ht, void (*pPersistElement)(void *pElem
zend_accel_store(ht->arBuckets, sizeof(Bucket*) * ht->nTableSize);
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
} else {
- ht->arBuckets = NULL;
+ ht->arBuckets = (Bucket**)&uninitialized_bucket;
}
#endif
}
diff --git a/ext/opcache/zend_shared_alloc.c b/ext/opcache/zend_shared_alloc.c
index 5405751ac..d752afea1 100644
--- a/ext/opcache/zend_shared_alloc.c
+++ b/ext/opcache/zend_shared_alloc.c
@@ -119,7 +119,7 @@ static void copy_shared_segments(void *to, void *from, int count, int size)
}
}
-static int zend_shared_alloc_try(const zend_shared_memory_handler_entry *he, int requested_size, zend_shared_segment ***shared_segments_p, int *shared_segments_count, char **error_in)
+static int zend_shared_alloc_try(const zend_shared_memory_handler_entry *he, size_t requested_size, zend_shared_segment ***shared_segments_p, int *shared_segments_count, char **error_in)
{
int res;
g_shared_alloc_handler = he->handler;
@@ -148,7 +148,7 @@ static int zend_shared_alloc_try(const zend_shared_memory_handler_entry *he, int
return ALLOC_FAILURE;
}
-int zend_shared_alloc_startup(int requested_size)
+int zend_shared_alloc_startup(size_t requested_size)
{
zend_shared_segment **tmp_shared_segments;
size_t shared_segments_array_size;
diff --git a/ext/opcache/zend_shared_alloc.h b/ext/opcache/zend_shared_alloc.h
index b7f36299b..e94ecab9b 100644
--- a/ext/opcache/zend_shared_alloc.h
+++ b/ext/opcache/zend_shared_alloc.h
@@ -117,7 +117,7 @@ extern zend_smm_shared_globals *smm_shared_globals;
#define SHARED_ALLOC_REATTACHED (SUCCESS+1)
-int zend_shared_alloc_startup(int requested_size);
+int zend_shared_alloc_startup(size_t requested_size);
void zend_shared_alloc_shutdown(void);
/* allocate shared memory block */
diff --git a/ext/pdo/tests/bug61292.phpt b/ext/pdo/tests/bug61292.phpt
index 2381fd1a2..05b2e9c01 100644
--- a/ext/pdo/tests/bug61292.phpt
+++ b/ext/pdo/tests/bug61292.phpt
@@ -17,8 +17,15 @@ class Database_SQL extends PDO
{
function __construct()
{
+ $dsn = getenv('PDOTEST_DSN');
+ $user = getenv('PDOTEST_USER');
+ $pass = getenv('PDOTEST_PASS');
+
+ if ($user === false) $user = NULL;
+ if ($pass === false) $pass = NULL;
$options = array(PDO::ATTR_PERSISTENT => TRUE);
- parent::__construct(getenv("PDOTEST_DSN"), getenv("PDOTEST_USER"), getenv("PDOTEST_PASS"), $options);
+
+ parent::__construct($dsn, $user, $pass, $options);
}
var $bar = array();
diff --git a/ext/pdo_dblib/dblib_driver.c b/ext/pdo_dblib/dblib_driver.c
index ffc910177..9ed508736 100644
--- a/ext/pdo_dblib/dblib_driver.c
+++ b/ext/pdo_dblib/dblib_driver.c
@@ -32,6 +32,9 @@
#include "php_pdo_dblib_int.h"
#include "zend_exceptions.h"
+/* Cache of the server supported datatypes, initialized in handle_factory */
+zval* pdo_dblib_datatypes;
+
static int dblib_fetch_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval *info TSRMLS_DC)
{
pdo_dblib_db_handle *H = (pdo_dblib_db_handle *)dbh->driver_data;
@@ -262,17 +265,37 @@ static struct pdo_dbh_methods dblib_methods = {
static int pdo_dblib_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC)
{
pdo_dblib_db_handle *H;
- int i, ret = 0;
+ int i, nvars, nvers, ret = 0;
+ int *val;
+
+ const pdo_dblib_keyval tdsver[] = {
+ {"4.2",DBVERSION_42}
+ ,{"4.6",DBVERSION_46}
+ ,{"5.0",DBVERSION_70} /* FIXME: This does not work with Sybase, but environ will */
+ ,{"6.0",DBVERSION_70}
+ ,{"7.0",DBVERSION_70}
+ ,{"7.1",DBVERSION_71}
+ ,{"7.2",DBVERSION_72}
+ ,{"8.0",DBVERSION_72}
+ ,{"10.0",DBVERSION_100}
+ ,{"auto",0} /* Only works with FreeTDS. Other drivers will bork */
+
+ };
+
+ nvers = sizeof(tdsver)/sizeof(tdsver[0]);
+
struct pdo_data_src_parser vars[] = {
- { "charset", NULL, 0 },
- { "appname", "PHP " PDO_DBLIB_FLAVOUR, 0 },
- { "host", "127.0.0.1", 0 },
- { "dbname", NULL, 0 },
- { "secure", NULL, 0 }, /* DBSETLSECURE */
- /* TODO: DBSETLVERSION ? */
+ { "charset", NULL, 0 }
+ ,{ "appname", "PHP " PDO_DBLIB_FLAVOUR, 0 }
+ ,{ "host", "127.0.0.1", 0 }
+ ,{ "dbname", NULL, 0 }
+ ,{ "secure", NULL, 0 } /* DBSETLSECURE */
+ ,{ "version", NULL, 0 } /* DBSETLVERSION */
};
-
- php_pdo_parse_data_source(dbh->data_source, dbh->data_source_len, vars, 5);
+
+ nvars = sizeof(vars)/sizeof(vars[0]);
+
+ php_pdo_parse_data_source(dbh->data_source, dbh->data_source_len, vars, nvars);
H = pecalloc(1, sizeof(*H), dbh->is_persistent);
H->login = dblogin();
@@ -282,11 +305,37 @@ static int pdo_dblib_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_
goto cleanup;
}
+ DBERRHANDLE(H->login, (EHANDLEFUNC) error_handler);
+ DBMSGHANDLE(H->login, (MHANDLEFUNC) msg_handler);
+
+ if(vars[5].optval) {
+ for(i=0;i<nvers;i++) {
+ if(strcmp(vars[5].optval,tdsver[i].key) == 0) {
+ if(FAIL==dbsetlversion(H->login, tdsver[i].value)) {
+ pdo_raise_impl_error(dbh, NULL, "HY000", "PDO_DBLIB: Failed to set version specified in connection string." TSRMLS_CC);
+ goto cleanup;
+ }
+ break;
+ }
+ }
+
+ if (i==nvers) {
+ printf("Invalid version '%s'\n", vars[5].optval);
+ pdo_raise_impl_error(dbh, NULL, "HY000", "PDO_DBLIB: Invalid version specified in connection string." TSRMLS_CC);
+ goto cleanup; /* unknown version specified */
+ }
+ }
+
if (dbh->username) {
- DBSETLUSER(H->login, dbh->username);
+ if(FAIL == DBSETLUSER(H->login, dbh->username)) {
+ goto cleanup;
+ }
}
+
if (dbh->password) {
- DBSETLPWD(H->login, dbh->password);
+ if(FAIL == DBSETLPWD(H->login, dbh->password)) {
+ goto cleanup;
+ }
}
#if !PHP_DBLIB_IS_MSSQL
@@ -297,14 +346,9 @@ static int pdo_dblib_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_
DBSETLAPP(H->login, vars[1].optval);
-#if PHP_DBLIB_IS_MSSQL
- dbprocerrhandle(H->login, (EHANDLEFUNC) error_handler);
- dbprocmsghandle(H->login, (MHANDLEFUNC) msg_handler);
-#endif
-
H->link = dbopen(H->login, vars[2].optval);
- if (H->link == NULL) {
+ if (!H->link) {
goto cleanup;
}
@@ -315,18 +359,35 @@ static int pdo_dblib_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_
DBSETOPT(H->link, DBTEXTSIZE, "2147483647");
/* allow double quoted indentifiers */
- DBSETOPT(H->link, DBQUOTEDIDENT, NULL);
+ DBSETOPT(H->link, DBQUOTEDIDENT, "1");
- if (vars[3].optval && FAIL == dbuse(H->link, vars[3].optval)) {
- goto cleanup;
+ if (vars[3].optval) {
+ DBSETLDBNAME(H->login, vars[3].optval);
}
ret = 1;
dbh->max_escaped_char_length = 2;
dbh->alloc_own_columns = 1;
+#if 0
+ /* Cache the supported data types from the servers systypes table */
+ if(dbcmd(H->link, "select usertype, name from systypes order by usertype") != FAIL) {
+ if(dbsqlexec(H->link) != FAIL) {
+ dbresults(H->link);
+ while (dbnextrow(H->link) == SUCCESS) {
+ val = dbdata(H->link, 1);
+ add_index_string(pdo_dblib_datatypes, *val, dbdata(H->link, 2), 1);
+ }
+ }
+ /* Throw out any remaining resultsets */
+ dbcancel(H-link);
+ }
+#endif
+
+
+
cleanup:
- for (i = 0; i < sizeof(vars)/sizeof(vars[0]); i++) {
+ for (i = 0; i < nvars; i++) {
if (vars[i].freeme) {
efree(vars[i].optval);
}
diff --git a/ext/pdo_dblib/dblib_stmt.c b/ext/pdo_dblib/dblib_stmt.c
index 1a2fefd47..51cebc48b 100644
--- a/ext/pdo_dblib/dblib_stmt.c
+++ b/ext/pdo_dblib/dblib_stmt.c
@@ -36,35 +36,51 @@
/* {{{ pdo_dblib_get_field_name
*
- * Updated for MSSQL 2008 SR2 extended types
+ * Return the data type name for a given TDS number
*
*/
static char *pdo_dblib_get_field_name(int type)
{
+ /*
+ * I don't return dbprtype(type) because it does not fully describe the type
+ * (example: varchar is reported as char by dbprtype)
+ *
+ * FIX ME: Cache datatypes from server systypes table in pdo_dblib_handle_factory()
+ * to make this future proof.
+ */
+
switch (type) {
+ case 31: return "nvarchar";
case 34: return "image";
case 35: return "text";
case 36: return "uniqueidentifier";
+ case 37: return "varbinary"; /* & timestamp - Sybase AS12 */
+ case 38: return "bigint"; /* & bigintn - Sybase AS12 */
+ case 39: return "varchar"; /* & sysname & nvarchar - Sybase AS12 */
case 40: return "date";
case 41: return "time";
case 42: return "datetime2";
case 43: return "datetimeoffset";
+ case 45: return "binary"; /* Sybase AS12 */
+ case 47: return "char"; /* & nchar & uniqueidentifierstr Sybase AS12 */
case 48: return "tinyint";
+ case 50: return "bit"; /* Sybase AS12 */
case 52: return "smallint";
+ case 55: return "decimal"; /* Sybase AS12 */
case 56: return "int";
case 58: return "smalldatetime";
case 59: return "real";
case 60: return "money";
case 61: return "datetime";
case 62: return "float";
+ case 63: return "numeric"; /* or uint, ubigint, usmallint Sybase AS12 */
case 98: return "sql_variant";
case 99: return "ntext";
case 104: return "bit";
- case 106: return "decimal";
- case 108: return "numeric";
+ case 106: return "decimal"; /* decimal n on sybase */
+ case 108: return "numeric"; /* numeric n on sybase */
case 122: return "smallmoney";
case 127: return "bigint";
- case 240: return "geometry";
case 165: return "varbinary";
case 167: return "varchar";
case 173: return "binary";
@@ -72,23 +88,22 @@ static char *pdo_dblib_get_field_name(int type)
case 189: return "timestamp";
case 231: return "nvarchar";
case 239: return "nchar";
+ case 240: return "geometry";
case 241: return "xml";
- default:
- return "unknown";
- break;
+ default: return "unknown";
}
}
/* }}} */
-static int dblib_dblib_stmt_cursor_closer(pdo_stmt_t *stmt TSRMLS_DC)
+static int pdo_dblib_stmt_cursor_closer(pdo_stmt_t *stmt TSRMLS_DC)
{
pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data;
pdo_dblib_db_handle *H = S->H;
/* Cancel any pending results */
dbcancel(H->link);
-
- efree(stmt->columns);
+
+ efree(stmt->columns);
stmt->columns = NULL;
return 1;
@@ -98,7 +113,8 @@ static int pdo_dblib_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC)
{
pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data;
- dblib_dblib_stmt_cursor_closer(stmt TSRMLS_CC);
+ efree(stmt->columns);
+ stmt->columns = NULL;
efree(S);
@@ -113,7 +129,12 @@ static int pdo_dblib_stmt_next_rowset(pdo_stmt_t *stmt TSRMLS_DC)
ret = dbresults(H->link);
- if (ret == FAIL || ret == NO_MORE_RESULTS) {
+ if (FAIL == ret) {
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO_DBLIB: dbresults() returned FAIL" TSRMLS_CC);
+ return 0;
+ }
+
+ if(NO_MORE_RESULTS == ret) {
return 0;
}
@@ -131,6 +152,8 @@ static int pdo_dblib_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC)
dbsetuserdata(H->link, (BYTE*) &S->err);
+ pdo_dblib_stmt_cursor_closer(stmt TSRMLS_CC);
+
if (FAIL == dbcmd(H->link, stmt->active_query_string)) {
return 0;
}
@@ -141,10 +164,6 @@ static int pdo_dblib_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC)
ret = pdo_dblib_stmt_next_rowset(stmt TSRMLS_CC);
- if (ret == 0) {
- return 0;
- }
-
stmt->row_count = DBCOUNT(H->link);
stmt->column_count = dbnumcols(H->link);
@@ -162,7 +181,12 @@ static int pdo_dblib_stmt_fetch(pdo_stmt_t *stmt,
ret = dbnextrow(H->link);
- if (ret == FAIL || ret == NO_MORE_ROWS) {
+ if (FAIL == ret) {
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO_DBLIB: dbnextrow() returned FAIL" TSRMLS_CC);
+ return 0;
+ }
+
+ if(NO_MORE_ROWS == ret) {
return 0;
}
@@ -174,6 +198,10 @@ static int pdo_dblib_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC)
pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data;
pdo_dblib_db_handle *H = S->H;
+ if(colno >= stmt->column_count || colno < 0) {
+ return FAILURE;
+ }
+
struct pdo_column_data *col = &stmt->columns[colno];
col->name = (char*)dbcolname(H->link, colno+1);
@@ -205,11 +233,12 @@ static int pdo_dblib_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr,
}
switch (coltype) {
- case SQLCHAR:
- case SQLTEXT:
case SQLVARBINARY:
case SQLBINARY:
case SQLIMAGE:
+ case SQLTEXT:
+ /* FIXME: Above types should be returned as a stream as they can be VERY large */
+ case SQLCHAR:
case SQLVARCHAR:
tmp_ptr = emalloc(*len + 1);
memcpy(tmp_ptr, *ptr, *len);
@@ -225,34 +254,26 @@ static int pdo_dblib_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr,
*ptr = tmp_ptr;
break;
}
-#ifdef SQLUNIQUE
case SQLUNIQUE: {
-#else
- case 36: { /* FreeTDS hack, also used by ext/mssql */
-#endif
*len = 36+1;
tmp_ptr = emalloc(*len + 1);
/* uniqueidentifier is a 16-byte binary number, convert to 32 char hex string */
-#ifdef SQLUNIQUE
*len = dbconvert(NULL, SQLUNIQUE, *ptr, *len, SQLCHAR, tmp_ptr, *len);
-#else
- *len = dbconvert(NULL, 36, *ptr, *len, SQLCHAR, tmp_ptr, *len);
-#endif
php_strtoupper(tmp_ptr, *len);
*ptr = tmp_ptr;
break;
}
default:
if (dbwillconvert(coltype, SQLCHAR)) {
- tmp_len = 32 + (2 * (*len));
+ tmp_len = 32 + (2 * (*len)); /* FIXME: We allocate more than we need here */
tmp_ptr = emalloc(tmp_len);
*len = dbconvert(NULL, coltype, *ptr, *len, SQLCHAR, tmp_ptr, -1);
*ptr = tmp_ptr;
- } else {
- *len = 0;
- *ptr = NULL;
- }
+ } else {
+ *len = 0; /* FIXME: Silently fails and returns null on conversion errors */
+ *ptr = NULL;
+ }
}
*caller_frees = 1;
@@ -270,17 +291,25 @@ static int pdo_dblib_stmt_get_column_meta(pdo_stmt_t *stmt, long colno, zval *re
{
pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data;
pdo_dblib_db_handle *H = S->H;
-
+ DBTYPEINFO* dbtypeinfo;
+
+ if(colno >= stmt->column_count || colno < 0) {
+ return FAILURE;
+ }
+
array_init(return_value);
- DBTYPEINFO* dbtypeinfo;
dbtypeinfo = dbcoltypeinfo(H->link, colno+1);
+
+ if(!dbtypeinfo) return FAILURE;
add_assoc_long(return_value, "max_length", dbcollen(H->link, colno+1) );
add_assoc_long(return_value, "precision", (int) dbtypeinfo->precision );
add_assoc_long(return_value, "scale", (int) dbtypeinfo->scale );
add_assoc_string(return_value, "column_source", dbcolsource(H->link, colno+1), 1);
add_assoc_string(return_value, "native_type", pdo_dblib_get_field_name(dbcoltype(H->link, colno+1)), 1);
+ add_assoc_long(return_value, "native_type_id", dbcoltype(H->link, colno+1));
+ add_assoc_long(return_value, "native_usertype_id", dbcolutype(H->link, colno+1));
return 1;
}
@@ -297,6 +326,6 @@ struct pdo_stmt_methods dblib_stmt_methods = {
NULL, /* get attr */
pdo_dblib_stmt_get_column_meta, /* meta */
pdo_dblib_stmt_next_rowset, /* nextrow */
- dblib_dblib_stmt_cursor_closer
+ pdo_dblib_stmt_cursor_closer
};
diff --git a/ext/pdo_dblib/pdo_dblib.c b/ext/pdo_dblib/pdo_dblib.c
index ed79aea20..bc5d364ed 100644
--- a/ext/pdo_dblib/pdo_dblib.c
+++ b/ext/pdo_dblib/pdo_dblib.c
@@ -93,8 +93,12 @@ int error_handler(DBPROCESS *dbproc, int severity, int dberr,
char *state = "HY000";
TSRMLS_FETCH();
- einfo = (pdo_dblib_err*)dbgetuserdata(dbproc);
- if (!einfo) einfo = &DBLIB_G(err);
+ if(dbproc) {
+ einfo = (pdo_dblib_err*)dbgetuserdata(dbproc);
+ if (!einfo) einfo = &DBLIB_G(err);
+ } else {
+ einfo = &DBLIB_G(err);
+ }
einfo->severity = severity;
einfo->oserr = oserr;
diff --git a/ext/pdo_dblib/php_pdo_dblib_int.h b/ext/pdo_dblib/php_pdo_dblib_int.h
index dd06a1d94..2bdb83c32 100644
--- a/ext/pdo_dblib/php_pdo_dblib_int.h
+++ b/ext/pdo_dblib/php_pdo_dblib_int.h
@@ -71,6 +71,8 @@
# define SQLVARBINARY SYBVARBINARY
# ifdef SYBUNIQUE
# define SQLUNIQUE SYBUNIQUE
+#else
+# define SQLUNIQUE 36 /* FreeTDS Hack */
# endif
# define DBERRHANDLE(a, b) dberrhandle(b)
@@ -118,6 +120,12 @@ typedef struct {
pdo_dblib_err err;
} pdo_dblib_stmt;
+typedef struct {
+ const char* key;
+ int value;
+} pdo_dblib_keyval;
+
+
ZEND_BEGIN_MODULE_GLOBALS(dblib)
pdo_dblib_err err;
char sqlstate[6];
diff --git a/ext/pdo_firebird/firebird_statement.c b/ext/pdo_firebird/firebird_statement.c
index 5c3e435f7..2b57cd8ba 100644
--- a/ext/pdo_firebird/firebird_statement.c
+++ b/ext/pdo_firebird/firebird_statement.c
@@ -344,7 +344,7 @@ static int firebird_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, /* {{
if (n >= 0) {
*len = slprintf(*ptr, CHAR_BUF_LEN, "%" LL_MASK "d.%0*" LL_MASK "d",
n / f, -var->sqlscale, n % f);
- } else if (n < -f) {
+ } else if (n <= -f) {
*len = slprintf(*ptr, CHAR_BUF_LEN, "%" LL_MASK "d.%0*" LL_MASK "d",
n / f, -var->sqlscale, -n % f);
} else {
@@ -535,12 +535,14 @@ static int firebird_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_dat
int force_null;
case IS_LONG:
- var->sqltype = sizeof(long) == 8 ? SQL_INT64 : SQL_LONG;
+ /* keep the allow-NULL flag */
+ var->sqltype = (sizeof(long) == 8 ? SQL_INT64 : SQL_LONG) | (var->sqltype & 1);
var->sqldata = (void*)&Z_LVAL_P(param->parameter);
var->sqllen = sizeof(long);
break;
case IS_DOUBLE:
- var->sqltype = SQL_DOUBLE;
+ /* keep the allow-NULL flag */
+ var->sqltype = SQL_DOUBLE | (var->sqltype & 1);
var->sqldata = (void*)&Z_DVAL_P(param->parameter);
var->sqllen = sizeof(double);
break;
@@ -560,7 +562,8 @@ static int firebird_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_dat
force_null = (Z_STRLEN_P(param->parameter) == 0);
}
if (!force_null) {
- var->sqltype = SQL_TEXT;
+ /* keep the allow-NULL flag */
+ var->sqltype = SQL_TEXT | (var->sqltype & 1);
var->sqldata = Z_STRVAL_P(param->parameter);
var->sqllen = Z_STRLEN_P(param->parameter);
break;
diff --git a/ext/pdo_firebird/tests/bug_62024.phpt b/ext/pdo_firebird/tests/bug_62024.phpt
new file mode 100644
index 000000000..e046879c2
--- /dev/null
+++ b/ext/pdo_firebird/tests/bug_62024.phpt
@@ -0,0 +1,51 @@
+--TEST--
+Bug #62024 Cannot insert second row with null using parametrized query (Firebird PDO)
+--SKIPIF--
+<?php extension_loaded("pdo_firebird") or die("skip"); ?>
+<?php function_exists("ibase_query") or die("skip"); ?>
+--FILE--
+<?php
+
+require("testdb.inc");
+
+$dbh = new PDO("firebird:dbname=$test_base",$user,$password) or die;
+$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
+$value = '2';
+@$dbh->exec('DROP TABLE test_insert');
+$dbh->exec("CREATE TABLE test_insert (ID INTEGER NOT NULL, TEXT VARCHAR(10))");
+
+$dbh->commit();
+
+//start actual test
+
+$sql = "insert into test_insert (id, text) values (?, ?)";
+$sttmt = $dbh->prepare($sql);
+
+$args_ok = array(1, "test1");
+$args_err = array(2, null);
+
+$res = $sttmt->execute($args_ok);
+var_dump($res);
+
+$res = $sttmt->execute($args_err);
+var_dump($res);
+
+$dbh->commit();
+
+
+//teardown test data
+$sttmt = $dbh->prepare('DELETE FROM test_insert');
+$sttmt->execute();
+
+$dbh->commit();
+
+$dbh->exec('DROP TABLE test_insert');
+
+unset($sttmt);
+unset($dbh);
+
+?>
+--EXPECT--
+bool(true)
+bool(true)
+
diff --git a/ext/pdo_firebird/tests/bug_64037.phpt b/ext/pdo_firebird/tests/bug_64037.phpt
new file mode 100644
index 000000000..f7b53e57a
--- /dev/null
+++ b/ext/pdo_firebird/tests/bug_64037.phpt
@@ -0,0 +1,45 @@
+--TEST--
+Bug #64037 Firebird return wrong value for numeric field
+--SKIPIF--
+<?php extension_loaded("pdo_firebird") or die("skip"); ?>
+<?php function_exists("ibase_query") or die("skip"); ?>
+--FILE--
+<?php
+
+require("testdb.inc");
+
+$dbh = new PDO("firebird:dbname=$test_base",$user,$password) or die;
+$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
+$value = '2';
+@$dbh->exec('DROP TABLE price');
+$dbh->exec("CREATE TABLE PRICE (ID INTEGER NOT NULL, TEXT VARCHAR(10), COST NUMERIC(15, 2))");
+$dbh->exec("INSERT INTO PRICE (ID, TEXT, COST) VALUES (1, 'test', -1.0)");
+$dbh->exec("INSERT INTO PRICE (ID, TEXT, COST) VALUES (2, 'test', -0.99)");
+$dbh->exec("INSERT INTO PRICE (ID, TEXT, COST) VALUES (3, 'test', -1.01)");
+
+$dbh->commit();
+
+$query = "SELECT * from price order by ID";
+$stmt = $dbh->prepare($query);
+$stmt->execute();
+$rows = $stmt->fetchAll();
+var_dump($rows[0]['COST']);
+var_dump($rows[1]['COST']);
+var_dump($rows[2]['COST']);
+
+
+$stmt = $dbh->prepare('DELETE FROM price');
+$stmt->execute();
+
+$dbh->commit();
+
+$dbh->exec('DROP TABLE price');
+
+unset($stmt);
+unset($dbh);
+
+?>
+--EXPECT--
+string(5) "-1.00"
+string(5) "-0.99"
+string(5) "-1.01" \ No newline at end of file
diff --git a/ext/pdo_pgsql/pgsql_driver.c b/ext/pdo_pgsql/pgsql_driver.c
index a54fccd0e..252bfff25 100644
--- a/ext/pdo_pgsql/pgsql_driver.c
+++ b/ext/pdo_pgsql/pgsql_driver.c
@@ -76,7 +76,7 @@ int _pdo_pgsql_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, int errcode, const char *
einfo->errmsg = NULL;
}
- if (sqlstate == NULL) {
+ if (sqlstate == NULL || strlen(sqlstate) >= sizeof(pdo_error_type)) {
strcpy(*pdo_err, "HY000");
}
else {
diff --git a/ext/pdo_pgsql/tests/copy_from.phpt b/ext/pdo_pgsql/tests/copy_from.phpt
index 2858905d0..10967b0fe 100644
--- a/ext/pdo_pgsql/tests/copy_from.phpt
+++ b/ext/pdo_pgsql/tests/copy_from.phpt
@@ -110,8 +110,10 @@ $db->rollback();
echo "Exception! at line ", $e->getLine(), "\n";
var_dump($e->getMessage());
}
-if(isset($filename)) {
- @unlink($filename);
+
+// Clean up
+foreach (array($filename, $filenameWithDifferentNullValues, $filenameWithDifferentNullValuesAndSelectedFields) as $f) {
+ @unlink($f);
}
?>
--EXPECT--
@@ -383,4 +385,4 @@ array(6) {
NULL
}
Testing pgsqlCopyFromFile() with error
-bool(false) \ No newline at end of file
+bool(false)
diff --git a/ext/pgsql/pgsql.c b/ext/pgsql/pgsql.c
index 7ee838a9f..dcc2c2869 100644
--- a/ext/pgsql/pgsql.c
+++ b/ext/pgsql/pgsql.c
@@ -4998,7 +4998,7 @@ PHP_PGSQL_API int php_pgsql_meta_data(PGconn *pg_link, const char *table_name, z
}
smart_str_appends(&querystr,
- "SELECT a.attname, a.attnum, t.typname, a.attlen, a.attnotNULL, a.atthasdef, a.attndims "
+ "SELECT a.attname, a.attnum, t.typname, a.attlen, a.attnotnull, a.atthasdef, a.attndims, t.typtype = 'e' "
"FROM pg_class as c, pg_attribute a, pg_type t, pg_namespace n "
"WHERE a.attnum > 0 AND a.attrelid = c.oid AND c.relname = '");
tmp_name2 = php_addslashes(tmp_name2, strlen(tmp_name2), &new_len, 0 TSRMLS_CC);
@@ -5044,6 +5044,12 @@ PHP_PGSQL_API int php_pgsql_meta_data(PGconn *pg_link, const char *table_name, z
add_assoc_bool(elem, "has default", 0);
}
add_assoc_long(elem, "array dims", atoi(PQgetvalue(pg_result,i,6)));
+ if (!strcmp(PQgetvalue(pg_result,i,7), "t")) {
+ add_assoc_bool(elem, "is enum", 1);
+ }
+ else {
+ add_assoc_bool(elem, "is enum", 0);
+ }
name = PQgetvalue(pg_result,i,0);
add_assoc_zval(meta, name, elem);
}
@@ -5077,7 +5083,18 @@ PHP_FUNCTION(pg_meta_data)
zval_dtor(return_value); /* destroy array */
RETURN_FALSE;
}
-}
+ else {
+ HashPosition pos;
+ zval **val;
+
+ for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(return_value), &pos);
+ zend_hash_get_current_data_ex(Z_ARRVAL_P(return_value), (void **)&val, &pos) == SUCCESS;
+ zend_hash_move_forward_ex(Z_ARRVAL_P(return_value), &pos)) {
+ /* delete newly added entry, in order to keep BC */
+ zend_hash_del_key_or_index(Z_ARRVAL_PP(val), "is enum", sizeof("is enum"), 0, HASH_DEL_KEY);
+ }
+ }
+}
/* }}} */
/* {{{ php_pgsql_get_data_type
@@ -5259,8 +5276,9 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con
char *field = NULL;
uint field_len = -1;
ulong num_idx = -1;
- zval *meta, **def, **type, **not_null, **has_default, **val, *new_val;
+ zval *meta, **def, **type, **not_null, **has_default, **is_enum, **val, *new_val;
int new_len, key_type, err = 0, skip_field;
+ php_pgsql_data_type data_type;
assert(pg_link != NULL);
assert(Z_TYPE_P(values) == IS_ARRAY);
@@ -5311,17 +5329,30 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con
php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected broken meta data. Missing 'has default'");
err = 1;
}
+ if (!err && zend_hash_find(Z_ARRVAL_PP(def), "is enum", sizeof("is enum"), (void **)&is_enum) == FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected broken meta data. Missing 'is enum'");
+ err = 1;
+ }
if (!err && (Z_TYPE_PP(val) == IS_ARRAY ||
Z_TYPE_PP(val) == IS_OBJECT ||
Z_TYPE_PP(val) == IS_CONSTANT_ARRAY)) {
- php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects scaler values as field values");
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects scalar values as field values");
err = 1;
}
if (err) {
break; /* break out for() */
}
ALLOC_INIT_ZVAL(new_val);
- switch(php_pgsql_get_data_type(Z_STRVAL_PP(type), Z_STRLEN_PP(type)))
+
+ if (Z_BVAL_PP(is_enum)) {
+ /* enums need to be treated like strings */
+ data_type = PG_TEXT;
+ }
+ else {
+ data_type = php_pgsql_get_data_type(Z_STRVAL_PP(type), Z_STRLEN_PP(type));
+ }
+
+ switch(data_type)
{
case PG_BOOL:
switch (Z_TYPE_PP(val)) {
diff --git a/ext/pgsql/tests/10pg_convert_85.phpt b/ext/pgsql/tests/10pg_convert_85.phpt
index 4f1c92bf1..8b1cc8f53 100644
--- a/ext/pgsql/tests/10pg_convert_85.phpt
+++ b/ext/pgsql/tests/10pg_convert_85.phpt
@@ -12,6 +12,7 @@ error_reporting(E_ALL);
include 'config.inc';
$db = pg_connect($conn_str);
+pg_query($db, "SET standard_conforming_strings = 0");
$fields = array('num'=>'1234', 'str'=>'AAA', 'bin'=>'BBB');
$converted = pg_convert($db, $table_name, $fields);
diff --git a/ext/pgsql/tests/12pg_insert_85.phpt b/ext/pgsql/tests/12pg_insert_85.phpt
index a85dea036..5fbbe4b7a 100644
--- a/ext/pgsql/tests/12pg_insert_85.phpt
+++ b/ext/pgsql/tests/12pg_insert_85.phpt
@@ -12,6 +12,8 @@ error_reporting(E_ALL);
include 'config.inc';
$db = pg_connect($conn_str);
+pg_query($db, "SET standard_conforming_strings = 0");
+
$fields = array('num'=>'1234', 'str'=>'AAA', 'bin'=>'BBB');
pg_insert($db, $table_name, $fields) or print "Error in test 1\n";
diff --git a/ext/pgsql/tests/14pg_update_85.phpt b/ext/pgsql/tests/14pg_update_85.phpt
index f1c77eac1..06ca8c3de 100644
--- a/ext/pgsql/tests/14pg_update_85.phpt
+++ b/ext/pgsql/tests/14pg_update_85.phpt
@@ -12,6 +12,8 @@ error_reporting(E_ALL);
include 'config.inc';
$db = pg_connect($conn_str);
+pg_query($db, "SET standard_conforming_strings = 0");
+
$fields = array('num'=>'1234', 'str'=>'ABC', 'bin'=>'XYZ');
$ids = array('num'=>'1234');
diff --git a/ext/pgsql/tests/18pg_escape_bytea.phpt b/ext/pgsql/tests/18pg_escape_bytea.phpt
index 43f98c446..5f52a17d9 100644
--- a/ext/pgsql/tests/18pg_escape_bytea.phpt
+++ b/ext/pgsql/tests/18pg_escape_bytea.phpt
@@ -8,10 +8,11 @@ PostgreSQL pg_escape_bytea() functions
include('config.inc');
+$db = pg_connect($conn_str);
+
$image = file_get_contents(dirname(__FILE__) . '/php.gif');
$esc_image = pg_escape_bytea($image);
-$db = pg_connect($conn_str);
pg_query($db, 'INSERT INTO '.$table_name.' (num, bin) VALUES (9876, \''.$esc_image.'\');');
$result = pg_query($db, 'SELECT * FROM '.$table_name.' WHERE num = 9876');
$rows = pg_fetch_all($result);
diff --git a/ext/pgsql/tests/bug64609.phpt b/ext/pgsql/tests/bug64609.phpt
new file mode 100644
index 000000000..0df63012d
--- /dev/null
+++ b/ext/pgsql/tests/bug64609.phpt
@@ -0,0 +1,30 @@
+--TEST--
+Bug #64609 (pg_convert enum type support)
+--SKIPIF--
+<?php
+include("skipif.inc");
+skip_server_version('8.3', '<');
+?>
+--FILE--
+<?php
+error_reporting(E_ALL);
+
+include 'config.inc';
+
+$db = pg_connect($conn_str);
+pg_query("BEGIN");
+pg_query("CREATE TYPE t_enum AS ENUM ('ok', 'ko')");
+pg_query("CREATE TABLE test_enum (a t_enum)");
+
+$fields = array('a' => 'ok');
+$converted = pg_convert($db, 'test_enum', $fields);
+
+pg_query("ROLLBACK");
+
+var_dump($converted);
+?>
+--EXPECT--
+array(1) {
+ ["a"]=>
+ string(4) "'ok'"
+}
diff --git a/ext/standard/quot_print.c b/ext/standard/quot_print.c
index 28dcc63f1..0df127362 100644
--- a/ext/standard/quot_print.c
+++ b/ext/standard/quot_print.c
@@ -151,7 +151,7 @@ PHPAPI unsigned char *php_quot_print_encode(const unsigned char *str, size_t len
unsigned char c, *ret, *d;
char *hex = "0123456789ABCDEF";
- ret = safe_emalloc(1, 3 * length + 3 * (((3 * length)/PHP_QPRINT_MAXL) + 1), 0);
+ ret = safe_emalloc(3, length + (((3 * length)/(PHP_QPRINT_MAXL-9)) + 1), 1);
d = ret;
while (length--) {
@@ -286,4 +286,4 @@ PHP_FUNCTION(quoted_printable_encode)
* End:
* vim600: sw=4 ts=4 fdm=marker
* vim<600: sw=4 ts=4
- */ \ No newline at end of file
+ */
diff --git a/ext/standard/tests/strings/bug64879.phpt b/ext/standard/tests/strings/bug64879.phpt
new file mode 100644
index 000000000..1df90c6d8
--- /dev/null
+++ b/ext/standard/tests/strings/bug64879.phpt
@@ -0,0 +1,12 @@
+--TEST--
+Bug #64879: quoted_printable_encode() wrong size calculation (CVE-2013-2110)
+--FILE--
+<?php
+
+quoted_printable_encode(str_repeat("\xf4", 1000));
+quoted_printable_encode(str_repeat("\xf4", 100000));
+
+echo "Done\n";
+?>
+--EXPECTF--
+Done
diff --git a/main/php_version.h b/main/php_version.h
index 459c69924..629634e29 100644
--- a/main/php_version.h
+++ b/main/php_version.h
@@ -3,6 +3,6 @@
#define PHP_MAJOR_VERSION 5
#define PHP_MINOR_VERSION 5
#define PHP_RELEASE_VERSION 0
-#define PHP_EXTRA_VERSION "RC2"
-#define PHP_VERSION "5.5.0RC2"
+#define PHP_EXTRA_VERSION "RC3"
+#define PHP_VERSION "5.5.0RC3"
#define PHP_VERSION_ID 50500
diff --git a/sapi/fpm/fpm/fpm_stdio.c b/sapi/fpm/fpm/fpm_stdio.c
index 10b867d00..d81e10150 100644
--- a/sapi/fpm/fpm/fpm_stdio.c
+++ b/sapi/fpm/fpm/fpm_stdio.c
@@ -291,7 +291,11 @@ int fpm_stdio_open_error_log(int reopen) /* {{{ */
fd = fpm_globals.error_log_fd; /* for FD_CLOSEXEC to work */
} else {
fpm_globals.error_log_fd = fd;
+#if HAVE_UNISTD_H
+ if (fpm_global_config.daemonize || !isatty(STDERR_FILENO)) {
+#else
if (fpm_global_config.daemonize) {
+#endif
zlog_set_fd(fpm_globals.error_log_fd);
}
}