diff options
46 files changed, 5446 insertions, 0 deletions
diff --git a/ext/filter/CREDITS b/ext/filter/CREDITS new file mode 100644 index 0000000000..fade411d07 --- /dev/null +++ b/ext/filter/CREDITS @@ -0,0 +1,2 @@ +Input Filter +Rasmus Lerdorf, Derick Rethans diff --git a/ext/filter/callback_filter.c b/ext/filter/callback_filter.c new file mode 100644 index 0000000000..5ce17fe23f --- /dev/null +++ b/ext/filter/callback_filter.c @@ -0,0 +1,68 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2006 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. | + +----------------------------------------------------------------------+ + | Authors: Derick Rethans <derick@php.net> | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#include "php_filter.h" + +void php_filter_callback(PHP_INPUT_FILTER_PARAM_DECL) +{ + char *name = NULL; + zval *retval_ptr; + zval ***args; + int status; + + if (!option_array || !zend_is_callable(option_array, IS_CALLABLE_CHECK_NO_ACCESS, &name)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "First argument is expected to be a valid callback"); + if (name) { + efree(name); + } + zval_dtor(value); + Z_TYPE_P(value) = IS_NULL; + return; + } + efree(name); + + args = safe_emalloc(sizeof(zval **), 1, 0); + args[0] = &value; + + status = call_user_function_ex(EG(function_table), NULL, option_array, &retval_ptr, 1, args, 0, NULL TSRMLS_CC); + + if (status == SUCCESS && retval_ptr != NULL) { + zval_dtor(value); + *value = *retval_ptr; + zval_copy_ctor(value); + } else { + zval_dtor(value); + Z_TYPE_P(value) = IS_NULL; + } + + if (retval_ptr) { + zval_ptr_dtor(&retval_ptr); + } + efree(args); +} + +/* + * 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/filter/config.m4 b/ext/filter/config.m4 new file mode 100644 index 0000000000..0db0375e26 --- /dev/null +++ b/ext/filter/config.m4 @@ -0,0 +1,95 @@ +dnl $Id$ +dnl config.m4 for input filtering extension + +PHP_ARG_ENABLE(filter, whether to enable input filter support, +[ --disable-filter Disable input filter support], yes) + +PHP_ARG_WITH(pcre-dir, pcre install prefix, +[ --with-pcre-dir FILTER: pcre install prefix], no, no) + +if test "$PHP_FILTER" != "no"; then + + dnl Check if configure is the PHP core configure + if test -n "$PHP_VERSION"; then + dnl This extension can not be build as shared when in PHP core + ext_shared=no + else + dnl This is PECL build, check if bundled PCRE library is used + old_CPPFLAGS=$CPPFLAGS + CPPFLAGS=$INCLUDES + AC_EGREP_CPP(yes,[ +#include <main/php_config.h> +#if defined(HAVE_BUNDLED_PCRE) && !defined(COMPILE_DL_PCRE) +yes +#endif + ],[ + PHP_PCRE_REGEX=yes + ],[ + AC_EGREP_CPP(yes,[ +#include <main/php_config.h> +#if defined(HAVE_PCRE) && !defined(COMPILE_DL_PCRE) +yes +#endif + ],[ + PHP_PCRE_REGEX=pecl + ],[ + PHP_PCRE_REGEX=no + ]) + ]) + CPPFLAGS=$old_CPPFLAGS + fi + + if test "$PHP_PCRE_REGEX" != "yes"; then + dnl + dnl If PCRE extension is enabled we can use the already found paths, + dnl otherwise we have to detect them here: + dnl + if test "$PHP_PCRE_REGEX" = "no" || test "$PHP_PCRE_REGEX" = "pecl"; then + dnl Set the PCRE search dirs correctly + case "$PHP_PCRE_DIR" in + yes|no) + PCRE_SEARCH_DIR="/usr/local /usr" + ;; + *) + PCRE_SEARCH_DIR="$PHP_PCRE_DIR" + ;; + esac + + for i in $PCRE_SEARCH_DIR; do + if test -f $i/include/pcre/pcre.h; then + PCRE_INCDIR=$i/include/pcre + break + elif test -f $i/include/pcre.h; then + PCRE_INCDIR=$i/include + break + elif test -f $i/pcre.h; then + PCRE_INCDIR=$i + break + fi + done + + if test -z "$PCRE_INCDIR"; then + AC_MSG_ERROR([Could not find pcre.h anywhere under $PCRE_SEARCH_DIR]) + fi + + for j in $PCRE_SEARCH_DIR/$PHP_LIBDIR $PCRE_SEARCH_DIR; do + if test -f $j/libpcre.a || test -f $j/libpcre.$SHLIB_SUFFIX_NAME; then + PCRE_LIBDIR=$j + break + fi + done + + if test -z "$PCRE_LIBDIR" ; then + AC_MSG_ERROR([Could not find libpcre.(a|$SHLIB_SUFFIX_NAME) anywhere under $PCRE_SEARCH_DIR]) + fi + fi + + PHP_ADD_LIBRARY_WITH_PATH(pcre, $PCRE_LIBDIR, FILTER_SHARED_LIBADD) + PHP_ADD_INCLUDE($PCRE_INCDIR) + fi + + PHP_NEW_EXTENSION(filter, filter.c sanitizing_filters.c logical_filters.c callback_filter.c, $ext_shared) + PHP_SUBST(FILTER_SHARED_LIBADD) + + PHP_INSTALL_HEADERS([$ext_srcdir/php_filter.h]) +fi diff --git a/ext/filter/config.w32 b/ext/filter/config.w32 new file mode 100644 index 0000000000..083555a4c7 --- /dev/null +++ b/ext/filter/config.w32 @@ -0,0 +1,8 @@ +// $Id$ +// vim:ft=javascript + +ARG_ENABLE("filter", "Filter Support", "yes"); + +if (PHP_FILTER == "yes") { + EXTENSION("filter", "filter.c sanitizing_filters.c logical_filters.c callback_filter.c"); +} diff --git a/ext/filter/sanitizing_filters.c b/ext/filter/sanitizing_filters.c new file mode 100644 index 0000000000..50d17eb65c --- /dev/null +++ b/ext/filter/sanitizing_filters.c @@ -0,0 +1,340 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2006 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. | + +----------------------------------------------------------------------+ + | Authors: Derick Rethans <derick@php.net> | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#include "php_filter.h" +#include "filter_private.h" +#include "ext/standard/php_smart_str.h" + +/* {{{ STRUCTS */ +typedef unsigned long filter_map[256]; +/* }}} */ + +/* {{{ HELPER FUNCTIONS */ +static void php_filter_encode_html(zval *value, char* chars, int encode_nul) +{ + register int x, y; + smart_str str = {0}; + int len = Z_STRLEN_P(value); + char *s = Z_STRVAL_P(value); + + if (Z_STRLEN_P(value) == 0) { + return; + } + + for (x = 0, y = 0; len--; x++, y++) { + if (strchr(chars, s[x]) || (encode_nul && s[x] == 0)) { + smart_str_appendl(&str, "&#", 2); + smart_str_append_long(&str, s[x]); + smart_str_appendc(&str, ';'); + } else { + smart_str_appendc(&str, s[x]); + } + } + smart_str_0(&str); + efree(Z_STRVAL_P(value)); + Z_STRVAL_P(value) = str.c; + Z_STRLEN_P(value) = str.len; +} + +static void php_filter_encode_html_high_low(zval *value, long flags) +{ + register int x, y; + smart_str str = {0}; + int len = Z_STRLEN_P(value); + unsigned char *s = Z_STRVAL_P(value); + + if (Z_STRLEN_P(value) == 0) { + return; + } + + for (x = 0, y = 0; len--; x++, y++) { + if (((flags & FILTER_FLAG_ENCODE_LOW) && (s[x] < 32)) || ((flags & FILTER_FLAG_ENCODE_HIGH) && (s[x] > 127))) { + smart_str_appendl(&str, "&#", 2); + smart_str_append_long(&str, s[x]); + smart_str_appendc(&str, ';'); + } else { + smart_str_appendc(&str, s[x]); + } + } + smart_str_0(&str); + efree(Z_STRVAL_P(value)); + Z_STRVAL_P(value) = str.c; + Z_STRLEN_P(value) = str.len; +} + +static unsigned char hexchars[] = "0123456789ABCDEF"; + +#define LOWALPHA "abcdefghijklmnopqrstuvwxyz" +#define HIALPHA "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +#define DIGIT "0123456789" + +#define DEFAULT_URL_ENCODE LOWALPHA HIALPHA DIGIT "-._" + +static void php_filter_encode_url(zval *value, char* chars, int high, int low, int encode_nul) +{ + register int x, y; + unsigned char *str; + int len = Z_STRLEN_P(value); + char *s = Z_STRVAL_P(value); + + str = (unsigned char *) safe_emalloc(3, len, 1); + for (x = 0, y = 0; len--; x++, y++) { + str[y] = (unsigned char) s[x]; + + if ((strlen(chars) && !strchr(chars, str[y])) || (high && str[y] > 127) || (low && str[y] < 32) || (encode_nul && str[y] == 0)) { + str[y++] = '%'; + str[y++] = hexchars[(unsigned char) s[x] >> 4]; + str[y] = hexchars[(unsigned char) s[x] & 15]; + } + } + str[y] = '\0'; + efree(Z_STRVAL_P(value)); + Z_STRVAL_P(value) = str; + Z_STRLEN_P(value) = y; +} + +static void php_filter_strip(zval *value, long flags) +{ + unsigned char *buf, *str; + int i, c; + + /* Optimization for if no strip flags are set */ + if (! ((flags & FILTER_FLAG_STRIP_LOW) || (flags & FILTER_FLAG_STRIP_HIGH)) ) { + return; + } + + str = Z_STRVAL_P(value); + buf = safe_emalloc(1, Z_STRLEN_P(value) + 1, 1); + c = 0; + for (i = 0; i < Z_STRLEN_P(value); i++) { + if ((str[i] > 127) && (flags & FILTER_FLAG_STRIP_HIGH)) { + } else if ((str[i] < 32) && (flags & FILTER_FLAG_STRIP_LOW)) { + } else { + buf[c] = str[i]; + ++c; + } + } + /* update zval string data */ + buf[c] = '\0'; + efree(Z_STRVAL_P(value)); + Z_STRVAL_P(value) = buf; + Z_STRLEN_P(value) = c; +} +/* }}} */ + +/* {{{ FILTER MAP HELPERS */ +static void filter_map_init(filter_map *map) +{ + memset(map, 0, sizeof(filter_map)); +} + +static void filter_map_update(filter_map *map, int flag, unsigned char *allowed_list) +{ + int l, i; + + l = strlen(allowed_list); + for (i = 0; i < l; ++i) { + (*map)[allowed_list[i]] = flag; + } +} + +static void filter_map_apply(zval *value, filter_map *map) +{ + unsigned char *buf, *str; + int i, c; + + str = Z_STRVAL_P(value); + buf = safe_emalloc(1, Z_STRLEN_P(value) + 1, 1); + c = 0; + for (i = 0; i < Z_STRLEN_P(value); i++) { + if ((*map)[str[i]]) { + buf[c] = str[i]; + ++c; + } + } + /* update zval string data */ + buf[c] = '\0'; + efree(Z_STRVAL_P(value)); + Z_STRVAL_P(value) = buf; + Z_STRLEN_P(value) = c; +} +/* }}} */ + + +/* {{{ php_filter_string */ +void php_filter_string(PHP_INPUT_FILTER_PARAM_DECL) +{ + size_t new_len; + + /* strip tags, implicitly also removes \0 chars */ + new_len = php_strip_tags(Z_STRVAL_P(value), Z_STRLEN_P(value), NULL, NULL, 0); + Z_STRLEN_P(value) = new_len; + + if (new_len == 0) { + zval_dtor(value); + ZVAL_EMPTY_STRING(value); + return; + } + + if (! (flags & FILTER_FLAG_NO_ENCODE_QUOTES)) { + /* encode ' and " to numerical entity */ + php_filter_encode_html(value, "'\"", 0); + } + /* strip high/strip low ( see flags )*/ + php_filter_strip(value, flags); + + /* encode low/encode high flags */ + php_filter_encode_html_high_low(value, flags); + + /* also all the flags - & encode as %xx */ + if (flags & FILTER_FLAG_ENCODE_AMP) { + php_filter_encode_html(value, "&", 0); + } +} +/* }}} */ + +/* {{{ php_filter_encoded */ +void php_filter_encoded(PHP_INPUT_FILTER_PARAM_DECL) +{ + /* apply strip_high and strip_low filters */ + php_filter_strip(value, flags); + /* urlencode */ + php_filter_encode_url(value, DEFAULT_URL_ENCODE, flags & FILTER_FLAG_ENCODE_HIGH, flags & FILTER_FLAG_ENCODE_LOW, 1); +} +/* }}} */ + +/* {{{ php_filter_special_chars */ +void php_filter_special_chars(PHP_INPUT_FILTER_PARAM_DECL) +{ + /* encodes ' " < > & \0 to numerical entities */ + php_filter_encode_html(value, "'\"<>&", 1); + /* if strip low is not set, then we encode them as &#xx; */ + php_filter_strip(value, flags); + php_filter_encode_html_high_low(value, FILTER_FLAG_ENCODE_LOW | flags); +} +/* }}} */ + +/* {{{ php_filter_unsafe_raw */ +void php_filter_unsafe_raw(PHP_INPUT_FILTER_PARAM_DECL) +{ + /* Only if no flags are set (optimization) */ + if (flags != 0 && Z_STRLEN_P(value) > 0) { + php_filter_strip(value, flags); + if (flags & FILTER_FLAG_ENCODE_AMP) { + php_filter_encode_html(value, "&", 0); + } + php_filter_encode_html_high_low(value, flags); + } +} +/* }}} */ + +/* {{{ php_filter_email */ +#define SAFE "$-_.+" +#define EXTRA "!*'()," +#define NATIONAL "{}|\\^~[]`" +#define PUNCTUATION "<>#%\"" +#define RESERVED ";/?:@&=" + +void php_filter_email(PHP_INPUT_FILTER_PARAM_DECL) +{ + /* Check section 6 of rfc 822 http://www.faqs.org/rfcs/rfc822.html */ + unsigned char *allowed_list = LOWALPHA HIALPHA DIGIT "!#$%&'*+-/=?^_`{|}~@.[]"; + filter_map map; + + filter_map_init(&map); + filter_map_update(&map, 1, allowed_list); + filter_map_apply(value, &map); +} +/* }}} */ + +/* {{{ php_filter_url */ +void php_filter_url(PHP_INPUT_FILTER_PARAM_DECL) +{ + /* Strip all chars not part of section 5 of + * http://www.faqs.org/rfcs/rfc1738.html */ + unsigned char *allowed_list = LOWALPHA HIALPHA DIGIT SAFE EXTRA NATIONAL PUNCTUATION RESERVED; + filter_map map; + + filter_map_init(&map); + filter_map_update(&map, 1, allowed_list); + filter_map_apply(value, &map); +} +/* }}} */ + +/* {{{ php_filter_number_int */ +void php_filter_number_int(PHP_INPUT_FILTER_PARAM_DECL) +{ + /* strip everything [^0-9+-] */ + unsigned char *allowed_list = "+-" DIGIT; + filter_map map; + + filter_map_init(&map); + filter_map_update(&map, 1, allowed_list); + filter_map_apply(value, &map); +} +/* }}} */ + +/* {{{ php_filter_number_float */ +void php_filter_number_float(PHP_INPUT_FILTER_PARAM_DECL) +{ + /* strip everything [^0-9+-] */ + unsigned char *allowed_list = "+-" DIGIT; + filter_map map; + + filter_map_init(&map); + filter_map_update(&map, 1, allowed_list); + + /* depending on flags, strip '.', 'e', ",", "'" */ + if (flags & FILTER_FLAG_ALLOW_FRACTION) { + filter_map_update(&map, 2, "."); + } + if (flags & FILTER_FLAG_ALLOW_THOUSAND) { + filter_map_update(&map, 3, ","); + } + if (flags & FILTER_FLAG_ALLOW_SCIENTIFIC) { + filter_map_update(&map, 4, "eE"); + } + filter_map_apply(value, &map); +} +/* }}} */ + +/* {{{ php_filter_magic_quotes */ +void php_filter_magic_quotes(PHP_INPUT_FILTER_PARAM_DECL) +{ + char *buf; + int len; + + /* just call php_addslashes quotes */ + buf = php_addslashes(Z_STRVAL_P(value), Z_STRLEN_P(value), &len, 0 TSRMLS_CC); + + efree(Z_STRVAL_P(value)); + Z_STRVAL_P(value) = buf; + Z_STRLEN_P(value) = len; +} +/* }}} */ + +/* + * 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/filter/tests/001.phpt b/ext/filter/tests/001.phpt new file mode 100644 index 0000000000..2755a57363 --- /dev/null +++ b/ext/filter/tests/001.phpt @@ -0,0 +1,8 @@ +--TEST-- +Simple GET test +--GET-- +a=1 +--FILE-- +<?php echo $_GET['a']; ?> +--EXPECT-- +1 diff --git a/ext/filter/tests/002.phpt b/ext/filter/tests/002.phpt new file mode 100644 index 0000000000..7136b251a6 --- /dev/null +++ b/ext/filter/tests/002.phpt @@ -0,0 +1,11 @@ +--TEST-- +GET test with 2 values and an empty one +--GET-- +a=1&b=&c=3 +--FILE-- +<?php echo $_GET['a']; +echo $_GET['b']; +echo $_GET['c']; +?> +--EXPECT-- +13 diff --git a/ext/filter/tests/003.phpt b/ext/filter/tests/003.phpt new file mode 100644 index 0000000000..43e6cd9b03 --- /dev/null +++ b/ext/filter/tests/003.phpt @@ -0,0 +1,22 @@ +--TEST-- +GET/POST/REQUEST Test +--POST-- +d=4&e=5 +--GET-- +a=1&b=&c=3 +--FILE-- +<?php echo $_GET['a']; +echo $_GET['b']; +echo $_GET['c']; +echo $_POST['d']; +echo $_POST['e']; +echo "\n"; +echo $_REQUEST['a']; +echo $_REQUEST['b']; +echo $_REQUEST['c']; +echo $_REQUEST['d']; +echo $_REQUEST['e']; +?> +--EXPECT-- +1345 +1345 diff --git a/ext/filter/tests/004.phpt b/ext/filter/tests/004.phpt new file mode 100644 index 0000000000..05ea952145 --- /dev/null +++ b/ext/filter/tests/004.phpt @@ -0,0 +1,24 @@ +--TEST-- +GET/POST/REQUEST Test with filtered data +--INI-- +filter.default=special_chars +--POST-- +d="quotes"&e=\slash +--GET-- +a=O'Henry&b=&c=<b>Bold</b> +--FILE-- +<?php echo $_GET['a']; +echo $_GET['b']; +echo $_GET['c']; +echo $_POST['d']; +echo $_POST['e']; +echo "\n"; +echo $_REQUEST['a']; +echo $_REQUEST['b']; +echo $_REQUEST['c']; +echo $_REQUEST['d']; +echo $_REQUEST['e']; +?> +--EXPECT-- +O'HenryBold"quotes"\slash +O'HenryBold"quotes"\slash diff --git a/ext/filter/tests/005.phpt b/ext/filter/tests/005.phpt new file mode 100644 index 0000000000..f44379153e --- /dev/null +++ b/ext/filter/tests/005.phpt @@ -0,0 +1,21 @@ +--TEST-- +GET/REQUEST Test with fifa example data +--INI-- +filter.default=stripped +--GET-- +id=f03_photos&pgurl=http%3A//fifaworldcup.yahoo.com/03/en/photozone/index.html +--FILE-- +<?php +echo $_GET['id']; +echo "\n"; +echo $_GET['pgurl']; +echo "\n"; +echo $_REQUEST['id']; +echo "\n"; +echo $_REQUEST['pgurl']; +?> +--EXPECT-- +f03_photos +http://fifaworldcup.yahoo.com/03/en/photozone/index.html +f03_photos +http://fifaworldcup.yahoo.com/03/en/photozone/index.html diff --git a/ext/filter/tests/006.phpt b/ext/filter/tests/006.phpt new file mode 100644 index 0000000000..189579acf1 --- /dev/null +++ b/ext/filter/tests/006.phpt @@ -0,0 +1,10 @@ +--TEST-- +filter() test +--POST-- +foo=<b>abc</b> +--FILE-- +<?php +echo input_get(INPUT_POST, 'foo', FILTER_SANITIZE_STRIPPED); +?> +--EXPECT-- +abc diff --git a/ext/filter/tests/007.phpt b/ext/filter/tests/007.phpt new file mode 100644 index 0000000000..ffc727801d --- /dev/null +++ b/ext/filter/tests/007.phpt @@ -0,0 +1,68 @@ +--TEST-- +input_has_variable() +--GET-- +a=qwe&abc=<a>href</a> +--POST-- +b=qwe&bbc=<a>href</a> +--FILE-- +<?php + +var_dump(input_has_variable(INPUT_GET, "a")); +var_dump(input_has_variable(INPUT_GET, "abc")); +var_dump(input_has_variable(INPUT_GET, "nonex")); +var_dump(input_has_variable(INPUT_GET, " ")); +var_dump(input_has_variable(INPUT_GET, "")); +var_dump(input_has_variable(INPUT_GET, array())); + +var_dump(input_has_variable(INPUT_POST, "b")); +var_dump(input_has_variable(INPUT_POST, "bbc")); +var_dump(input_has_variable(INPUT_POST, "nonex")); +var_dump(input_has_variable(INPUT_POST, " ")); +var_dump(input_has_variable(INPUT_POST, "")); +var_dump(input_has_variable(INPUT_POST, array())); + +var_dump(input_has_variable(-1, "")); +var_dump(input_has_variable("", "")); +var_dump(input_has_variable(array(), array())); +var_dump(input_has_variable(array(), "")); +var_dump(input_has_variable("", array())); + +echo "Done\n"; +?> +--EXPECTF-- +bool(true) +bool(true) +bool(false) +bool(false) +bool(false) +PHP Warning: input_has_variable() expects parameter 2 to be string, array given in %s on line %d + +Warning: input_has_variable() expects parameter 2 to be string, array given in %s on line %d +NULL +bool(true) +bool(true) +bool(false) +bool(false) +bool(false) +PHP Warning: input_has_variable() expects parameter 2 to be string, array given in %s on line %d + +Warning: input_has_variable() expects parameter 2 to be string, array given in %s on line %d +NULL +bool(false) +PHP Warning: input_has_variable() expects parameter 1 to be long, string given in %s on line %d + +Warning: input_has_variable() expects parameter 1 to be long, string given in %s on line %d +NULL +PHP Warning: input_has_variable() expects parameter 1 to be long, array given in %s on line %d + +Warning: input_has_variable() expects parameter 1 to be long, array given in %s on line %d +NULL +PHP Warning: input_has_variable() expects parameter 1 to be long, array given in %s on line %d + +Warning: input_has_variable() expects parameter 1 to be long, array given in %s on line %d +NULL +PHP Warning: input_has_variable() expects parameter 1 to be long, string given in %s on line %d + +Warning: input_has_variable() expects parameter 1 to be long, string given in %s on line %d +NULL +Done diff --git a/ext/filter/tests/008.phpt b/ext/filter/tests/008.phpt new file mode 100644 index 0000000000..eb6963c099 --- /dev/null +++ b/ext/filter/tests/008.phpt @@ -0,0 +1,88 @@ +--TEST-- +input_filters_list() +--FILE-- +<?php + +var_dump(input_filters_list()); +var_dump(input_filters_list(array())); + +echo "Done\n"; +?> +--EXPECTF-- +array(18) { + [0]=> + string(3) "int" + [1]=> + string(7) "boolean" + [2]=> + string(5) "float" + [3]=> + string(15) "validate_regexp" + [4]=> + string(12) "validate_url" + [5]=> + string(14) "validate_email" + [6]=> + string(11) "validate_ip" + [7]=> + string(6) "string" + [8]=> + string(8) "stripped" + [9]=> + string(7) "encoded" + [10]=> + string(13) "special_chars" + [11]=> + string(10) "unsafe_raw" + [12]=> + string(5) "email" + [13]=> + string(3) "url" + [14]=> + string(10) "number_int" + [15]=> + string(12) "number_float" + [16]=> + string(12) "magic_quotes" + [17]=> + string(8) "callback" +} +array(18) { + [0]=> + string(3) "int" + [1]=> + string(7) "boolean" + [2]=> + string(5) "float" + [3]=> + string(15) "validate_regexp" + [4]=> + string(12) "validate_url" + [5]=> + string(14) "validate_email" + [6]=> + string(11) "validate_ip" + [7]=> + string(6) "string" + [8]=> + string(8) "stripped" + [9]=> + string(7) "encoded" + [10]=> + string(13) "special_chars" + [11]=> + string(10) "unsafe_raw" + [12]=> + string(5) "email" + [13]=> + string(3) "url" + [14]=> + string(10) "number_int" + [15]=> + string(12) "number_float" + [16]=> + string(12) "magic_quotes" + [17]=> + string(8) "callback" +} +Done diff --git a/ext/filter/tests/009.phpt b/ext/filter/tests/009.phpt new file mode 100644 index 0000000000..c33fe8ae36 --- /dev/null +++ b/ext/filter/tests/009.phpt @@ -0,0 +1,30 @@ +--TEST-- +input_name_to_filter() +--FILE-- +<?php + +var_dump(input_name_to_filter("stripped")); +var_dump(input_name_to_filter("string")); +var_dump(input_name_to_filter("url")); +var_dump(input_name_to_filter("int")); +var_dump(input_name_to_filter("none")); +var_dump(input_name_to_filter(array())); +var_dump(input_name_to_filter(-1)); +var_dump(input_name_to_filter(0,0,0)); + +echo "Done\n"; +?> +--EXPECTF-- +int(513) +int(513) +int(518) +int(257) +NULL + +Warning: input_name_to_filter() expects parameter 1 to be string, array given in %s on line %d +NULL +NULL + +Warning: input_name_to_filter() expects exactly 1 parameter, 3 given in %s on line %d +NULL +Done diff --git a/ext/filter/tests/011.phpt b/ext/filter/tests/011.phpt new file mode 100644 index 0000000000..0d3fa42745 --- /dev/null +++ b/ext/filter/tests/011.phpt @@ -0,0 +1,49 @@ +--TEST-- +input_get() +--GET-- +a=<b>test</b>&b=http://example.com +--POST-- +c=<p>string</p>&d=12345.7 +--FILE-- +<?php + +var_dump(input_get(INPUT_GET, "a", FILTER_SANITIZE_STRIPPED)); +var_dump(input_get(INPUT_GET, "b", FILTER_SANITIZE_URL)); +var_dump(input_get(INPUT_GET, "a", FILTER_SANITIZE_SPECIAL_CHARS, array(1,2,3,4,5))); +var_dump(input_get(INPUT_GET, "b", FILTER_VALIDATE_FLOAT, new stdClass)); +var_dump(input_get(INPUT_POST, "c", FILTER_SANITIZE_STRIPPED, array(5,6,7,8))); +var_dump(input_get(INPUT_POST, "d", FILTER_VALIDATE_FLOAT)); +var_dump(input_get(INPUT_POST, "c", FILTER_SANITIZE_SPECIAL_CHARS)); +var_dump(input_get(INPUT_POST, "d", FILTER_VALIDATE_INT)); + +var_dump(input_get(new stdClass, "d")); + +var_dump(input_get(INPUT_POST, "c", "", "")); +var_dump(input_get("", "", "", "", "")); +var_dump(input_get(0, 0, 0, 0, 0)); + +echo "Done\n"; +?> +--EXPECTF-- +string(4) "test" +string(18) "http://example.com" +string(27) "<b>test</b>" +NULL +string(6) "string" +float(12345.7) +string(29) "<p>string</p>" +NULL +PHP Warning: input_get() expects parameter 1 to be long, object given in %s on line %d + +Warning: input_get() expects parameter 1 to be long, object given in %s on line %d +NULL +PHP Warning: input_get() expects parameter 3 to be long, string given in %s on line %d + +Warning: input_get() expects parameter 3 to be long, string given in %s on line %d +NULL +PHP Warning: input_get() expects parameter 1 to be long, string given in %s on line %d + +Warning: input_get() expects parameter 1 to be long, string given in %s on line %d +NULL +bool(false) +Done diff --git a/ext/filter/tests/012.phpt b/ext/filter/tests/012.phpt new file mode 100644 index 0000000000..77c1880137 --- /dev/null +++ b/ext/filter/tests/012.phpt @@ -0,0 +1,16 @@ +--TEST-- +input_get() +--FILE-- +<?php + +var_dump(input_get(INPUT_GET, "test")); +var_dump(input_get(INPUT_POST, "test")); +var_dump(input_get(INPUT_COOKIE, "")); + +echo "Done\n"; +?> +--EXPECT-- +bool(false) +bool(false) +bool(false) +Done diff --git a/ext/filter/tests/014.phpt b/ext/filter/tests/014.phpt new file mode 100644 index 0000000000..f31fe6e9f4 --- /dev/null +++ b/ext/filter/tests/014.phpt @@ -0,0 +1,41 @@ +--TEST-- +filter_data() and FILTER_VALIDATE_BOOLEAN +--FILE-- +<?php + +var_dump(filter_data("no", FILTER_VALIDATE_BOOLEAN)); +var_dump(filter_data(new stdClass, FILTER_VALIDATE_BOOLEAN)); +var_dump(filter_data("yes", FILTER_VALIDATE_BOOLEAN)); +var_dump(filter_data("true", FILTER_VALIDATE_BOOLEAN)); +var_dump(filter_data("false", FILTER_VALIDATE_BOOLEAN)); +var_dump(filter_data("off", FILTER_VALIDATE_BOOLEAN)); +var_dump(filter_data("on", FILTER_VALIDATE_BOOLEAN)); +var_dump(filter_data("0", FILTER_VALIDATE_BOOLEAN)); +var_dump(filter_data("1", FILTER_VALIDATE_BOOLEAN)); +var_dump(filter_data("NONE", FILTER_VALIDATE_BOOLEAN)); +var_dump(filter_data("", FILTER_VALIDATE_BOOLEAN)); +var_dump(filter_data(-1, FILTER_VALIDATE_BOOLEAN)); +var_dump(filter_data("000000", FILTER_VALIDATE_BOOLEAN)); +var_dump(filter_data("111111", FILTER_VALIDATE_BOOLEAN)); + + +echo "Done\n"; +?> +--EXPECTF-- +bool(false) + +Notice: Object of class stdClass to string conversion in %s on line %d +NULL +bool(true) +bool(true) +bool(false) +bool(false) +bool(true) +bool(false) +bool(true) +NULL +bool(false) +NULL +NULL +NULL +Done diff --git a/ext/filter/tests/020.phpt b/ext/filter/tests/020.phpt new file mode 100644 index 0000000000..914c199afb --- /dev/null +++ b/ext/filter/tests/020.phpt @@ -0,0 +1,18 @@ +--TEST-- +filter_data() and FILTER_SANITIZE_MAGIC_QUOTES +--FILE-- +<?php + +var_dump(filter_data("test'asd'asd'' asd\'\"asdfasdf", FILTER_SANITIZE_MAGIC_QUOTES)); +var_dump(filter_data("'", FILTER_SANITIZE_MAGIC_QUOTES)); +var_dump(filter_data("", FILTER_SANITIZE_MAGIC_QUOTES)); +var_dump(filter_data(-1, FILTER_SANITIZE_MAGIC_QUOTES)); + +echo "Done\n"; +?> +--EXPECT-- +string(36) "test\'asd\'asd\'\' asd\\\'\"asdfasdf" +string(2) "\'" +string(0) "" +string(2) "-1" +Done diff --git a/ext/filter/tests/021.phpt b/ext/filter/tests/021.phpt new file mode 100644 index 0000000000..697fdd69d4 --- /dev/null +++ b/ext/filter/tests/021.phpt @@ -0,0 +1,44 @@ +--TEST-- +filter_data() and FILTER_SANITIZE_NUMBER_* +--FILE-- +<?php + +var_dump(filter_data("qwertyu123456dfghj", FILTER_SANITIZE_NUMBER_INT)); +var_dump(filter_data("asd123123.asd123.23", FILTER_SANITIZE_NUMBER_INT)); +var_dump(filter_data("123,23", FILTER_SANITIZE_NUMBER_INT)); +var_dump(filter_data("", FILTER_SANITIZE_NUMBER_INT)); +var_dump(filter_data("0", FILTER_SANITIZE_NUMBER_INT)); +var_dump(filter_data("asd123.2asd", FILTER_SANITIZE_NUMBER_INT)); +var_dump(filter_data("qwertyuiop", FILTER_SANITIZE_NUMBER_INT)); +var_dump(filter_data("123.4", FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION)); +var_dump(filter_data("123,4", FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION)); +var_dump(filter_data("123.4", FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_THOUSAND)); +var_dump(filter_data("123,4", FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_THOUSAND)); +var_dump(filter_data("123.4e", FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_SCIENTIFIC)); +var_dump(filter_data("123,4E", FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_SCIENTIFIC)); +var_dump(filter_data("qwe123,4qwe", FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION)); +var_dump(filter_data("werty65456.34", FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION)); +var_dump(filter_data("234.56fsfd", FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION)); +var_dump(filter_data("", FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION)); + +echo "Done\n"; +?> +--EXPECT-- +string(6) "123456" +string(11) "12312312323" +string(5) "12323" +string(0) "" +string(1) "0" +string(4) "1232" +string(0) "" +string(5) "123.4" +string(4) "1234" +string(4) "1234" +string(5) "123,4" +string(5) "1234e" +string(5) "1234E" +string(4) "1234" +string(8) "65456.34" +string(6) "234.56" +string(0) "" +Done diff --git a/ext/filter/tests/022.phpt b/ext/filter/tests/022.phpt new file mode 100644 index 0000000000..28ad64e723 --- /dev/null +++ b/ext/filter/tests/022.phpt @@ -0,0 +1,20 @@ +--TEST-- +filter_data() and FILTER_SANITIZE_EMAIL +--FILE-- +<?php + +var_dump(filter_data("a@b.c", FILTER_SANITIZE_EMAIL)); +var_dump(filter_data("a[!@#$%^&*()@a@#$%^&*(.com@#$%^&*(", FILTER_SANITIZE_EMAIL)); +var_dump(filter_data("white space here \ \ \" som more", FILTER_SANITIZE_EMAIL)); +var_dump(filter_data("", FILTER_SANITIZE_EMAIL)); +var_dump(filter_data("123456789000000", FILTER_SANITIZE_EMAIL)); + +echo "Done\n"; +?> +--EXPECTF-- +string(5) "a@b.c" +string(30) "a[!@#$%^&*@a@#$%^&*.com@#$%^&*" +string(21) "whitespaceheresommore" +string(0) "" +string(15) "123456789000000" +Done diff --git a/ext/filter/tests/023.phpt b/ext/filter/tests/023.phpt new file mode 100644 index 0000000000..21fdc49a9b --- /dev/null +++ b/ext/filter/tests/023.phpt @@ -0,0 +1,20 @@ +--TEST-- +filter_data() and FILTER_UNSAFE_RAW +--FILE-- +<?php + +var_dump(filter_data("}\"<p>test para</p>", FILTER_UNSAFE_RAW, FILTER_FLAG_ENCODE_AMP)); +var_dump(filter_data("a[!@#<b>$%^&*()@a@#$%^&*(.<br>com@#$%^&*(", FILTER_UNSAFE_RAW, FILTER_FLAG_ENCODE_AMP)); +var_dump(filter_data("white space here \ \ \" some more", FILTER_UNSAFE_RAW, FILTER_FLAG_ENCODE_AMP)); +var_dump(filter_data("", FILTER_UNSAFE_RAW, FILTER_FLAG_ENCODE_AMP)); +var_dump(filter_data(" 123456789000000 <qwertyuiop> ", FILTER_UNSAFE_RAW, FILTER_FLAG_ENCODE_AMP)); + +echo "Done\n"; +?> +--EXPECT-- +string(18) "}"<p>test para</p>" +string(53) "a[!@#<b>$%^&*()@a@#$%^&*(.<br>com@#$%^&*(" +string(32) "white space here \ \ " some more" +string(0) "" +string(48) " 123456789000000 <qwertyuiop> " +Done diff --git a/ext/filter/tests/024.phpt b/ext/filter/tests/024.phpt new file mode 100644 index 0000000000..d405af3f08 --- /dev/null +++ b/ext/filter/tests/024.phpt @@ -0,0 +1,18 @@ +--TEST-- +filter_data() and FILTER_SANITIZE_ENCODED +--FILE-- +<?php + +var_dump(filter_data("\"<br>blah</ph>", FILTER_SANITIZE_ENCODED)); +var_dump(filter_data("", FILTER_SANITIZE_ENCODED)); +var_dump(filter_data(" text here ", FILTER_SANITIZE_ENCODED)); +var_dump(filter_data("!@#$%^&*()QWERTYUIOP{ASDFGHJKL:\"ZXCVBNM<>?", FILTER_SANITIZE_ENCODED)); + +echo "Done\n"; +?> +--EXPECT-- +string(26) "%22%3Cbr%3Eblah%3C%2Fph%3E" +string(0) "" +string(23) "%20%20text%20here%20%20" +string(74) "%21%40%23%24%25%5E%26%2A%28%29QWERTYUIOP%7BASDFGHJKL%3A%22ZXCVBNM%3C%3E%3F" +Done diff --git a/ext/filter/tests/025.phpt b/ext/filter/tests/025.phpt new file mode 100644 index 0000000000..c770fb80f7 --- /dev/null +++ b/ext/filter/tests/025.phpt @@ -0,0 +1,24 @@ +--TEST-- +filter_data() and FILTER_SANITIZE_STRING +--FILE-- +<?php + +var_dump(filter_data("", FILTER_SANITIZE_STRING)); +var_dump(filter_data("<>", FILTER_SANITIZE_STRING)); +var_dump(filter_data("<>!@#$%^&*()'\"", FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES)); +var_dump(filter_data("<>!@#$%^&*()'\"", FILTER_SANITIZE_STRING, FILTER_FLAG_ENCODE_AMP)); +var_dump(filter_data("<>`1234567890", FILTER_SANITIZE_STRING)); +var_dump(filter_data("`123`", FILTER_SANITIZE_STRING)); +var_dump(filter_data(".", FILTER_SANITIZE_STRING)); + +echo "Done\n"; +?> +--EXPECT-- +string(0) "" +string(0) "" +string(12) "!@#$%^&*()'"" +string(32) "!@#$%^&*()&#39;&#34;" +string(11) "`1234567890" +string(5) "`123`" +string(1) "." +Done diff --git a/ext/filter/tests/026.phpt b/ext/filter/tests/026.phpt new file mode 100644 index 0000000000..b53dcb1989 --- /dev/null +++ b/ext/filter/tests/026.phpt @@ -0,0 +1,30 @@ +--TEST-- +filter_data() and FILTER_SANITIZE_STRIPPED +--FILE-- +<?php + +var_dump(filter_data("<p>Let me <font color=\"#000000\">see</font> you <br /><b>Stripped</b> down to the bone</p>", FILTER_SANITIZE_STRIPPED)); +var_dump(filter_data("!@#$%^&*()><<>+_\"'<br><p /><li />", FILTER_SANITIZE_STRIPPED)); +var_dump(filter_data("", FILTER_SANITIZE_STRIPPED)); + +var_dump(filter_data("<p>Let me <font color=\"#000000\">see</font> you <br /><b>Stripped</b> down to the bone</p>", FILTER_SANITIZE_STRIPPED, FILTER_FLAG_STRIP_LOW)); +var_dump(filter_data("!@#$%^&*()><<>+_\"'<br><p /><li />", FILTER_SANITIZE_STRIPPED, FILTER_FLAG_STRIP_LOW)); +var_dump(filter_data("", FILTER_SANITIZE_STRIPPED, FILTER_FLAG_STRIP_LOW)); + +var_dump(filter_data("<p>Let me <font color=\"#000000\">see</font> you <br /><b>Stripped</b> down to the bone</p>", FILTER_SANITIZE_STRIPPED, FILTER_FLAG_STRIP_HIGH)); +var_dump(filter_data("!@#$%^&*()><<>+_\"'<br><p /><li />", FILTER_SANITIZE_STRIPPED, FILTER_FLAG_STRIP_HIGH)); +var_dump(filter_data("", FILTER_SANITIZE_STRIPPED, FILTER_FLAG_STRIP_HIGH)); + +echo "Done\n"; +?> +--EXPECTF-- +string(40) "Let me see you Stripped down to the bone" +string(11) "!@#$%^&*()>" +string(0) "" +string(40) "Let me see you Stripped down to the bone" +string(11) "!@#$%^&*()>" +string(0) "" +string(40) "Let me see you Stripped down to the bone" +string(11) "!@#$%^&*()>" +string(0) "" +Done diff --git a/ext/filter/tests/027.phpt b/ext/filter/tests/027.phpt new file mode 100644 index 0000000000..048dc362ef --- /dev/null +++ b/ext/filter/tests/027.phpt @@ -0,0 +1,30 @@ +--TEST-- +filter_data() and FILTER_SANITIZE_ENCODED +--FILE-- +<?php + +var_dump(filter_data("?><!@#$%^&*()}{~Qwertyuilfdsasdfgmnbvcxcvbn", FILTER_SANITIZE_ENCODED)); +var_dump(filter_data("<data&sons>", FILTER_SANITIZE_ENCODED)); +var_dump(filter_data("", FILTER_SANITIZE_ENCODED)); + +var_dump(filter_data("?><!@#$%^&*()}{~Qwertyuilfdsasdfgmnbvcxcvbn", FILTER_SANITIZE_ENCODED, FILTER_FLAG_ENCODE_LOW)); +var_dump(filter_data("<data&sons>", FILTER_SANITIZE_ENCODED, FILTER_FLAG_ENCODE_LOW)); +var_dump(filter_data("", FILTER_SANITIZE_ENCODED, FILTER_FLAG_ENCODE_LOW)); + +var_dump(filter_data("?><!@#$%^&*()}{~Qwertyuilfdsasdfgmnbvcxcvbn", FILTER_SANITIZE_ENCODED, FILTER_FLAG_ENCODE_HIGH)); +var_dump(filter_data("<data&sons>", FILTER_SANITIZE_ENCODED, FILTER_FLAG_ENCODE_HIGH)); +var_dump(filter_data("", FILTER_SANITIZE_ENCODED, FILTER_FLAG_ENCODE_HIGH)); + +echo "Done\n"; +?> +--EXPECT-- +string(75) "%3F%3E%3C%21%40%23%24%25%5E%26%2A%28%29%7D%7B%7EQwertyuilfdsasdfgmnbvcxcvbn" +string(17) "%3Cdata%26sons%3E" +string(0) "" +string(75) "%3F%3E%3C%21%40%23%24%25%5E%26%2A%28%29%7D%7B%7EQwertyuilfdsasdfgmnbvcxcvbn" +string(17) "%3Cdata%26sons%3E" +string(0) "" +string(75) "%3F%3E%3C%21%40%23%24%25%5E%26%2A%28%29%7D%7B%7EQwertyuilfdsasdfgmnbvcxcvbn" +string(17) "%3Cdata%26sons%3E" +string(0) "" +Done diff --git a/ext/filter/tests/028.phpt b/ext/filter/tests/028.phpt new file mode 100644 index 0000000000..1d0d2e2071 --- /dev/null +++ b/ext/filter/tests/028.phpt @@ -0,0 +1,35 @@ +--TEST-- +filter_data() and FILTER_SANITIZE_SPECIAL_CHARS +--FILE-- +<?php + +var_dump(filter_data("?><!@#$%^&*()}{~Qwertyuilfdsasdfgmnbvcxcvbn", FILTER_SANITIZE_SPECIAL_CHARS)); +var_dump(filter_data("<data&sons>", FILTER_SANITIZE_SPECIAL_CHARS)); +var_dump(filter_data("", FILTER_SANITIZE_SPECIAL_CHARS)); + +var_dump(filter_data("?><!@#$%^&*()}{~Qwertyuilfdsasdfgmnbvcxcvbn", FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_ENCODE_LOW)); +var_dump(filter_data("<data&sons>", FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_ENCODE_LOW)); +var_dump(filter_data("", FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_ENCODE_LOW)); + +var_dump(filter_data("?><!@#$%^&*()}{~Qwertyuilfdsasdfgmnbvcxcvbn", FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_ENCODE_HIGH)); +var_dump(filter_data("<data&sons>", FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_ENCODE_HIGH)); +var_dump(filter_data("", FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_ENCODE_HIGH)); + +var_dump(filter_data("кириллица", FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_ENCODE_HIGH)); +var_dump(filter_data("кириллица", FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_ENCODE_LOW)); + +echo "Done\n"; +?> +--EXPECT-- +string(55) "?><!@#$%^&*()}{~Qwertyuilfdsasdfgmnbvcxcvbn" +string(23) "<data&sons>" +string(0) "" +string(55) "?><!@#$%^&*()}{~Qwertyuilfdsasdfgmnbvcxcvbn" +string(23) "<data&sons>" +string(0) "" +string(55) "?><!@#$%^&*()}{~Qwertyuilfdsasdfgmnbvcxcvbn" +string(23) "<data&sons>" +string(0) "" +string(108) "кириллица" +string(18) "кириллица" +Done diff --git a/ext/filter/tests/029.phpt b/ext/filter/tests/029.phpt new file mode 100644 index 0000000000..f60c42ef3c --- /dev/null +++ b/ext/filter/tests/029.phpt @@ -0,0 +1,103 @@ +--TEST-- +filter_data() and FILTER_CALLBACK +--FILE-- +<?php + +/* Simple callback function */ +function test($var) { + return strtoupper($var); +} + +var_dump(filter_data("data", FILTER_CALLBACK, "test")); +var_dump(filter_data("~!@#$%^&*()_QWERTYUIOPASDFGHJKLZXCVBNM<>>?\"}{:", FILTER_CALLBACK, "test")); +var_dump(filter_data("", FILTER_CALLBACK, "test")); +var_dump(filter_data("qwe", FILTER_CALLBACK, "no such func")); +var_dump(filter_data("qwe", FILTER_CALLBACK, "")); +var_dump(filter_data("qwe", FILTER_CALLBACK)); + +/* Simple class method callback */ +class test_class { + static function test ($var) { + return strtolower($var); + } +} + +var_dump(filter_data("dAtA", FILTER_CALLBACK, array("test_class", "test"))); +var_dump(filter_data("~!@#$%^&*()_QWERTYUIOPASDFGHJKLZXCVBNM<>>?\"}{:", FILTER_CALLBACK, array("test_class","test"))); +var_dump(filter_data("", FILTER_CALLBACK, array("test_class","test"))); + +/* empty function without return value */ +function test1($var) { +} + +var_dump(filter_data("data", FILTER_CALLBACK, "test1")); +var_dump(filter_data("~!@#$%^&*()_QWERTYUIOPASDFGHJKLZXCVBNM<>>?\"}{:", FILTER_CALLBACK, "test1")); +var_dump(filter_data("", FILTER_CALLBACK, "test1")); + +/* attempting to change data by reference */ +function test2(&$var) { + $var = 1; +} + +var_dump(filter_data("data", FILTER_CALLBACK, "test2")); +var_dump(filter_data("~!@#$%^&*()_QWERTYUIOPASDFGHJKLZXCVBNM<>>?\"}{:", FILTER_CALLBACK, "test2")); +var_dump(filter_data("", FILTER_CALLBACK, "test2")); + +/* unsetting data */ +function test3(&$var) { + unset($var); +} + +var_dump(filter_data("data", FILTER_CALLBACK, "test3")); +var_dump(filter_data("~!@#$%^&*()_QWERTYUIOPASDFGHJKLZXCVBNM<>>?\"}{:", FILTER_CALLBACK, "test3")); +var_dump(filter_data("", FILTER_CALLBACK, "test3")); + +/* unset data and return value */ +function test4(&$var) { + unset($var); + return 1; +} + +var_dump(filter_data("data", FILTER_CALLBACK, "test4")); + +/* thrown exception in the callback */ +function test5(&$var) { + throw new Exception("test"); +} + +try { + var_dump(filter_data("data", FILTER_CALLBACK, "test5")); +} catch (Exception $e) { + var_dump($e->getMessage()); +} + +echo "Done\n"; +?> +--EXPECTF-- +string(4) "DATA" +string(46) "~!@#$%^&*()_QWERTYUIOPASDFGHJKLZXCVBNM<>>?"}{:" +string(0) "" + +Warning: filter_data(): First argument is expected to be a valid callback in %s on line %d +NULL + +Warning: filter_data(): First argument is expected to be a valid callback in %s on line %d +NULL + +Warning: filter_data(): First argument is expected to be a valid callback in %s on line %d +NULL +string(4) "data" +string(46) "~!@#$%^&*()_qwertyuiopasdfghjklzxcvbnm<>>?"}{:" +string(0) "" +NULL +NULL +NULL +NULL +NULL +NULL +NULL +NULL +NULL +int(1) +string(4) "test" +Done diff --git a/ext/filter/tests/filter_data.phpt b/ext/filter/tests/filter_data.phpt new file mode 100644 index 0000000000..e907d02093 --- /dev/null +++ b/ext/filter/tests/filter_data.phpt @@ -0,0 +1,71 @@ +--TEST-- +Simple filter_data() tests +--FILE-- +<?php + +/* Integer */ +$data = "-123"; var_dump(filter_data($data, FILTER_VALIDATE_INT)); +$data = "0"; var_dump(filter_data($data, FILTER_VALIDATE_INT)); +$data = "123"; var_dump(filter_data($data, FILTER_VALIDATE_INT)); +$data = -123; var_dump(filter_data($data, FILTER_VALIDATE_INT)); +$data = 0; var_dump(filter_data($data, FILTER_VALIDATE_INT)); +$data = 123; var_dump(filter_data($data, FILTER_VALIDATE_INT)); +$data = ""; var_dump(filter_data($data, FILTER_VALIDATE_INT)); +echo "\n"; + +/* Float */ +$data = "-0.123"; var_dump(filter_data($data, FILTER_VALIDATE_FLOAT)); +$data = "0.00"; var_dump(filter_data($data, FILTER_VALIDATE_FLOAT)); +$data = "1.23"; var_dump(filter_data($data, FILTER_VALIDATE_FLOAT)); +$data = -1.23; var_dump(filter_data($data, FILTER_VALIDATE_FLOAT)); +$data = 0.0; var_dump(filter_data($data, FILTER_VALIDATE_FLOAT)); +$data = 1.23; var_dump(filter_data($data, FILTER_VALIDATE_FLOAT)); +$data = ""; var_dump(filter_data($data, FILTER_VALIDATE_FLOAT)); +echo "\n"; + +/* Boolean */ +$data = "on"; var_dump(filter_data($data, FILTER_VALIDATE_BOOLEAN)); +$data = "off"; var_dump(filter_data($data, FILTER_VALIDATE_BOOLEAN)); +$data = "yes"; var_dump(filter_data($data, FILTER_VALIDATE_BOOLEAN)); +$data = "no"; var_dump(filter_data($data, FILTER_VALIDATE_BOOLEAN)); +$data = "true"; var_dump(filter_data($data, FILTER_VALIDATE_BOOLEAN)); +$data = "false"; var_dump(filter_data($data, FILTER_VALIDATE_BOOLEAN)); +$data = "1"; var_dump(filter_data($data, FILTER_VALIDATE_BOOLEAN)); +$data = "0"; var_dump(filter_data($data, FILTER_VALIDATE_BOOLEAN)); +$data = 1; var_dump(filter_data($data, FILTER_VALIDATE_BOOLEAN)); +$data = 0; var_dump(filter_data($data, FILTER_VALIDATE_BOOLEAN)); +$data = true; var_dump(filter_data($data, FILTER_VALIDATE_BOOLEAN)); +$data = false; var_dump(filter_data($data, FILTER_VALIDATE_BOOLEAN)); +$data = ""; var_dump(filter_data($data, FILTER_VALIDATE_BOOLEAN)); + +?> +--EXPECT-- +int(-123) +int(0) +int(123) +int(-123) +int(0) +int(123) +int(0) + +float(-0.123) +float(0) +float(1.23) +float(-1.23) +float(0) +float(1.23) +float(0) + +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(false) diff --git a/ext/json/JSON_parser.c b/ext/json/JSON_parser.c new file mode 100644 index 0000000000..adb974346e --- /dev/null +++ b/ext/json/JSON_parser.c @@ -0,0 +1,757 @@ +/* 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 "JSON_parser.h" +#include <stdio.h> + +#define true 1 +#define false 0 + +/* + Characters are mapped into these 32 symbol classes. This allows for + significant reductions in the size of the state transition table. +*/ + +/* error */ +#define S_ERR -1 + +/* space */ +#define S_SPA 0 + +/* other whitespace */ +#define S_WSP 1 + +/* { */ +#define S_LBE 2 + +/* } */ +#define S_RBE 3 + +/* [ */ +#define S_LBT 4 + +/* ] */ +#define S_RBT 5 + +/* : */ +#define S_COL 6 + +/* , */ +#define S_COM 7 + +/* " */ +#define S_QUO 8 + +/* \ */ +#define S_BAC 9 + +/* / */ +#define S_SLA 10 + +/* + */ +#define S_PLU 11 + +/* - */ +#define S_MIN 12 + +/* . */ +#define S_DOT 13 + +/* 0 */ +#define S_ZER 14 + +/* 123456789 */ +#define S_DIG 15 + +/* a */ +#define S__A_ 16 + +/* b */ +#define S__B_ 17 + +/* c */ +#define S__C_ 18 + +/* d */ +#define S__D_ 19 + +/* e */ +#define S__E_ 20 + +/* f */ +#define S__F_ 21 + +/* l */ +#define S__L_ 22 + +/* n */ +#define S__N_ 23 + +/* r */ +#define S__R_ 24 + +/* s */ +#define S__S_ 25 + +/* t */ +#define S__T_ 26 + +/* u */ +#define S__U_ 27 + +/* ABCDF */ +#define S_A_F 28 + +/* E */ +#define S_E 29 + +/* everything else */ +#define S_ETC 30 + + +/* + This table maps the 128 ASCII characters into the 32 character classes. + The remaining Unicode characters should be mapped to S_ETC. +*/ +static int ascii_class[128] = { + S_ERR, S_ERR, S_ERR, S_ERR, S_ERR, S_ERR, S_ERR, S_ERR, + S_ERR, S_WSP, S_WSP, S_ERR, S_ERR, S_WSP, S_ERR, S_ERR, + S_ERR, S_ERR, S_ERR, S_ERR, S_ERR, S_ERR, S_ERR, S_ERR, + S_ERR, S_ERR, S_ERR, S_ERR, S_ERR, S_ERR, S_ERR, S_ERR, + + S_SPA, S_ETC, S_QUO, S_ETC, S_ETC, S_ETC, S_ETC, S_ETC, + S_ETC, S_ETC, S_ETC, S_PLU, S_COM, S_MIN, S_DOT, S_SLA, + S_ZER, S_DIG, S_DIG, S_DIG, S_DIG, S_DIG, S_DIG, S_DIG, + S_DIG, S_DIG, S_COL, S_ETC, S_ETC, S_ETC, S_ETC, S_ETC, + + S_ETC, S_A_F, S_A_F, S_A_F, S_A_F, S_E , S_A_F, S_ETC, + S_ETC, S_ETC, S_ETC, S_ETC, S_ETC, S_ETC, S_ETC, S_ETC, + S_ETC, S_ETC, S_ETC, S_ETC, S_ETC, S_ETC, S_ETC, S_ETC, + S_ETC, S_ETC, S_ETC, S_LBT, S_BAC, S_RBT, S_ETC, S_ETC, + + S_ETC, S__A_, S__B_, S__C_, S__D_, S__E_, S__F_, S_ETC, + S_ETC, S_ETC, S_ETC, S_ETC, S__L_, S_ETC, S__N_, S_ETC, + S_ETC, S_ETC, S__R_, S__S_, S__T_, S__U_, S_ETC, S_ETC, + S_ETC, S_ETC, S_ETC, S_LBE, S_ETC, S_RBE, S_ETC, S_ETC +}; + + +/* + The state transition table takes the current state and the current symbol, + and returns either a new state or an action. A new state is a number between + 0 and 29. An action is a negative number between -1 and -9. A JSON text is + accepted if the end of the text is in state 9 and mode is MODE_DONE. +*/ +static int state_transition_table[30][31] = { +/* 0*/ { 0, 0,-8,-1,-6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, +/* 1*/ { 1, 1,-1,-9,-1,-1,-1,-1, 3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, +/* 2*/ { 2, 2,-8,-1,-6,-5,-1,-1, 3,-1,-1,-1,20,-1,21,22,-1,-1,-1,-1,-1,13,-1,17,-1,-1,10,-1,-1,-1,-1}, +/* 3*/ { 3,-1, 3, 3, 3, 3, 3, 3,-4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}, +/* 4*/ {-1,-1,-1,-1,-1,-1,-1,-1, 3, 3, 3,-1,-1,-1,-1,-1,-1, 3,-1,-1,-1, 3,-1, 3, 3,-1, 3, 5,-1,-1,-1}, +/* 5*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 6, 6, 6, 6, 6, 6, 6, 6,-1,-1,-1,-1,-1,-1, 6, 6,-1}, +/* 6*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 7, 7, 7, 7, 7, 7, 7, 7,-1,-1,-1,-1,-1,-1, 7, 7,-1}, +/* 7*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 8, 8, 8, 8, 8, 8, 8, 8,-1,-1,-1,-1,-1,-1, 8, 8,-1}, +/* 8*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 3, 3, 3, 3, 3, 3, 3, 3,-1,-1,-1,-1,-1,-1, 3, 3,-1}, +/* 9*/ { 9, 9,-1,-7,-1,-5,-1,-3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, +/*10*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,11,-1,-1,-1,-1,-1,-1}, +/*11*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,12,-1,-1,-1}, +/*12*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 9,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, +/*13*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,14,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, +/*14*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,15,-1,-1,-1,-1,-1,-1,-1,-1}, +/*15*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,16,-1,-1,-1,-1,-1}, +/*16*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 9,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, +/*17*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,18,-1,-1,-1}, +/*18*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,19,-1,-1,-1,-1,-1,-1,-1,-1}, +/*19*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 9,-1,-1,-1,-1,-1,-1,-1,-1}, +/*20*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,21,22,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, +/*21*/ { 9, 9,-1,-7,-1,-5,-1,-3,-1,-1,-1,-1,-1,23,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, +/*22*/ { 9, 9,-1,-7,-1,-5,-1,-3,-1,-1,-1,-1,-1,23,22,22,-1,-1,-1,-1,24,-1,-1,-1,-1,-1,-1,-1,-1,24,-1}, +/*23*/ { 9, 9,-1,-7,-1,-5,-1,-3,-1,-1,-1,-1,-1,-1,23,23,-1,-1,-1,-1,24,-1,-1,-1,-1,-1,-1,-1,-1,24,-1}, +/*24*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,25,25,-1,26,26,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, +/*25*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,26,26,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, +/*26*/ { 9, 9,-1,-7,-1,-5,-1,-3,-1,-1,-1,-1,-1,-1,26,26,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, +/*27*/ {27,27,-1,-1,-1,-1,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, +/*28*/ {28,28,-8,-1,-6,-1,-1,-1, 3,-1,-1,-1,20,-1,21,22,-1,-1,-1,-1,-1,13,-1,17,-1,-1,10,-1,-1,-1,-1}, +/*29*/ {29,29,-1,-1,-1,-1,-1,-1, 3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1} +}; + +#define JSON_PARSER_MAX_DEPTH 20 + + +/* + A stack maintains the states of nested structures. +*/ + +typedef struct json_parser +{ + int the_stack[JSON_PARSER_MAX_DEPTH]; + zval *the_zstack[JSON_PARSER_MAX_DEPTH]; + int the_top; +} json_parser; + + +/* + These modes can be pushed on the PDA stack. +*/ +#define MODE_DONE 1 +#define MODE_KEY 2 +#define MODE_OBJECT 3 +#define MODE_ARRAY 4 + +/* + Push a mode onto the stack. Return false if there is overflow. +*/ +static int +push(json_parser *json, zval *z, int mode) +{ + json->the_top += 1; + if (json->the_top >= JSON_PARSER_MAX_DEPTH) { + return false; + } + + json->the_stack[json->the_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 *json, zval *z, int mode) +{ + if (json->the_top < 0 || json->the_stack[json->the_top] != mode) { + return false; + } + json->the_stack[json->the_top] = 0; + json->the_top -= 1; + + return true; +} + + +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) +{ + ALLOC_INIT_ZVAL(*z); + + if (type == IS_LONG) + { + ZVAL_LONG(*z, atol(buf->c)); + } + else if (type == IS_DOUBLE) + { + ZVAL_DOUBLE(*z, atof(buf->c)); + } + else if (type == IS_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 + { + 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 *json, int up, int cur, smart_str *key, int assoc TSRMLS_DC) +{ + zval *root = json->the_zstack[up]; + zval *child = json->the_zstack[cur]; + int up_mode = json->the_stack[up]; + + if (up_mode == MODE_ARRAY) + { + add_next_index_zval(root, child); + } + else if (up_mode == MODE_OBJECT) + { + if (!assoc) + { + add_property_zval(root, key->c, child); +#if PHP_MAJOR_VERSION >= 5 + ZVAL_DELREF(child); +#endif + } + else + { + add_assoc_zval(root, key->c, child); + } + key->len = 0; + } +} + + +#define FREE_BUFFERS() do { smart_str_free(&buf); smart_str_free(&key); } while (0); +#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() do { type = -1; } while(0); +#define JSON(x) the_json.x + + +/* + 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 +JSON_parser(zval *z, unsigned short p[], int length, int assoc TSRMLS_DC) +{ + int b; /* the next character */ + int c; /* the next character class */ + int s; /* the next state */ + json_parser the_json; /* the parser state */ + int the_state = 0; + int the_index; + + smart_str buf = {0}; + smart_str key = {0}; + + int type = -1; + unsigned short utf16; + + JSON(the_top) = -1; + push(&the_json, z, MODE_DONE); + + for (the_index = 0; the_index < length; the_index += 1) { + b = p[the_index]; + if ((b & 127) == b) { + c = ascii_class[b]; + if (c <= S_ERR) { + FREE_BUFFERS(); + return false; + } + } else { + c = S_ETC; + } +/* + Get the next state from the transition table. +*/ + s = state_transition_table[the_state][c]; + if (s < 0) { +/* + Perform one of the predefined actions. +*/ + switch (s) { +/* + empty } +*/ + case -9: + if (!pop(&the_json, z, MODE_KEY)) { + FREE_BUFFERS(); + return false; + } + the_state = 9; + break; +/* + { +*/ + case -8: + if (!push(&the_json, z, MODE_KEY)) { + FREE_BUFFERS(); + return false; + } + + the_state = 1; + if (JSON(the_top) > 0) + { + zval *obj; + + if (JSON(the_top) == 1) + { + obj = z; + } + else + { + ALLOC_INIT_ZVAL(obj); + } + + if (!assoc) + { + object_init(obj); + } + else + { + array_init(obj); + } + + JSON(the_zstack)[JSON(the_top)] = obj; + + if (JSON(the_top) > 1) + { + attach_zval(&the_json, JSON(the_top-1), JSON(the_top), &key, assoc TSRMLS_CC); + } + + JSON_RESET_TYPE(); + } + + break; +/* + } +*/ + case -7: + if (type != -1 && + (JSON(the_stack)[JSON(the_top)] == MODE_OBJECT || + JSON(the_stack)[JSON(the_top)] == MODE_ARRAY)) + { + zval *mval; + smart_str_0(&buf); + + json_create_zval(&mval, &buf, type); + + if (!assoc) + { + add_property_zval(JSON(the_zstack)[JSON(the_top)], key.c, mval); +#if PHP_MAJOR_VERSION >= 5 + ZVAL_DELREF(mval); +#endif + } + else + { + add_assoc_zval(JSON(the_zstack)[JSON(the_top)], key.c, mval); + } + key.len = 0; + buf.len = 0; + JSON_RESET_TYPE(); + } + + + if (!pop(&the_json, z, MODE_OBJECT)) { + FREE_BUFFERS(); + return false; + } + the_state = 9; + break; +/* + [ +*/ + case -6: + if (!push(&the_json, z, MODE_ARRAY)) { + FREE_BUFFERS(); + return false; + } + the_state = 2; + + if (JSON(the_top) > 0) + { + zval *arr; + + if (JSON(the_top) == 1) + { + arr = z; + } + else + { + ALLOC_INIT_ZVAL(arr); + } + + array_init(arr); + JSON(the_zstack)[JSON(the_top)] = arr; + + if (JSON(the_top) > 1) + { + attach_zval(&the_json, JSON(the_top-1), JSON(the_top), &key, assoc TSRMLS_CC); + } + + JSON_RESET_TYPE(); + } + + break; +/* + ] +*/ + case -5: + { + if (type != -1 && + (JSON(the_stack)[JSON(the_top)] == MODE_OBJECT || + JSON(the_stack)[JSON(the_top)] == MODE_ARRAY)) + { + zval *mval; + smart_str_0(&buf); + + json_create_zval(&mval, &buf, type); + add_next_index_zval(JSON(the_zstack)[JSON(the_top)], mval); + buf.len = 0; + JSON_RESET_TYPE(); + } + + if (!pop(&the_json, z, MODE_ARRAY)) { + FREE_BUFFERS(); + return false; + } + the_state = 9; + } + break; +/* + " +*/ + case -4: + switch (JSON(the_stack)[JSON(the_top)]) { + case MODE_KEY: + the_state = 27; + smart_str_0(&buf); + SWAP_BUFFERS(buf, key); + JSON_RESET_TYPE(); + break; + case MODE_ARRAY: + case MODE_OBJECT: + the_state = 9; + break; + default: + FREE_BUFFERS(); + return false; + } + break; +/* + , +*/ + case -3: + { + zval *mval; + + if (type != -1 && + (JSON(the_stack)[JSON(the_top)] == MODE_OBJECT || + JSON(the_stack[JSON(the_top)]) == MODE_ARRAY)) + { + smart_str_0(&buf); + json_create_zval(&mval, &buf, type); + } + + switch (JSON(the_stack)[JSON(the_top)]) { + case MODE_OBJECT: + if (pop(&the_json, z, MODE_OBJECT) && push(&the_json, z, MODE_KEY)) { + if (type != -1) + { + if (!assoc) + { + add_property_zval(JSON(the_zstack)[JSON(the_top)], (key.len ? key.c : "_empty_"), mval); +#if PHP_MAJOR_VERSION >= 5 + ZVAL_DELREF(mval); +#endif + } + else + { + add_assoc_zval(JSON(the_zstack)[JSON(the_top)], (key.len ? key.c : "_empty_"), mval); + } + key.len = 0; + } + the_state = 29; + } + break; + case MODE_ARRAY: + if (type != -1) + { + add_next_index_zval(JSON(the_zstack)[JSON(the_top)], mval); + } + the_state = 28; + break; + default: + FREE_BUFFERS(); + return false; + } + buf.len = 0; + JSON_RESET_TYPE(); + } + break; +/* + : +*/ + case -2: + if (pop(&the_json, z, MODE_KEY) && push(&the_json, z, MODE_OBJECT)) { + the_state = 28; + break; + } +/* + syntax error +*/ + case -1: + { + FREE_BUFFERS(); + return false; + } + } + } else { +/* + Change the state and iterate. +*/ + if (type == IS_STRING) + { + if (s == 3 && the_state != 8) + { + if (the_state != 4) + { + utf16_to_utf8(&buf, b); + } + else + { + switch (b) + { + 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, b); + break; + } + } + } + else if (s == 6) + { + utf16 = dehexchar(b) << 12; + } + else if (s == 7) + { + utf16 += dehexchar(b) << 8; + } + else if (s == 8) + { + utf16 += dehexchar(b) << 4; + } + else if (s == 3 && the_state == 8) + { + utf16 += dehexchar(b); + utf16_to_utf8(&buf, utf16); + } + } + else if (type < IS_LONG && (c == S_DIG || c == S_ZER)) + { + type = IS_LONG; + smart_str_appendc(&buf, b); + } + else if (type == IS_LONG && s == 24) + { + type = IS_DOUBLE; + smart_str_appendc(&buf, b); + } + else if (type < IS_DOUBLE && c == S_DOT) + { + type = IS_DOUBLE; + smart_str_appendc(&buf, b); + } + else if (type < IS_STRING && c == S_QUO) + { + type = IS_STRING; + } + else if (type < IS_BOOL && ((the_state == 12 && s == 9) || (the_state == 16 && s == 9))) + { + type = IS_BOOL; + } + else if (type < IS_NULL && the_state == 19 && s == 9) + { + type = IS_NULL; + } + else if (type != IS_STRING && c > S_WSP) + { + utf16_to_utf8(&buf, b); + } + + the_state = s; + } + } + + FREE_BUFFERS(); + + return the_state == 9 && pop(&the_json, z, MODE_DONE); +} + + +/* + * 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 0000000000..085e776982 --- /dev/null +++ b/ext/json/JSON_parser.h @@ -0,0 +1,8 @@ +/* JSON_checker.h */ + +#include "php.h" +#include "ext/standard/php_smart_str.h" + +static char digits[] = "0123456789abcdef"; + +extern int JSON_parser(zval *z, unsigned short p[], int length, int assoc TSRMLS_DC); diff --git a/ext/json/README b/ext/json/README new file mode 100644 index 0000000000..d680b0c592 --- /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 0000000000..a937b1f91b --- /dev/null +++ b/ext/json/config.m4 @@ -0,0 +1,88 @@ +dnl +dnl $Id$ +dnl + +AC_DEFUN([PHP_JSON_ADD_SOURCES], [ + PHP_JSON_SOURCES="$PHP_JSON_SOURCES $1" +]) + +AC_DEFUN([PHP_JSON_ADD_BASE_SOURCES], [ + PHP_JSON_BASE_SOURCES="$PHP_JSON_BASE_SOURCES $1" +]) + +AC_DEFUN([PHP_JSON_ADD_BUILD_DIR], [ + PHP_JSON_EXTRA_BUILD_DIRS="$PHP_JSON_EXTRA_BUILD_DIRS $1" +]) + +AC_DEFUN([PHP_JSON_ADD_INCLUDE], [ + PHP_JSON_EXTRA_INCLUDES="$PHP_JSON_EXTRA_INCLUDES $1" +]) + +AC_DEFUN([PHP_JSON_ADD_CONFIG_HEADER], [ + PHP_JSON_EXTRA_CONFIG_HEADERS="$PHP_JSON_EXTRA_CONFIG_HEADERS $1" +]) + +AC_DEFUN([PHP_JSON_ADD_CFLAG], [ + PHP_JSON_CFLAGS="$PHP_JSON_CFLAGS $1" +]) + +AC_DEFUN([PHP_JSON_EXTENSION], [ + PHP_NEW_EXTENSION(json, $PHP_JSON_SOURCES, $ext_shared,, $PHP_JSON_CFLAGS) + PHP_SUBST(JSON_SHARED_LIBADD) + + for dir in $PHP_JSON_EXTRA_BUILD_DIRS; do + PHP_ADD_BUILD_DIR([$ext_builddir/$dir], 1) + done + + for dir in $PHP_JSON_EXTRA_INCLUDES; do + PHP_ADD_INCLUDE([$ext_srcdir/$dir]) + PHP_ADD_INCLUDE([$ext_builddir/$dir]) + done + + if test "$ext_shared" = "no"; then + PHP_ADD_SOURCES(PHP_EXT_DIR(json), $PHP_JSON_BASE_SOURCES,$PHP_JSON_CFLAGS) + out="php_config.h" + else + PHP_ADD_SOURCES_X(PHP_EXT_DIR(json),$PHP_JSON_BASE_SOURCES,$PHP_JSON_CFLAGS,shared_objects_json,yes) + if test -f "$ext_builddir/config.h.in"; then + out="$abs_builddir/config.h" + else + out="php_config.h" + fi + fi + + for cfg in $PHP_JSON_EXTRA_CONFIG_HEADERS; do + cat > $ext_builddir/$cfg <<EOF +#include "$out" +EOF + done +]) + +AC_DEFUN([PHP_JSON_SETUP_JSON_CHECKER], [ + PHP_JSON_ADD_SOURCES([ + utf8_to_utf16.c + utf8_decode.c + JSON_parser.c + ]) +]) + +dnl +dnl Main config +dnl + +PHP_ARG_WITH(json, whether to enable JavaScript Object Serialization support, +[ --with-json Enable JavaScript Object Serialization support]) + +if test "$PHP_JSON" != "no"; then + AC_DEFINE([HAVE_JSON],1,[whether to have JavaScript Object Serialization support]) + AC_HEADER_STDC + + PHP_JSON_ADD_BASE_SOURCES([json.c]) + + dnl json_c is required + PHP_JSON_SETUP_JSON_CHECKER + PHP_JSON_EXTENSION + dnl PHP_INSTALL_HEADERS([ext/json], [json_c]) +fi + +# vim600: sts=2 sw=2 et diff --git a/ext/json/config.w32 b/ext/json/config.w32 new file mode 100644 index 0000000000..fa001d308c --- /dev/null +++ b/ext/json/config.w32 @@ -0,0 +1,10 @@ +// $Id$ +// vim:ft=javascript + +ARG_WITH("json", "JavaScript Object Serialization support", "no"); + +if (PHP_JSON != "no") { + EXTENSION('json', 'json.c', PHP_JSON_SHARED, ""); + ADD_SOURCES(configure_module_dirname, "JSON_parser.c utf8_decode.c utf8_to_utf16.c", "json"); +} + diff --git a/ext/json/json.c b/ext/json/json.c new file mode 100644 index 0000000000..d19eb2e9b5 --- /dev/null +++ b/ext/json/json.c @@ -0,0 +1,449 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2006 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/php_smart_str.h" +#include "utf8_to_utf16.h" +#include "JSON_parser.h" +#include "php_json.h" + +/* If you declare any globals in php_json.h uncomment this: +ZEND_DECLARE_MODULE_GLOBALS(json) +*/ + +/* True global resources - no need for thread safety here */ +static int le_json; + +/* {{{ json_functions[] + * + * Every user visible function must have an entry in json_functions[]. + */ +function_entry json_functions[] = { + PHP_FE(json_encode, NULL) + PHP_FE(json_decode, NULL) + {NULL, NULL, NULL} /* Must be the last line in json_functions[] */ +}; +/* }}} */ + +/* {{{ json_module_entry + */ +zend_module_entry json_module_entry = { +#if ZEND_MODULE_API_NO >= 20010901 + STANDARD_MODULE_HEADER, +#endif + "json", + json_functions, + NULL, + NULL, + NULL, + NULL, + PHP_MINFO(json), +#if ZEND_MODULE_API_NO >= 20010901 + PHP_JSON_VERSION, +#endif + STANDARD_MODULE_PROPERTIES +}; +/* }}} */ + +#ifdef COMPILE_DL_JSON +ZEND_GET_MODULE(json) +#endif + +/* {{{ PHP_MINFO_FUNCTION + */ +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_encode_r(smart_str *buf, zval *val TSRMLS_DC); +static void json_escape_string(smart_str *buf, char *s, int len TSRMLS_DC); + +static int json_determine_array_type(zval **val TSRMLS_DC) { + int i; + HashTable *myht; + + if (Z_TYPE_PP(val) == IS_ARRAY) { + myht = HASH_OF(*val); + } else { + myht = Z_OBJPROP_PP(val); + return 1; + } + + 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 0; +} + +static void json_encode_array(smart_str *buf, zval **val TSRMLS_DC) { + int i, r; + HashTable *myht; + + if (Z_TYPE_PP(val) == IS_ARRAY) { + myht = HASH_OF(*val); + r = json_determine_array_type(val TSRMLS_CC); + } else { + myht = Z_OBJPROP_PP(val); + r = 1; + } + + if (r == 0) + { + smart_str_appendc(buf, '['); + } + else + { + smart_str_appendc(buf, '{'); + } + + i = myht ? zend_hash_num_elements(myht) : 0; + if (i > 0) { + char *key; + zval **data; + ulong index; + uint key_len; + HashPosition pos; + 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) { + if (r == 0) { + if (need_comma) { + smart_str_appendc(buf, ','); + } else { + need_comma = 1; + } + + json_encode_r(buf, *data TSRMLS_CC); + } else if (r == 1) { + if (i == HASH_KEY_IS_STRING) { + if (key[0] == '\0') { + /* Skip protected and private members. */ + continue; + } + + if (need_comma) { + smart_str_appendc(buf, ','); + } else { + need_comma = 1; + } + + json_escape_string(buf, key, key_len - 1 TSRMLS_CC); + smart_str_appendc(buf, ':'); + + json_encode_r(buf, *data TSRMLS_CC); + } else { + if (need_comma) { + smart_str_appendc(buf, ','); + } else { + need_comma = 1; + } + + smart_str_appendc(buf, '"'); + smart_str_append_long(buf, (long) index); + smart_str_appendc(buf, '"'); + smart_str_appendc(buf, ':'); + + json_encode_r(buf, *data TSRMLS_CC); + } + } + } + } + } + + if (r == 0) + { + smart_str_appendc(buf, ']'); + } + else + { + smart_str_appendc(buf, '}'); + } +} + +#define REVERSE16(us) (((us & 0xf) << 12) | (((us >> 4) & 0xf) << 8) | (((us >> 8) & 0xf) << 4) | ((us >> 12) & 0xf)) + +static void json_escape_string(smart_str *buf, char *s, int len TSRMLS_DC) +{ + int pos = 0; + unsigned short us; + unsigned short *utf16; + + if (len == 0) + { + smart_str_appendl(buf, "\"\"", 2); + return; + } + + utf16 = (unsigned short *) emalloc(len * sizeof(unsigned short)); + + len = utf8_to_utf16(utf16, s, len); + if (len <= 0) + { + if (utf16) + { + efree(utf16); + } + + smart_str_appendl(buf, "\"\"", 2); + return; + } + + smart_str_appendc(buf, '"'); + + while(pos < len) + { + us = utf16[pos++]; + + switch (us) + { + case '"': + { + smart_str_appendl(buf, "\\\"", 2); + } + break; + case '\\': + { + smart_str_appendl(buf, "\\\\", 2); + } + break; + case '/': + { + 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; + default: + { + if (us < ' ' || (us & 127) == us) + { + smart_str_appendc(buf, (unsigned char) us); + } + else + { + smart_str_appendl(buf, "\\u", 2); + us = REVERSE16(us); + + smart_str_appendc(buf, digits[us & ((1 << 4) - 1)]); + us >>= 4; + smart_str_appendc(buf, digits[us & ((1 << 4) - 1)]); + us >>= 4; + smart_str_appendc(buf, digits[us & ((1 << 4) - 1)]); + us >>= 4; + smart_str_appendc(buf, digits[us & ((1 << 4) - 1)]); + } + } + break; + } + } + + smart_str_appendc(buf, '"'); + efree(utf16); +} + +static void json_encode_r(smart_str *buf, zval *val 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, "%.9g", dbl); + if (d) + { + smart_str_appendl(buf, d, len); + efree(d); + } + } + else + { + zend_error(E_WARNING, "[json] (json_encode_r) double %.9g does not conform to the JSON spec, encoded as 0.", dbl); + smart_str_appendc(buf, '0'); + } + } + break; + case IS_STRING: + json_escape_string(buf, Z_STRVAL_P(val), Z_STRLEN_P(val) TSRMLS_CC); + break; + case IS_ARRAY: + case IS_OBJECT: + json_encode_array(buf, &val TSRMLS_CC); + break; + default: + zend_error(E_WARNING, "[json] (json_encode_r) type is unsupported, encoded as null."); + smart_str_appendl(buf, "null", 4); + break; + } + + return; +} + +PHP_FUNCTION(json_encode) +{ + zval *parameter; + smart_str buf = {0}; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", ¶meter) == FAILURE) { + return; + } + + json_encode_r(&buf, parameter TSRMLS_CC); + + ZVAL_STRINGL(return_value, buf.c, buf.len, 1); + + smart_str_free(&buf); +} + +PHP_FUNCTION(json_decode) +{ + char *parameter; + int parameter_len, utf16_len; + zend_bool assoc = 0; /* return JS objects as PHP objects by default */ + zval *z; + unsigned short *utf16; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", ¶meter, ¶meter_len, &assoc) == FAILURE) { + return; + } + + if (!parameter_len) + { + RETURN_NULL(); + } + + utf16 = (unsigned short *) emalloc((parameter_len+1) * sizeof(unsigned short)); + + utf16_len = utf8_to_utf16(utf16, parameter, parameter_len); + if (utf16_len <= 0) + { + if (utf16) + { + efree(utf16); + } + + RETURN_NULL(); + } + + ALLOC_INIT_ZVAL(z); + if (JSON_parser(z, utf16, utf16_len, assoc TSRMLS_CC)) + { + *return_value = *z; + + FREE_ZVAL(z); + efree(utf16); + } + else + { + zval_dtor(z); + FREE_ZVAL(z); + efree(utf16); + RETURN_NULL(); + } +} + +/* + * 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.dsp b/ext/json/json.dsp new file mode 100644 index 0000000000..e5bb3767bf --- /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 0000000000..0651de736f --- /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 0000000000..48555ee31f --- /dev/null +++ b/ext/json/php_json.h @@ -0,0 +1,60 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2006 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" + +extern zend_module_entry json_module_entry; +#define phpext_json_ptr &json_module_entry + +#ifdef PHP_WIN32 +#define PHP_JSON_API __declspec(dllexport) +#else +#define PHP_JSON_API +#endif + +#ifdef ZTS +#include "TSRM.h" +#endif + +PHP_MINFO_FUNCTION(json); + +PHP_FUNCTION(json_encode); +PHP_FUNCTION(json_decode); + +#ifdef ZTS +#define JSON_G(v) TSRMG(json_globals_id, zend_json_globals *, v) +#else +#define JSON_G(v) (json_globals.v) +#endif + +#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/fail001.phpt b/ext/json/tests/fail001.phpt new file mode 100644 index 0000000000..4ee3780cf3 --- /dev/null +++ b/ext/json/tests/fail001.phpt @@ -0,0 +1,166 @@ +--TEST-- +JSON Test Pattern fail1 -> fail24 +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 +NULL +AS ARRAY +NULL +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/pass001.1.phpt b/ext/json/tests/pass001.1.phpt new file mode 100644 index 0000000000..0cb05308da --- /dev/null +++ b/ext/json/tests/pass001.1.phpt @@ -0,0 +1,895 @@ +--TEST-- +JSON Test Pattern pass1.1 +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. +http://www.crockford.com/JSON/JSON_checker/test/pass1.json +--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, + \"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\": \"" \\u0022 %22 0x22 034 "\", + \"\\/\\\\\\\"\\uCAFE\\uBABE\\uAB98\\uFCDE\\ubcda\\uef4A\\b\\f\\n\\r\\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?\" +: \"A key can be any string\" + }, + 0.5 ,98.6 +, +99.44 +, + +1066 + + +,\"rosebud\"] +"; + +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 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": "" \u0022 %22 0x22 034 "", + "\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?" +: "A key can be any string" + }, + 0.5 ,98.6 +, +99.44 +, + +1066 + + +,"rosebud"] + +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 (36) { + ["integer"]=> + int(1234567890) + ["real"]=> + float(-9876.54321) + ["e"]=> + float(1.23456789E-13) + ["E"]=> + float(1.23456789E+34) + ["_empty_"]=> + float(INF) + ["E no ."]=> + float(4.0E+12) + ["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)#4 (0) { + } + ["123"]=> + object(stdClass)#5 (1) { + ["456"]=> + object(stdClass)#6 (1) { + ["abc"]=> + object(stdClass)#7 (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) "" " %22 0x22 034 "" + ["/\"쫾몾ꮘﳞ볚 + + `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) + ["_empty_"]=> + float(INF) + ["E no ."]=> + float(4.0E+12) + ["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) "" " %22 0x22 034 "" + ["/\"쫾몾ꮘﳞ볚 + + `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 .":4.0e+12,"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":"" \" %22 0x22 034 "","\/\\\"\ucafe\ubabe\uab98\ufcde\ubcda\uef4a\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',.\/<>?":"A key can be any string"},0.5,98.6,99.44,1066,"rosebud"] +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,"_empty_":0,"E no .":4.0e+12,"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":"" \" %22 0x22 034 "","\/\\\"\ucafe\ubabe\uab98\ufcde\ubcda\uef4a\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',.\/<>?":"A key can be any string"},0.5,98.6,99.44,1066,"rosebud"] +DECODE AGAIN: AS OBJECT +array(14) { + [0]=> + string(23) "JSON Test Pattern pass1" + [1]=> + object(stdClass)#8 (1) { + ["object with 1 member"]=> + array(1) { + [0]=> + string(20) "array with 1 element" + } + } + [2]=> + object(stdClass)#9 (0) { + } + [3]=> + array(0) { + } + [4]=> + int(-42) + [5]=> + bool(true) + [6]=> + bool(false) + [7]=> + NULL + [8]=> + object(stdClass)#10 (36) { + ["integer"]=> + int(1234567890) + ["real"]=> + float(-9876.54321) + ["e"]=> + float(1.23456789E-13) + ["E"]=> + float(1.23456789E+34) + ["_empty_"]=> + int(0) + ["E no ."]=> + float(4.0E+12) + ["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)#11 (0) { + } + ["123"]=> + object(stdClass)#12 (1) { + ["456"]=> + object(stdClass)#13 (1) { + ["abc"]=> + object(stdClass)#14 (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) "" " %22 0x22 034 "" + ["/\"쫾몾ꮘﳞ볚 + + `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) + ["_empty_"]=> + int(0) + ["E no ."]=> + float(4.0E+12) + ["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) "" " %22 0x22 034 "" + ["/\"쫾몾ꮘﳞ볚 + + `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 0000000000..aff970b107 --- /dev/null +++ b/ext/json/tests/pass001.phpt @@ -0,0 +1,709 @@ +--TEST-- +JSON Test Pattern pass1 +http://www.crockford.com/JSON/JSON_checker/test/pass1.json +--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\": \"" \\u0022 %22 0x22 034 "\", + \"\\/\\\\\\\"\\uCAFE\\uBABE\\uAB98\\uFCDE\\ubcda\\uef4A\\b\\f\\n\\r\\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?\" +: \"A key can be any string\" + }, + 0.5 ,98.6 +, +99.44 +, + +1066 + + +,\"rosebud\"] +"; + +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 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": "" \u0022 %22 0x22 034 "", + "\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?" +: "A key can be any string" + }, + 0.5 ,98.6 +, +99.44 +, + +1066 + + +,"rosebud"] + +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) "" " %22 0x22 034 "" + ["/\"쫾몾ꮘﳞ볚 + + `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) + ["_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"]=> + 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) "" " %22 0x22 034 "" + ["/\"쫾몾ꮘﳞ볚 + + `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":"" \" %22 0x22 034 "","\/\\\"\ucafe\ubabe\uab98\ufcde\ubcda\uef4a\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',.\/<>?":"A key can be any string"},0.5,98.6,99.44,1066,"rosebud"] +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,"_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":"" \" %22 0x22 034 "","\/\\\"\ucafe\ubabe\uab98\ufcde\ubcda\uef4a\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',.\/<>?":"A key can be any string"},0.5,98.6,99.44,1066,"rosebud"] +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) "" " %22 0x22 034 "" + ["/\"쫾몾ꮘﳞ볚 + + `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) + ["_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"]=> + 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) "" " %22 0x22 034 "" + ["/\"쫾몾ꮘﳞ볚 + + `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 0000000000..a0e527ac4f --- /dev/null +++ b/ext/json/tests/pass002.phpt @@ -0,0 +1,276 @@ +--TEST-- +JSON Test Pattern pass2 +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 0000000000..506ff05b3e --- /dev/null +++ b/ext/json/tests/pass003.phpt @@ -0,0 +1,95 @@ +--TEST-- +JSON Test Pattern pass3 +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/utf8_decode.c b/ext/json/utf8_decode.c new file mode 100644 index 0000000000..cea1f8cec8 --- /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 & 0xF1) == 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 0000000000..cc0fc79f6c --- /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/json/utf8_to_utf16.c b/ext/json/utf8_to_utf16.c new file mode 100644 index 0000000000..bc2d6f36d6 --- /dev/null +++ b/ext/json/utf8_to_utf16.c @@ -0,0 +1,56 @@ +/* utf8_to_utf16.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_to_utf16.h" +#include "utf8_decode.h" + +int +utf8_to_utf16(unsigned short w[], char p[], int length) +{ + int c; + int the_index = 0; + json_utf8_decode utf8; + + utf8_decode_init(&utf8, p, length); + for (;;) { + c = utf8_decode_next(&utf8); + if (c < 0) { + return UTF8_END ? the_index : UTF8_ERROR; + } + if (c < 0x10000) { + w[the_index] = (unsigned short)c; + the_index += 1; + } else { + c &= 0xFFFF; + w[the_index] = (unsigned short)(0xD800 | (c >> 10)); + the_index += 1; + w[the_index] = (unsigned short)(0xDC00 | (c & 0x3FF)); + the_index += 1; + } + } +} diff --git a/ext/json/utf8_to_utf16.h b/ext/json/utf8_to_utf16.h new file mode 100644 index 0000000000..5aff0268bf --- /dev/null +++ b/ext/json/utf8_to_utf16.h @@ -0,0 +1,3 @@ +/* utf8_to_utf16.h */ + +extern int utf8_to_utf16(unsigned short w[], char p[], int length); |