From 7823bb815dcdfe9890c0ac08e114b2b68433d4b7 Mon Sep 17 00:00:00 2001 From: jcm Date: Sun, 24 Jul 2022 19:55:19 +0200 Subject: [PATCH 01/25] is_json() --- ext/json/json.c | 78 +++++++++++++++++++- ext/json/json.stub.php | 2 + ext/json/json_arginfo.h | 10 ++- ext/json/json_parser.y | 30 +++++++- ext/json/php_json.h | 12 +++- ext/json/tests/juan.phpt | 149 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 275 insertions(+), 6 deletions(-) create mode 100644 ext/json/tests/juan.phpt diff --git a/ext/json/json.c b/ext/json/json.c index 4fac95fab39fe..c6b6f79c2ff13 100644 --- a/ext/json/json.c +++ b/ext/json/json.c @@ -157,7 +157,8 @@ static const char *php_json_get_error_msg(php_json_error_code error_code) /* {{{ } /* }}} */ -PHP_JSON_API zend_result php_json_decode_ex(zval *return_value, const char *str, size_t str_len, zend_long options, zend_long depth) /* {{{ */ +/* {{{ */ +PHP_JSON_API zend_result php_json_decode_ex(zval *return_value, const char *str, size_t str_len, zend_long options, zend_long depth) { php_json_parser parser; @@ -178,6 +179,30 @@ PHP_JSON_API zend_result php_json_decode_ex(zval *return_value, const char *str, } /* }}} */ +/* {{{ */ +PHP_JSON_API zend_result php_is_json_ex(zval *return_value, const char *str, size_t str_len, zend_long options, zend_long depth) +{ + php_json_parser parser; + + options |= PHP_JSON_VALIDATE_ONLY; + + php_json_parser_init(&parser, return_value, str, str_len, (int)options, (int)depth); + + if (php_json_yyparse(&parser)) { + php_json_error_code error_code = php_json_parser_error_code(&parser); + if (!(options & PHP_JSON_THROW_ON_ERROR)) { + JSON_G(error_code) = error_code; + } else { + zend_throw_exception(php_json_exception_ce, php_json_get_error_msg(error_code), error_code); + } + RETVAL_FALSE; + return FAILURE; + } + + return SUCCESS; +} +/* }}} */ + /* {{{ Returns the JSON representation of a value */ PHP_FUNCTION(json_encode) { @@ -216,6 +241,57 @@ PHP_FUNCTION(json_encode) } /* }}} */ +/* {{{ Validates if an string contains a valid json */ +PHP_FUNCTION(is_json) +{ + char *str; + size_t str_len; + zend_long depth = PHP_JSON_PARSER_DEFAULT_DEPTH; + zend_long options = 0; + + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_STRING(str, str_len) + Z_PARAM_OPTIONAL + Z_PARAM_LONG(depth) + Z_PARAM_LONG(options) + ZEND_PARSE_PARAMETERS_END(); + + if ((options != 0) + && (!(options & PHP_JSON_THROW_ON_ERROR) && !(options & PHP_JSON_INVALID_UTF8_IGNORE))) { + zend_argument_value_error(3, "must be a valid flag (JSON_THROW_ON_ERROR, JSON_INVALID_UTF8_IGNORE)"); + RETURN_THROWS(); + } + + if (!str_len) { + if (!(options & PHP_JSON_THROW_ON_ERROR)) { + JSON_G(error_code) = PHP_JSON_ERROR_SYNTAX; + } + + RETURN_FALSE; + } + + if (!(options & PHP_JSON_THROW_ON_ERROR)) { + JSON_G(error_code) = PHP_JSON_ERROR_NONE; + } + + if (depth <= 0) { + zend_argument_value_error(2, "must be greater than 0"); + RETURN_THROWS(); + } + + if (depth > INT_MAX) { + zend_argument_value_error(2, "must be less than %d", INT_MAX); + RETURN_THROWS(); + } + + if (php_is_json_ex(return_value, str, str_len, options, depth) == SUCCESS) { + RETURN_TRUE; + } + + RETURN_FALSE; +} +/* }}} */ + /* {{{ Decodes the JSON representation into a PHP value */ PHP_FUNCTION(json_decode) { diff --git a/ext/json/json.stub.php b/ext/json/json.stub.php index 7a8b479ab7657..fc7396493e8ff 100644 --- a/ext/json/json.stub.php +++ b/ext/json/json.stub.php @@ -156,6 +156,8 @@ function json_encode(mixed $value, int $flags = 0, int $depth = 512): string|fal function json_decode(string $json, ?bool $associative = null, int $depth = 512, int $flags = 0): mixed {} +function is_json(string $json, int $depth = 512, int $flags = 0): bool {} + function json_last_error(): int {} /** @refcount 1 */ diff --git a/ext/json/json_arginfo.h b/ext/json/json_arginfo.h index 8c88f24c403cd..e9169804a4fdc 100644 --- a/ext/json/json_arginfo.h +++ b/ext/json/json_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 91b1a992a7020081c42e1db876e5cdce94b681dd */ + * Stub hash: a0669aae151188f14deeda48c4f2d29d0d06ecec */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_json_encode, 0, 1, MAY_BE_STRING|MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0) @@ -14,6 +14,12 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_json_decode, 0, 1, IS_MIXED, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "0") ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_is_json, 0, 1, _IS_BOOL, 0) + ZEND_ARG_TYPE_INFO(0, json, IS_STRING, 0) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, depth, IS_LONG, 0, "512") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "0") +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_json_last_error, 0, 0, IS_LONG, 0) ZEND_END_ARG_INFO() @@ -26,6 +32,7 @@ ZEND_END_ARG_INFO() ZEND_FUNCTION(json_encode); ZEND_FUNCTION(json_decode); +ZEND_FUNCTION(is_json); ZEND_FUNCTION(json_last_error); ZEND_FUNCTION(json_last_error_msg); @@ -33,6 +40,7 @@ ZEND_FUNCTION(json_last_error_msg); static const zend_function_entry ext_functions[] = { ZEND_FE(json_encode, arginfo_json_encode) ZEND_FE(json_decode, arginfo_json_decode) + ZEND_FE(is_json, arginfo_is_json) ZEND_FE(json_last_error, arginfo_json_last_error) ZEND_FE(json_last_error_msg, arginfo_json_last_error_msg) ZEND_FE_END diff --git a/ext/json/json_parser.y b/ext/json/json_parser.y index 862b1bc0ab7e6..96ec1ec5765e9 100644 --- a/ext/json/json_parser.y +++ b/ext/json/json_parser.y @@ -79,7 +79,14 @@ start: value PHP_JSON_T_EOI { ZVAL_COPY_VALUE(&$$, &$1); - ZVAL_COPY_VALUE(parser->return_value, &$1); + + if (parser->scanner.options & PHP_JSON_VALIDATE_ONLY) { + zval_ptr_dtor(parser->return_value); + ZVAL_BOOL(parser->return_value, true); + } else { + ZVAL_COPY_VALUE(parser->return_value, &$1); + } + YYACCEPT; } ; @@ -213,18 +220,30 @@ value: static int php_json_parser_array_create(php_json_parser *parser, zval *array) { + if (parser->scanner.options & PHP_JSON_VALIDATE_ONLY) { + return SUCCESS; + } + array_init(array); return SUCCESS; } static int php_json_parser_array_append(php_json_parser *parser, zval *array, zval *zvalue) { + if (parser->scanner.options & PHP_JSON_VALIDATE_ONLY) { + return SUCCESS; + } + zend_hash_next_index_insert(Z_ARRVAL_P(array), zvalue); return SUCCESS; } static int php_json_parser_object_create(php_json_parser *parser, zval *object) { + if (parser->scanner.options & PHP_JSON_VALIDATE_ONLY) { + return SUCCESS; + } + if (parser->scanner.options & PHP_JSON_OBJECT_AS_ARRAY) { array_init(object); } else { @@ -235,6 +254,10 @@ static int php_json_parser_object_create(php_json_parser *parser, zval *object) static int php_json_parser_object_update(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue) { + if (parser->scanner.options & PHP_JSON_VALIDATE_ONLY) { + return SUCCESS; + } + /* if JSON_OBJECT_AS_ARRAY is set */ if (Z_TYPE_P(object) == IS_ARRAY) { zend_symtable_update(Z_ARRVAL_P(object), key, zvalue); @@ -258,6 +281,11 @@ static int php_json_yylex(union YYSTYPE *value, php_json_parser *parser) { int token = php_json_scan(&parser->scanner); value->value = parser->scanner.value; + + if (parser->scanner.options & PHP_JSON_VALIDATE_ONLY) { + zval_ptr_dtor_str(&(parser->scanner.value)); + } + return token; } diff --git a/ext/json/php_json.h b/ext/json/php_json.h index d4d8ac421f886..0ba152725b5f0 100644 --- a/ext/json/php_json.h +++ b/ext/json/php_json.h @@ -72,10 +72,15 @@ typedef enum { #define PHP_JSON_PRESERVE_ZERO_FRACTION (1<<10) #define PHP_JSON_UNESCAPED_LINE_TERMINATORS (1<<11) -/* json_decode() and json_encode() common options */ +/* is_json(), json_decode() and json_encode() common options */ #define PHP_JSON_INVALID_UTF8_IGNORE (1<<20) -#define PHP_JSON_INVALID_UTF8_SUBSTITUTE (1<<21) -#define PHP_JSON_THROW_ON_ERROR (1<<22) +#define PHP_JSON_THROW_ON_ERROR (1<<21) + +/* json_decode() and json_encode() common options */ +#define PHP_JSON_INVALID_UTF8_SUBSTITUTE (1<<22) + +/* is_json() internal option only */ +#define PHP_JSON_VALIDATE_ONLY (1<<23) /* Internal flags */ #define PHP_JSON_OUTPUT_ARRAY 0 @@ -100,6 +105,7 @@ ZEND_TSRMLS_CACHE_EXTERN() PHP_JSON_API zend_result php_json_encode_ex(smart_str *buf, zval *val, int options, zend_long depth); PHP_JSON_API zend_result php_json_encode(smart_str *buf, zval *val, int options); PHP_JSON_API zend_result php_json_decode_ex(zval *return_value, const char *str, size_t str_len, zend_long options, zend_long depth); +PHP_JSON_API zend_result php_is_json_ex(zval *return_value, const char *str, size_t str_len, zend_long options, zend_long depth); static inline zend_result php_json_decode(zval *return_value, const char *str, size_t str_len, bool assoc, zend_long depth) { diff --git a/ext/json/tests/juan.phpt b/ext/json/tests/juan.phpt new file mode 100644 index 0000000000000..3f29610558ed2 --- /dev/null +++ b/ext/json/tests/juan.phpt @@ -0,0 +1,149 @@ +--TEST-- +is_json() tests +--INI-- +memory_limit=-1 +--FILE-- +getMessage()); +} +return; + +var_dump(is_json('{ "test": {} "foo": "bar" }, "test2": {"foo" : "bar" }, "test2": {"foo" : "bar" } }')); +return; +*/ + +/* +echo "-----------------------\n"; +$limit = 1000000; +$jsonString = '{ "test": { "foo": "bar" },'; + +for ($i=0; $i < $limit; $i++) { + $jsonString .= " \"test$i\": { \"foo\": { \"test\" : { \"foo\" : { \"test\" : { \"foo\" : \"bar\" }}}}},"; +} + +$jsonString .= ' "testXXXX": { "foo": "replaceme" } }'; +//{ "test" : { "foo" : "bar" }}} + +$memoryBefore = memory_get_usage(true) / 1024 / 1024; +$memoryBeforePeak = memory_get_peak_usage(true) / 1024 / 1024; +echo "Megas used before call: " . $memoryBefore . PHP_EOL; +echo "PEAK Megas used before call: " . $memoryBeforePeak . PHP_EOL; + +$start = microtime(true); + +//json_decode($jsonString, null, $limit, 0); +var_dump(is_json($jsonString)); + +$memoryAfter = memory_get_usage(true) / 1024 / 1024; +$memoryAfterPeak = memory_get_peak_usage(true) / 1024 / 1024; +echo "Megas used after call: " . $memoryAfter . PHP_EOL; +echo "PEAK Megas used after call: " . $memoryAfterPeak . PHP_EOL; + +echo "Difference: " . ($memoryAfter - $memoryBefore) . PHP_EOL; +echo "PEAK Difference: " . ($memoryAfterPeak - $memoryBeforePeak) . PHP_EOL; + +echo "Time: " . (microtime(true) - $start) . " seconds" . PHP_EOL; +return; +*/ + + + +var_dump(json_decode(""), is_json("")); +echo "-------------------\n"; +var_dump(json_decode("."), is_json(".")); +echo "-------------------\n"; +var_dump(json_decode(""), is_json("")); +echo "-------------------\n"; +var_dump(json_decode(";"), is_json(";")); +echo "-------------------\n"; +var_dump(json_decode("руссиш"), is_json("руссиш")); +echo "-------------------\n"; +var_dump(json_decode("blah"), is_json("blah")); +echo "-------------------\n"; +var_dump(json_decode(NULL), is_json(NULL)); +echo "-------------------\n"; +var_dump(json_decode('{ "test": { "foo": "bar" } }'), is_json('{ "test": { "foo": "bar" } }')); +echo "-------------------\n"; +var_dump(json_decode('{ "test": { "foo": "" } }'), is_json('{ "test": { "foo": "" } }')); +echo "-------------------\n"; +var_dump(json_decode('{ "": { "foo": "" } }'), is_json('{ "": { "foo": "" } }')); +echo "-------------------\n"; +var_dump(json_decode('{ "": { "": "" } }'), is_json('{ "": { "": "" } }')); +echo "-------------------\n"; +var_dump(json_decode('{ "": { "": "" }'), is_json('{ "": { "": "" }')); +echo "-------------------\n"; +var_dump(json_decode('{ "": "": "" } }'), is_json('{ "": "": "" } }')); +?> + +--EXPECTF-- +NULL +bool(false) +------------------- +NULL +bool(false) +------------------- +NULL +bool(false) +------------------- +NULL +bool(false) +------------------- +NULL +bool(false) +------------------- +NULL +bool(false) +------------------- + +Deprecated: json_decode(): Passing null to parameter #1 ($json) of type string is deprecated in %s on line %d + +Deprecated: is_json(): Passing null to parameter #1 ($json) of type string is deprecated in %s on line %d +NULL +bool(false) +------------------- +object(stdClass)#2 (1) { + ["test"]=> + object(stdClass)#1 (1) { + ["foo"]=> + string(3) "bar" + } +} +bool(true) +------------------- +object(stdClass)#1 (1) { + ["test"]=> + object(stdClass)#2 (1) { + ["foo"]=> + string(0) "" + } +} +bool(true) +------------------- +object(stdClass)#2 (1) { + [""]=> + object(stdClass)#1 (1) { + ["foo"]=> + string(0) "" + } +} +bool(true) +------------------- +object(stdClass)#1 (1) { + [""]=> + object(stdClass)#2 (1) { + [""]=> + string(0) "" + } +} +bool(true) +------------------- +NULL +bool(false) +------------------- +NULL +bool(false) \ No newline at end of file From d80fe0d11f7dfdeaa171646c07cb9eff98697b48 Mon Sep 17 00:00:00 2001 From: jcm Date: Wed, 17 Aug 2022 14:00:52 +0200 Subject: [PATCH 02/25] Usage test --- .../tests/{juan.phpt => is_json_001.phpt} | 53 +------------------ 1 file changed, 1 insertion(+), 52 deletions(-) rename ext/json/tests/{juan.phpt => is_json_001.phpt} (60%) diff --git a/ext/json/tests/juan.phpt b/ext/json/tests/is_json_001.phpt similarity index 60% rename from ext/json/tests/juan.phpt rename to ext/json/tests/is_json_001.phpt index 3f29610558ed2..1fe71a4a2142c 100644 --- a/ext/json/tests/juan.phpt +++ b/ext/json/tests/is_json_001.phpt @@ -1,58 +1,7 @@ --TEST-- -is_json() tests ---INI-- -memory_limit=-1 +is_json() Usage --FILE-- getMessage()); -} -return; - -var_dump(is_json('{ "test": {} "foo": "bar" }, "test2": {"foo" : "bar" }, "test2": {"foo" : "bar" } }')); -return; -*/ - -/* -echo "-----------------------\n"; -$limit = 1000000; -$jsonString = '{ "test": { "foo": "bar" },'; - -for ($i=0; $i < $limit; $i++) { - $jsonString .= " \"test$i\": { \"foo\": { \"test\" : { \"foo\" : { \"test\" : { \"foo\" : \"bar\" }}}}},"; -} - -$jsonString .= ' "testXXXX": { "foo": "replaceme" } }'; -//{ "test" : { "foo" : "bar" }}} - -$memoryBefore = memory_get_usage(true) / 1024 / 1024; -$memoryBeforePeak = memory_get_peak_usage(true) / 1024 / 1024; -echo "Megas used before call: " . $memoryBefore . PHP_EOL; -echo "PEAK Megas used before call: " . $memoryBeforePeak . PHP_EOL; - -$start = microtime(true); - -//json_decode($jsonString, null, $limit, 0); -var_dump(is_json($jsonString)); - -$memoryAfter = memory_get_usage(true) / 1024 / 1024; -$memoryAfterPeak = memory_get_peak_usage(true) / 1024 / 1024; -echo "Megas used after call: " . $memoryAfter . PHP_EOL; -echo "PEAK Megas used after call: " . $memoryAfterPeak . PHP_EOL; - -echo "Difference: " . ($memoryAfter - $memoryBefore) . PHP_EOL; -echo "PEAK Difference: " . ($memoryAfterPeak - $memoryBeforePeak) . PHP_EOL; - -echo "Time: " . (microtime(true) - $start) . " seconds" . PHP_EOL; -return; -*/ - - - var_dump(json_decode(""), is_json("")); echo "-------------------\n"; var_dump(json_decode("."), is_json(".")); From ec963aae730555831d6a18cc329eb55ee708a737 Mon Sep 17 00:00:00 2001 From: jcm Date: Wed, 17 Aug 2022 14:11:59 +0200 Subject: [PATCH 03/25] is_json - test - general usage --- ext/json/tests/is_json_001.phpt | 104 ++++++++------------------------ 1 file changed, 24 insertions(+), 80 deletions(-) diff --git a/ext/json/tests/is_json_001.phpt b/ext/json/tests/is_json_001.phpt index 1fe71a4a2142c..ed49ad7ab0f7f 100644 --- a/ext/json/tests/is_json_001.phpt +++ b/ext/json/tests/is_json_001.phpt @@ -1,98 +1,42 @@ --TEST-- -is_json() Usage +is_json() - General usage --FILE-- "), is_json("")); -echo "-------------------\n"; -var_dump(json_decode(";"), is_json(";")); -echo "-------------------\n"; -var_dump(json_decode("руссиш"), is_json("руссиш")); -echo "-------------------\n"; -var_dump(json_decode("blah"), is_json("blah")); -echo "-------------------\n"; -var_dump(json_decode(NULL), is_json(NULL)); -echo "-------------------\n"; -var_dump(json_decode('{ "test": { "foo": "bar" } }'), is_json('{ "test": { "foo": "bar" } }')); -echo "-------------------\n"; -var_dump(json_decode('{ "test": { "foo": "" } }'), is_json('{ "test": { "foo": "" } }')); -echo "-------------------\n"; -var_dump(json_decode('{ "": { "foo": "" } }'), is_json('{ "": { "foo": "" } }')); -echo "-------------------\n"; -var_dump(json_decode('{ "": { "": "" } }'), is_json('{ "": { "": "" } }')); -echo "-------------------\n"; -var_dump(json_decode('{ "": { "": "" }'), is_json('{ "": { "": "" }')); -echo "-------------------\n"; -var_dump(json_decode('{ "": "": "" } }'), is_json('{ "": "": "" } }')); +var_dump( + is_json(""), + is_json("."), + is_json(""), + is_json(";"), + is_json("руссиш"), + is_json("blah"), + is_json(NULL), + is_json('{ "test": { "foo": "bar" } }'), + is_json('{ "test": { "foo": "" } }'), + is_json('{ "": { "foo": "" } }'), + is_json('{ "": { "": "" } }'), + is_json('{ "": { "": "" }'), + is_json('{ "test": {} "foo": "bar" }, "test2": {"foo" : "bar" }, "test2": {"foo" : "bar" } }'), + is_json('{ "test": {"foo": "bar"}, "test2": {"foo" : "bar" }, "test2": {"foo" : "bar" } }'), + is_json('{ "test": {"foo": "bar"}, "test2": {"foo" : "bar" }, "test3": {"foo" : "bar" } }'), + is_json('{ "": "": "" } }') +); ?> --EXPECTF-- -NULL +Deprecated: is_json(): Passing null to parameter #1 ($json) of type string is deprecated in %s on line %d bool(false) -------------------- -NULL bool(false) -------------------- -NULL bool(false) -------------------- -NULL bool(false) -------------------- -NULL bool(false) -------------------- -NULL bool(false) -------------------- - -Deprecated: json_decode(): Passing null to parameter #1 ($json) of type string is deprecated in %s on line %d - -Deprecated: is_json(): Passing null to parameter #1 ($json) of type string is deprecated in %s on line %d -NULL bool(false) -------------------- -object(stdClass)#2 (1) { - ["test"]=> - object(stdClass)#1 (1) { - ["foo"]=> - string(3) "bar" - } -} bool(true) -------------------- -object(stdClass)#1 (1) { - ["test"]=> - object(stdClass)#2 (1) { - ["foo"]=> - string(0) "" - } -} bool(true) -------------------- -object(stdClass)#2 (1) { - [""]=> - object(stdClass)#1 (1) { - ["foo"]=> - string(0) "" - } -} bool(true) -------------------- -object(stdClass)#1 (1) { - [""]=> - object(stdClass)#2 (1) { - [""]=> - string(0) "" - } -} bool(true) -------------------- -NULL bool(false) -------------------- -NULL -bool(false) \ No newline at end of file +bool(false) +bool(true) +bool(true) +bool(false) From a9a037da71a8a19c67294314e68a73b7cbfb7a39 Mon Sep 17 00:00:00 2001 From: jcm Date: Wed, 17 Aug 2022 14:45:23 +0200 Subject: [PATCH 04/25] Fix num-args - tests for validation and error handling --- ext/json/json.c | 2 +- ext/json/tests/is_json_001.phpt | 2 -- ext/json/tests/is_json_002.phpt | 37 +++++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 ext/json/tests/is_json_002.phpt diff --git a/ext/json/json.c b/ext/json/json.c index c6b6f79c2ff13..402df95564c2e 100644 --- a/ext/json/json.c +++ b/ext/json/json.c @@ -249,7 +249,7 @@ PHP_FUNCTION(is_json) zend_long depth = PHP_JSON_PARSER_DEFAULT_DEPTH; zend_long options = 0; - ZEND_PARSE_PARAMETERS_START(1, 2) + ZEND_PARSE_PARAMETERS_START(1, 3) Z_PARAM_STRING(str, str_len) Z_PARAM_OPTIONAL Z_PARAM_LONG(depth) diff --git a/ext/json/tests/is_json_001.phpt b/ext/json/tests/is_json_001.phpt index ed49ad7ab0f7f..38d77f7f92da9 100644 --- a/ext/json/tests/is_json_001.phpt +++ b/ext/json/tests/is_json_001.phpt @@ -9,7 +9,6 @@ var_dump( is_json(";"), is_json("руссиш"), is_json("blah"), - is_json(NULL), is_json('{ "test": { "foo": "bar" } }'), is_json('{ "test": { "foo": "" } }'), is_json('{ "": { "foo": "" } }'), @@ -23,7 +22,6 @@ var_dump( ?> --EXPECTF-- -Deprecated: is_json(): Passing null to parameter #1 ($json) of type string is deprecated in %s on line %d bool(false) bool(false) bool(false) diff --git a/ext/json/tests/is_json_002.phpt b/ext/json/tests/is_json_002.phpt new file mode 100644 index 0000000000000..dd5103079cfa4 --- /dev/null +++ b/ext/json/tests/is_json_002.phpt @@ -0,0 +1,37 @@ +--TEST-- +is_json() - Error handling +--FILE-- +getMessage() . PHP_EOL; +} + +try { + var_dump(is_json("-", PHP_INT_MAX)); +} catch (Error $error) { + echo $error->getMessage() . PHP_EOL; +} + +var_dump(is_json('{"key1":"value1", "key2":"value2"}', 1), is_json('{"key1":"value1", "key2":"value2"}', 2)); + +try { + var_dump(is_json("-", 512, JSON_BIGINT_AS_STRING)); +} catch (Error $error) { + echo $error->getMessage() . PHP_EOL; +} +?> + +--EXPECTF-- +Deprecated: is_json(): Passing null to parameter #1 ($json) of type string is deprecated in %s on line %d +bool(false) +bool(false) +bool(false) +is_json(): Argument #2 ($depth) must be greater than 0 +is_json(): Argument #2 ($depth) must be less than %d +bool(false) +bool(true) +is_json(): Argument #3 ($flags) must be a valid flag (JSON_THROW_ON_ERROR, JSON_INVALID_UTF8_IGNORE) From 12f875b4f29a1d2883dcdcd578d9603e68725262 Mon Sep 17 00:00:00 2001 From: jcm Date: Wed, 17 Aug 2022 15:55:51 +0200 Subject: [PATCH 05/25] constants value fix --- ext/json/php_json.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/json/php_json.h b/ext/json/php_json.h index 0ba152725b5f0..95149cf40d3a9 100644 --- a/ext/json/php_json.h +++ b/ext/json/php_json.h @@ -74,10 +74,10 @@ typedef enum { /* is_json(), json_decode() and json_encode() common options */ #define PHP_JSON_INVALID_UTF8_IGNORE (1<<20) -#define PHP_JSON_THROW_ON_ERROR (1<<21) +#define PHP_JSON_THROW_ON_ERROR (1<<22) /* json_decode() and json_encode() common options */ -#define PHP_JSON_INVALID_UTF8_SUBSTITUTE (1<<22) +#define PHP_JSON_INVALID_UTF8_SUBSTITUTE (1<<21) /* is_json() internal option only */ #define PHP_JSON_VALIDATE_ONLY (1<<23) From b516ad6297a824e977f3a96bb19e142bbbea9c3a Mon Sep 17 00:00:00 2001 From: jcm Date: Wed, 17 Aug 2022 15:56:03 +0200 Subject: [PATCH 06/25] Fix test general usage --- ext/json/tests/is_json_001.phpt | 1 - 1 file changed, 1 deletion(-) diff --git a/ext/json/tests/is_json_001.phpt b/ext/json/tests/is_json_001.phpt index 38d77f7f92da9..ee85f151188a2 100644 --- a/ext/json/tests/is_json_001.phpt +++ b/ext/json/tests/is_json_001.phpt @@ -28,7 +28,6 @@ bool(false) bool(false) bool(false) bool(false) -bool(false) bool(true) bool(true) bool(true) From bee4af4ae383a6d5ae243b0284b00265429eb90e Mon Sep 17 00:00:00 2001 From: jcm Date: Wed, 17 Aug 2022 15:56:22 +0200 Subject: [PATCH 07/25] Enhanced tests for error situations --- ext/json/tests/is_json_002.phpt | 74 ++++++++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 2 deletions(-) diff --git a/ext/json/tests/is_json_002.phpt b/ext/json/tests/is_json_002.phpt index dd5103079cfa4..0700eac16bda9 100644 --- a/ext/json/tests/is_json_002.phpt +++ b/ext/json/tests/is_json_002.phpt @@ -2,36 +2,106 @@ is_json() - Error handling --FILE-- getMessage() . PHP_EOL; + var_dump(json_last_error(), json_last_error_msg()); } try { var_dump(is_json("-", PHP_INT_MAX)); } catch (Error $error) { echo $error->getMessage() . PHP_EOL; + var_dump(json_last_error(), json_last_error_msg()); } -var_dump(is_json('{"key1":"value1", "key2":"value2"}', 1), is_json('{"key1":"value1", "key2":"value2"}', 2)); +var_dump( + is_json('{"key1":"value1", "key2":"value2"}', 1), + json_last_error(), json_last_error_msg(), + + is_json('{"key1":"value1", "key2":"value2"}', 2), + json_last_error(), json_last_error_msg() +); try { var_dump(is_json("-", 512, JSON_BIGINT_AS_STRING)); } catch (Error $error) { echo $error->getMessage() . PHP_EOL; + var_dump(json_last_error(), json_last_error_msg()); +} + +try { + is_json("-", 512, JSON_THROW_ON_ERROR); +} catch (Exception $exception) { + echo $exception->getMessage() . PHP_EOL; + var_dump( + json_last_error(), + json_last_error_msg() + ); } + +var_dump( + is_json("\"a\xb0b\""), + is_json("\"a\xd0\xf2b\""), + is_json("\"\x61\xf0\x80\x80\x41\""), + is_json("[\"\xc1\xc1\",\"a\"]"), + + is_json("\"a\xb0b\"", 512, JSON_INVALID_UTF8_IGNORE), + is_json("\"a\xd0\xf2b\"", 512, JSON_INVALID_UTF8_IGNORE), + is_json("\"\x61\xf0\x80\x80\x41\"", 512, JSON_INVALID_UTF8_IGNORE), + is_json("[\"\xc1\xc1\",\"a\"]", 512, JSON_INVALID_UTF8_IGNORE), +); ?> --EXPECTF-- Deprecated: is_json(): Passing null to parameter #1 ($json) of type string is deprecated in %s on line %d bool(false) +int(4) +string(12) "Syntax error" bool(false) +int(4) +string(12) "Syntax error" bool(false) +int(4) +string(12) "Syntax error" is_json(): Argument #2 ($depth) must be greater than 0 +int(0) +string(8) "No error" is_json(): Argument #2 ($depth) must be less than %d +int(0) +string(8) "No error" bool(false) +int(1) +string(28) "Maximum stack depth exceeded" bool(true) +int(0) +string(8) "No error" is_json(): Argument #3 ($flags) must be a valid flag (JSON_THROW_ON_ERROR, JSON_INVALID_UTF8_IGNORE) +int(0) +string(8) "No error" +Syntax error +int(0) +string(8) "No error" +bool(false) +bool(false) +bool(false) +bool(false) +bool(true) +bool(true) +bool(true) +bool(true) From 72cc3301e76e8ece07367a275f8e039b2965250c Mon Sep 17 00:00:00 2001 From: jcm Date: Wed, 17 Aug 2022 16:41:10 +0200 Subject: [PATCH 08/25] Resolve merge conflicts --- ext/json/json_parser.y | 1 + 1 file changed, 1 insertion(+) diff --git a/ext/json/json_parser.y b/ext/json/json_parser.y index 96ec1ec5765e9..f184ca51bb520 100644 --- a/ext/json/json_parser.y +++ b/ext/json/json_parser.y @@ -87,6 +87,7 @@ start: ZVAL_COPY_VALUE(parser->return_value, &$1); } + (void) php_json_yynerrs; YYACCEPT; } ; From d2bb65564cde6f0aae5234d5c08406daac4e8bce Mon Sep 17 00:00:00 2001 From: jcm Date: Wed, 17 Aug 2022 19:42:45 +0200 Subject: [PATCH 09/25] Generate json_arginfo.h - OMG! --- ext/json/json_arginfo.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/json/json_arginfo.h b/ext/json/json_arginfo.h index e9169804a4fdc..3530bf12367c6 100644 --- a/ext/json/json_arginfo.h +++ b/ext/json/json_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: a0669aae151188f14deeda48c4f2d29d0d06ecec */ + * Stub hash: 83310b1415a30a6593cef4e0b27f3f323fea5a8b */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_json_encode, 0, 1, MAY_BE_STRING|MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0) From 4b33d7491a253795f0c5a1acb236e81c7f222b65 Mon Sep 17 00:00:00 2001 From: jcm Date: Fri, 19 Aug 2022 11:44:28 +0200 Subject: [PATCH 10/25] null callbacks for parser methods --- ext/json/json.c | 9 ++-- ext/json/json_parser.y | 89 ++++++++++++++++++++------------------ ext/json/php_json.h | 3 -- ext/json/php_json_parser.h | 3 +- sapi/fuzzer/fuzzer-json.c | 2 +- 5 files changed, 54 insertions(+), 52 deletions(-) diff --git a/ext/json/json.c b/ext/json/json.c index 402df95564c2e..24bdfdf3c49b1 100644 --- a/ext/json/json.c +++ b/ext/json/json.c @@ -162,7 +162,7 @@ PHP_JSON_API zend_result php_json_decode_ex(zval *return_value, const char *str, { php_json_parser parser; - php_json_parser_init(&parser, return_value, str, str_len, (int)options, (int)depth); + php_json_parser_init(&parser, return_value, str, str_len, (int)options, (int)depth, NULL); if (php_json_yyparse(&parser)) { php_json_error_code error_code = php_json_parser_error_code(&parser); @@ -183,10 +183,11 @@ PHP_JSON_API zend_result php_json_decode_ex(zval *return_value, const char *str, PHP_JSON_API zend_result php_is_json_ex(zval *return_value, const char *str, size_t str_len, zend_long options, zend_long depth) { php_json_parser parser; - - options |= PHP_JSON_VALIDATE_ONLY; - php_json_parser_init(&parser, return_value, str, str_len, (int)options, (int)depth); + + static const php_json_parser_methods parser_methods = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; + + php_json_parser_init(&parser, return_value, str, str_len, (int)options, (int)depth, &parser_methods); if (php_json_yyparse(&parser)) { php_json_error_code error_code = php_json_parser_error_code(&parser); diff --git a/ext/json/json_parser.y b/ext/json/json_parser.y index f184ca51bb520..b719103977c17 100644 --- a/ext/json/json_parser.y +++ b/ext/json/json_parser.y @@ -79,14 +79,7 @@ start: value PHP_JSON_T_EOI { ZVAL_COPY_VALUE(&$$, &$1); - - if (parser->scanner.options & PHP_JSON_VALIDATE_ONLY) { - zval_ptr_dtor(parser->return_value); - ZVAL_BOOL(parser->return_value, true); - } else { - ZVAL_COPY_VALUE(parser->return_value, &$1); - } - + ZVAL_COPY_VALUE(parser->return_value, &$1); (void) php_json_yynerrs; YYACCEPT; } @@ -122,10 +115,12 @@ object_end: members: %empty { - if ((parser->scanner.options & PHP_JSON_OBJECT_AS_ARRAY) && parser->methods.object_create == php_json_parser_object_create) { - ZVAL_EMPTY_ARRAY(&$$); - } else { - parser->methods.object_create(parser, &$$); + if (parser->methods.object_create) { + if ((parser->scanner.options & PHP_JSON_OBJECT_AS_ARRAY) && parser->methods.object_create == php_json_parser_object_create) { + ZVAL_EMPTY_ARRAY(&$$); + } else { + parser->methods.object_create(parser, &$$); + } } } | member @@ -134,14 +129,17 @@ members: member: key ':' value { - parser->methods.object_create(parser, &$$); - if (parser->methods.object_update(parser, &$$, Z_STR($1), &$3) == FAILURE) { + if (parser->methods.object_create) { + parser->methods.object_create(parser, &$$); + } + + if (parser->methods.object_update && parser->methods.object_update(parser, &$$, Z_STR($1), &$3) == FAILURE) { YYERROR; } } | member ',' key ':' value { - if (parser->methods.object_update(parser, &$1, Z_STR($3), &$5) == FAILURE) { + if (parser->methods.object_update && parser->methods.object_update(parser, &$1, Z_STR($3), &$5) == FAILURE) { YYERROR; } ZVAL_COPY_VALUE(&$$, &$1); @@ -178,10 +176,12 @@ array_end: elements: %empty { - if (parser->methods.array_create == php_json_parser_array_create) { - ZVAL_EMPTY_ARRAY(&$$); - } else { - parser->methods.array_create(parser, &$$); + if (parser->methods.array_create) { + if (parser->methods.array_create == php_json_parser_array_create) { + ZVAL_EMPTY_ARRAY(&$$); + } else { + parser->methods.array_create(parser, &$$); + } } } | element @@ -190,13 +190,20 @@ elements: element: value { - parser->methods.array_create(parser, &$$); - parser->methods.array_append(parser, &$$, &$1); + if (parser->methods.array_create) { + parser->methods.array_create(parser, &$$); + } + + if (parser->methods.array_append) { + parser->methods.array_append(parser, &$$, &$1); + } } | element ',' value { - parser->methods.array_append(parser, &$1, &$3); - ZVAL_COPY_VALUE(&$$, &$1); + if (parser->methods.array_append) { + parser->methods.array_append(parser, &$1, &$3); + ZVAL_COPY_VALUE(&$$, &$1); + } } ; @@ -221,30 +228,18 @@ value: static int php_json_parser_array_create(php_json_parser *parser, zval *array) { - if (parser->scanner.options & PHP_JSON_VALIDATE_ONLY) { - return SUCCESS; - } - array_init(array); return SUCCESS; } static int php_json_parser_array_append(php_json_parser *parser, zval *array, zval *zvalue) { - if (parser->scanner.options & PHP_JSON_VALIDATE_ONLY) { - return SUCCESS; - } - zend_hash_next_index_insert(Z_ARRVAL_P(array), zvalue); return SUCCESS; } static int php_json_parser_object_create(php_json_parser *parser, zval *object) { - if (parser->scanner.options & PHP_JSON_VALIDATE_ONLY) { - return SUCCESS; - } - if (parser->scanner.options & PHP_JSON_OBJECT_AS_ARRAY) { array_init(object); } else { @@ -255,10 +250,6 @@ static int php_json_parser_object_create(php_json_parser *parser, zval *object) static int php_json_parser_object_update(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue) { - if (parser->scanner.options & PHP_JSON_VALIDATE_ONLY) { - return SUCCESS; - } - /* if JSON_OBJECT_AS_ARRAY is set */ if (Z_TYPE_P(object) == IS_ARRAY) { zend_symtable_update(Z_ARRVAL_P(object), key, zvalue); @@ -282,8 +273,15 @@ static int php_json_yylex(union YYSTYPE *value, php_json_parser *parser) { int token = php_json_scan(&parser->scanner); value->value = parser->scanner.value; - - if (parser->scanner.options & PHP_JSON_VALIDATE_ONLY) { + + if (!parser->methods.array_create + && !parser->methods.array_append + && !parser->methods.array_start + && !parser->methods.array_end + && !parser->methods.object_create + && !parser->methods.object_update + && !parser->methods.object_start + && !parser->methods.object_end) { zval_ptr_dtor_str(&(parser->scanner.value)); } @@ -335,8 +333,13 @@ PHP_JSON_API void php_json_parser_init(php_json_parser *parser, const char *str, size_t str_len, int options, - int max_depth) + int max_depth, + const php_json_parser_methods *parser_methods) { + if (parser_methods == NULL) { + parser_methods = &default_parser_methods; + } + php_json_parser_init_ex( parser, return_value, @@ -344,7 +347,7 @@ PHP_JSON_API void php_json_parser_init(php_json_parser *parser, str_len, options, max_depth, - &default_parser_methods); + parser_methods); } PHP_JSON_API int php_json_parse(php_json_parser *parser) diff --git a/ext/json/php_json.h b/ext/json/php_json.h index 95149cf40d3a9..d0c027b7f882c 100644 --- a/ext/json/php_json.h +++ b/ext/json/php_json.h @@ -79,9 +79,6 @@ typedef enum { /* json_decode() and json_encode() common options */ #define PHP_JSON_INVALID_UTF8_SUBSTITUTE (1<<21) -/* is_json() internal option only */ -#define PHP_JSON_VALIDATE_ONLY (1<<23) - /* Internal flags */ #define PHP_JSON_OUTPUT_ARRAY 0 #define PHP_JSON_OUTPUT_OBJECT 1 diff --git a/ext/json/php_json_parser.h b/ext/json/php_json_parser.h index c17cf708d35a5..3a86b77dcb8df 100644 --- a/ext/json/php_json_parser.h +++ b/ext/json/php_json_parser.h @@ -73,7 +73,8 @@ PHP_JSON_API void php_json_parser_init( const char *str, size_t str_len, int options, - int max_depth); + int max_depth, + const php_json_parser_methods *parser_methods); PHP_JSON_API php_json_error_code php_json_parser_error_code(const php_json_parser *parser); diff --git a/sapi/fuzzer/fuzzer-json.c b/sapi/fuzzer/fuzzer-json.c index 4335598bc3caa..10511e53ce3dd 100644 --- a/sapi/fuzzer/fuzzer-json.c +++ b/sapi/fuzzer/fuzzer-json.c @@ -42,7 +42,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { for (int option = 0; option <=1; ++option) { zval result; php_json_parser parser; - php_json_parser_init(&parser, &result, data, Size, option, 10); + php_json_parser_init(&parser, &result, data, Size, option, 10, NULL); if (php_json_yyparse(&parser) == SUCCESS) { zval_ptr_dtor(&result); } From 3e41de8a6dcf0f60d95d089c7851da47b62acbee Mon Sep 17 00:00:00 2001 From: jcm Date: Fri, 19 Aug 2022 12:18:42 +0200 Subject: [PATCH 11/25] parser - keep ZVAL_COPY_VALUE out of function exists check --- ext/json/json_parser.y | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/json/json_parser.y b/ext/json/json_parser.y index b719103977c17..aa8d18c6a5cee 100644 --- a/ext/json/json_parser.y +++ b/ext/json/json_parser.y @@ -202,8 +202,8 @@ element: { if (parser->methods.array_append) { parser->methods.array_append(parser, &$1, &$3); - ZVAL_COPY_VALUE(&$$, &$1); } + ZVAL_COPY_VALUE(&$$, &$1); } ; From a21e54d19583dcad611d100c831de966ed22bc89 Mon Sep 17 00:00:00 2001 From: jcm Date: Fri, 19 Aug 2022 16:47:33 +0200 Subject: [PATCH 12/25] Add output to test 002 --- ext/json/tests/is_json_002.phpt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ext/json/tests/is_json_002.phpt b/ext/json/tests/is_json_002.phpt index 0700eac16bda9..ee7e1ad0b55cb 100644 --- a/ext/json/tests/is_json_002.phpt +++ b/ext/json/tests/is_json_002.phpt @@ -55,6 +55,8 @@ try { ); } +echo "Testing Invalid UTF-8".PHP_EOL; + var_dump( is_json("\"a\xb0b\""), is_json("\"a\xd0\xf2b\""), From ffe1e53d4c8c157921547534c1782b43e2026319 Mon Sep 17 00:00:00 2001 From: jcm Date: Fri, 19 Aug 2022 16:55:37 +0200 Subject: [PATCH 13/25] 002 test changed --- ext/json/tests/is_json_002.phpt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ext/json/tests/is_json_002.phpt b/ext/json/tests/is_json_002.phpt index ee7e1ad0b55cb..e2a9fa7ea1258 100644 --- a/ext/json/tests/is_json_002.phpt +++ b/ext/json/tests/is_json_002.phpt @@ -55,7 +55,7 @@ try { ); } -echo "Testing Invalid UTF-8".PHP_EOL; +echo PHP_EOL . "Testing Invalid UTF-8" . PHP_EOL; var_dump( is_json("\"a\xb0b\""), @@ -71,7 +71,7 @@ var_dump( ?> --EXPECTF-- -Deprecated: is_json(): Passing null to parameter #1 ($json) of type string is deprecated in %s on line %d +Deprecated: is_json(): Passing null to parameter #1 ($json) of type string is deprecated in /home/jumorales/dev/php-src/ext/json/tests/is_json_002.php on line 3 bool(false) int(4) string(12) "Syntax error" @@ -84,7 +84,7 @@ string(12) "Syntax error" is_json(): Argument #2 ($depth) must be greater than 0 int(0) string(8) "No error" -is_json(): Argument #2 ($depth) must be less than %d +is_json(): Argument #2 ($depth) must be less than 2147483647 int(0) string(8) "No error" bool(false) @@ -99,6 +99,8 @@ string(8) "No error" Syntax error int(0) string(8) "No error" + +Testing Invalid UTF-8 bool(false) bool(false) bool(false) From 87b11d6d3a9556d6617ab52b5200ff7871548078 Mon Sep 17 00:00:00 2001 From: jcm Date: Fri, 19 Aug 2022 17:11:50 +0200 Subject: [PATCH 14/25] - --- ext/json/tests/is_json_002.phpt | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/ext/json/tests/is_json_002.phpt b/ext/json/tests/is_json_002.phpt index e2a9fa7ea1258..9e6bdc607c00d 100644 --- a/ext/json/tests/is_json_002.phpt +++ b/ext/json/tests/is_json_002.phpt @@ -57,7 +57,7 @@ try { echo PHP_EOL . "Testing Invalid UTF-8" . PHP_EOL; -var_dump( +/*var_dump( is_json("\"a\xb0b\""), is_json("\"a\xd0\xf2b\""), is_json("\"\x61\xf0\x80\x80\x41\""), @@ -67,11 +67,11 @@ var_dump( is_json("\"a\xd0\xf2b\"", 512, JSON_INVALID_UTF8_IGNORE), is_json("\"\x61\xf0\x80\x80\x41\"", 512, JSON_INVALID_UTF8_IGNORE), is_json("[\"\xc1\xc1\",\"a\"]", 512, JSON_INVALID_UTF8_IGNORE), -); +);*/ ?> --EXPECTF-- -Deprecated: is_json(): Passing null to parameter #1 ($json) of type string is deprecated in /home/jumorales/dev/php-src/ext/json/tests/is_json_002.php on line 3 +Deprecated: is_json(): Passing null to parameter #1 ($json) of type string is deprecated in %s on line %d bool(false) int(4) string(12) "Syntax error" @@ -101,11 +101,3 @@ int(0) string(8) "No error" Testing Invalid UTF-8 -bool(false) -bool(false) -bool(false) -bool(false) -bool(true) -bool(true) -bool(true) -bool(true) From 56a073b2d1fc530e75110662f554ee00d4f41fb3 Mon Sep 17 00:00:00 2001 From: jcm Date: Fri, 19 Aug 2022 17:37:02 +0200 Subject: [PATCH 15/25] - --- ext/json/tests/is_json_002.phpt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/json/tests/is_json_002.phpt b/ext/json/tests/is_json_002.phpt index 9e6bdc607c00d..222ec2aeddb9e 100644 --- a/ext/json/tests/is_json_002.phpt +++ b/ext/json/tests/is_json_002.phpt @@ -55,7 +55,7 @@ try { ); } -echo PHP_EOL . "Testing Invalid UTF-8" . PHP_EOL; +echo PHP_EOL . "Testing Invalid UTF-8-" . PHP_EOL; /*var_dump( is_json("\"a\xb0b\""), @@ -100,4 +100,4 @@ Syntax error int(0) string(8) "No error" -Testing Invalid UTF-8 +Testing Invalid UTF-8- From ac0b88035b71b06c0e46f24c594fdccbfa790a61 Mon Sep 17 00:00:00 2001 From: Juan Morales Date: Fri, 19 Aug 2022 21:16:30 +0200 Subject: [PATCH 16/25] Update expected output --- ext/json/tests/is_json_002.phpt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/json/tests/is_json_002.phpt b/ext/json/tests/is_json_002.phpt index 222ec2aeddb9e..9e6bdc607c00d 100644 --- a/ext/json/tests/is_json_002.phpt +++ b/ext/json/tests/is_json_002.phpt @@ -55,7 +55,7 @@ try { ); } -echo PHP_EOL . "Testing Invalid UTF-8-" . PHP_EOL; +echo PHP_EOL . "Testing Invalid UTF-8" . PHP_EOL; /*var_dump( is_json("\"a\xb0b\""), @@ -100,4 +100,4 @@ Syntax error int(0) string(8) "No error" -Testing Invalid UTF-8- +Testing Invalid UTF-8 From 6ca699182e182c70868dc79d811206f1feef32f7 Mon Sep 17 00:00:00 2001 From: jcm Date: Sat, 20 Aug 2022 08:51:08 +0200 Subject: [PATCH 17/25] updated 002 test --- ext/json/tests/is_json_002.phpt | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/ext/json/tests/is_json_002.phpt b/ext/json/tests/is_json_002.phpt index 9e6bdc607c00d..f257ec316968c 100644 --- a/ext/json/tests/is_json_002.phpt +++ b/ext/json/tests/is_json_002.phpt @@ -47,7 +47,7 @@ try { try { is_json("-", 512, JSON_THROW_ON_ERROR); -} catch (Exception $exception) { +} catch (JsonException $exception) { echo $exception->getMessage() . PHP_EOL; var_dump( json_last_error(), @@ -55,8 +55,20 @@ try { ); } -echo PHP_EOL . "Testing Invalid UTF-8" . PHP_EOL; +try { + is_json("-", 512, JSON_THROW_ON_ERROR); +} catch (JsonException $exception) { + echo $exception->getMessage() . PHP_EOL; + var_dump( + json_last_error(), + json_last_error_msg() + ); +} +echo PHP_EOL . "Testing Invalid UTF-8" . PHP_EOL; +var_dump( + is_json("\"a\xb0b\"") +); /*var_dump( is_json("\"a\xb0b\""), is_json("\"a\xd0\xf2b\""), @@ -99,5 +111,9 @@ string(8) "No error" Syntax error int(0) string(8) "No error" +Syntax error +int(0) +string(8) "No error" Testing Invalid UTF-8 +bool(false) From eeb59b3c060082ccb75652e3a54b6e5468487ace Mon Sep 17 00:00:00 2001 From: jcm Date: Sat, 20 Aug 2022 11:11:28 +0200 Subject: [PATCH 18/25] refactor - set 1 --- ext/json/json.c | 11 ++- ext/json/tests/is_json_001.phpt | 16 ++-- ext/json/tests/is_json_002.phpt | 137 +++++++++++----------------- ext/json/tests/is_json_003.phpt | 19 ++++ ext/json/tests/is_json_004.phpt | 81 ++++++++++++++++ ext/json/tests/is_json_requires.inc | 17 ++++ 6 files changed, 185 insertions(+), 96 deletions(-) create mode 100644 ext/json/tests/is_json_003.phpt create mode 100644 ext/json/tests/is_json_004.phpt create mode 100644 ext/json/tests/is_json_requires.inc diff --git a/ext/json/json.c b/ext/json/json.c index 24bdfdf3c49b1..c3f91fda94721 100644 --- a/ext/json/json.c +++ b/ext/json/json.c @@ -257,15 +257,18 @@ PHP_FUNCTION(is_json) Z_PARAM_LONG(options) ZEND_PARSE_PARAMETERS_END(); - if ((options != 0) - && (!(options & PHP_JSON_THROW_ON_ERROR) && !(options & PHP_JSON_INVALID_UTF8_IGNORE))) { - zend_argument_value_error(3, "must be a valid flag (JSON_THROW_ON_ERROR, JSON_INVALID_UTF8_IGNORE)"); - RETURN_THROWS(); + if (options != 0) { + if (!(options &= (PHP_JSON_THROW_ON_ERROR | PHP_JSON_INVALID_UTF8_IGNORE))) { + zend_argument_value_error(3, "must be a valid flag (JSON_THROW_ON_ERROR, JSON_INVALID_UTF8_IGNORE)"); + RETURN_THROWS(); + } } if (!str_len) { if (!(options & PHP_JSON_THROW_ON_ERROR)) { JSON_G(error_code) = PHP_JSON_ERROR_SYNTAX; + } else { + zend_throw_exception(php_json_exception_ce, php_json_get_error_msg(PHP_JSON_ERROR_SYNTAX), PHP_JSON_ERROR_SYNTAX); } RETURN_FALSE; diff --git a/ext/json/tests/is_json_001.phpt b/ext/json/tests/is_json_001.phpt index ee85f151188a2..7de79e9f6e81f 100644 --- a/ext/json/tests/is_json_001.phpt +++ b/ext/json/tests/is_json_001.phpt @@ -2,6 +2,7 @@ is_json() - General usage --FILE-- +?> --EXPECTF-- bool(false) bool(false) @@ -28,12 +30,12 @@ bool(false) bool(false) bool(false) bool(false) +bool(false) +bool(false) +bool(false) bool(true) bool(true) bool(true) bool(true) -bool(false) -bool(false) bool(true) bool(true) -bool(false) diff --git a/ext/json/tests/is_json_002.phpt b/ext/json/tests/is_json_002.phpt index f257ec316968c..68fcb3660d05d 100644 --- a/ext/json/tests/is_json_002.phpt +++ b/ext/json/tests/is_json_002.phpt @@ -2,87 +2,35 @@ is_json() - Error handling --FILE-- getMessage() . PHP_EOL; - var_dump(json_last_error(), json_last_error_msg()); -} +echo "*** Flag JSON_THROW_ON_ERROR Off" . PHP_EOL; -try { - var_dump(is_json("-", PHP_INT_MAX)); -} catch (Error $error) { - echo $error->getMessage() . PHP_EOL; - var_dump(json_last_error(), json_last_error_msg()); -} +is_json_trycatchdump(null); +is_json_trycatchdump(""); +is_json_trycatchdump("-"); +is_json_trycatchdump("", -1); +is_json_trycatchdump('{"key1":"value1", "key2":"value2"}', 1); +is_json_trycatchdump('{"key1":"value1", "key2":"value2"}', 2); +is_json_trycatchdump("-", 0); +is_json_trycatchdump("-", 512, JSON_BIGINT_AS_STRING); -var_dump( - is_json('{"key1":"value1", "key2":"value2"}', 1), - json_last_error(), json_last_error_msg(), +echo PHP_EOL . "*** Flag JSON_THROW_ON_ERROR On" . PHP_EOL; - is_json('{"key1":"value1", "key2":"value2"}', 2), - json_last_error(), json_last_error_msg() -); +is_json_trycatchdump(null, 512, JSON_THROW_ON_ERROR); +is_json_trycatchdump("", 512, JSON_THROW_ON_ERROR); +is_json_trycatchdump("-", 512, JSON_THROW_ON_ERROR); +is_json_trycatchdump("", -1, JSON_THROW_ON_ERROR); +is_json_trycatchdump('{"key1":"value1", "key2":"value2"}', 1, JSON_THROW_ON_ERROR); +is_json_trycatchdump('{"key1":"value1", "key2":"value2"}', 2, JSON_THROW_ON_ERROR); +is_json_trycatchdump("-", 0, JSON_THROW_ON_ERROR); +is_json_trycatchdump("-", 512, JSON_THROW_ON_ERROR | JSON_BIGINT_AS_STRING); -try { - var_dump(is_json("-", 512, JSON_BIGINT_AS_STRING)); -} catch (Error $error) { - echo $error->getMessage() . PHP_EOL; - var_dump(json_last_error(), json_last_error_msg()); -} - -try { - is_json("-", 512, JSON_THROW_ON_ERROR); -} catch (JsonException $exception) { - echo $exception->getMessage() . PHP_EOL; - var_dump( - json_last_error(), - json_last_error_msg() - ); -} - -try { - is_json("-", 512, JSON_THROW_ON_ERROR); -} catch (JsonException $exception) { - echo $exception->getMessage() . PHP_EOL; - var_dump( - json_last_error(), - json_last_error_msg() - ); -} - -echo PHP_EOL . "Testing Invalid UTF-8" . PHP_EOL; -var_dump( - is_json("\"a\xb0b\"") -); -/*var_dump( - is_json("\"a\xb0b\""), - is_json("\"a\xd0\xf2b\""), - is_json("\"\x61\xf0\x80\x80\x41\""), - is_json("[\"\xc1\xc1\",\"a\"]"), - - is_json("\"a\xb0b\"", 512, JSON_INVALID_UTF8_IGNORE), - is_json("\"a\xd0\xf2b\"", 512, JSON_INVALID_UTF8_IGNORE), - is_json("\"\x61\xf0\x80\x80\x41\"", 512, JSON_INVALID_UTF8_IGNORE), - is_json("[\"\xc1\xc1\",\"a\"]", 512, JSON_INVALID_UTF8_IGNORE), -);*/ ?> - --EXPECTF-- +*** Flag JSON_THROW_ON_ERROR Off + Deprecated: is_json(): Passing null to parameter #1 ($json) of type string is deprecated in %s on line %d bool(false) int(4) @@ -93,27 +41,46 @@ string(12) "Syntax error" bool(false) int(4) string(12) "Syntax error" -is_json(): Argument #2 ($depth) must be greater than 0 -int(0) -string(8) "No error" -is_json(): Argument #2 ($depth) must be less than 2147483647 -int(0) -string(8) "No error" +bool(false) +int(4) +string(12) "Syntax error" bool(false) int(1) string(28) "Maximum stack depth exceeded" bool(true) int(0) string(8) "No error" -is_json(): Argument #3 ($flags) must be a valid flag (JSON_THROW_ON_ERROR, JSON_INVALID_UTF8_IGNORE) +Error: 0 is_json(): Argument #2 ($depth) must be greater than 0 int(0) string(8) "No error" -Syntax error +Error: 0 is_json(): Argument #3 ($flags) must be a valid flag (JSON_THROW_ON_ERROR, JSON_INVALID_UTF8_IGNORE) int(0) string(8) "No error" -Syntax error + +*** Flag JSON_THROW_ON_ERROR On + +Deprecated: is_json(): Passing null to parameter #1 ($json) of type string is deprecated in %s on line %d +JsonException: 4 Syntax error +int(0) +string(8) "No error" +JsonException: 4 Syntax error +int(0) +string(8) "No error" +JsonException: 4 Syntax error +int(0) +string(8) "No error" +JsonException: 4 Syntax error +int(0) +string(8) "No error" +JsonException: 1 Maximum stack depth exceeded +int(0) +string(8) "No error" +bool(true) +int(0) +string(8) "No error" +Error: 0 is_json(): Argument #2 ($depth) must be greater than 0 +int(0) +string(8) "No error" +JsonException: 4 Syntax error int(0) string(8) "No error" - -Testing Invalid UTF-8 -bool(false) diff --git a/ext/json/tests/is_json_003.phpt b/ext/json/tests/is_json_003.phpt new file mode 100644 index 0000000000000..9f6e31ba16313 --- /dev/null +++ b/ext/json/tests/is_json_003.phpt @@ -0,0 +1,19 @@ +--TEST-- +is_json() - Error handling for max depth +--SKIPIF-- + +--FILE-- +getMessage() . PHP_EOL; + var_dump(json_last_error(), json_last_error_msg()); +} + +?> +--EXPECTF-- +is_json(): Argument #2 ($depth) must be less than %d +int(0) +string(8) "No error" diff --git a/ext/json/tests/is_json_004.phpt b/ext/json/tests/is_json_004.phpt new file mode 100644 index 0000000000000..843adcdab6f4b --- /dev/null +++ b/ext/json/tests/is_json_004.phpt @@ -0,0 +1,81 @@ +--TEST-- +is_json() - Invalid UTF-8's +--FILE-- + +--EXPECTF-- +Testing Invalid UTF-8 +bool(false) +int(5) +string(56) "Malformed UTF-8 characters, possibly incorrectly encoded" +bool(false) +int(5) +string(56) "Malformed UTF-8 characters, possibly incorrectly encoded" +bool(false) +int(5) +string(56) "Malformed UTF-8 characters, possibly incorrectly encoded" +bool(false) +int(5) +string(56) "Malformed UTF-8 characters, possibly incorrectly encoded" +JsonException: 5 Malformed UTF-8 characters, possibly incorrectly encoded +int(5) +string(56) "Malformed UTF-8 characters, possibly incorrectly encoded" +JsonException: 5 Malformed UTF-8 characters, possibly incorrectly encoded +int(5) +string(56) "Malformed UTF-8 characters, possibly incorrectly encoded" +JsonException: 5 Malformed UTF-8 characters, possibly incorrectly encoded +int(5) +string(56) "Malformed UTF-8 characters, possibly incorrectly encoded" +JsonException: 5 Malformed UTF-8 characters, possibly incorrectly encoded +int(5) +string(56) "Malformed UTF-8 characters, possibly incorrectly encoded" +bool(true) +int(0) +string(8) "No error" +bool(true) +int(0) +string(8) "No error" +bool(true) +int(0) +string(8) "No error" +bool(true) +int(0) +string(8) "No error" +bool(true) +int(0) +string(8) "No error" +bool(true) +int(0) +string(8) "No error" +bool(true) +int(0) +string(8) "No error" +bool(true) +int(0) +string(8) "No error" diff --git a/ext/json/tests/is_json_requires.inc b/ext/json/tests/is_json_requires.inc new file mode 100644 index 0000000000000..5ef7e97a7dd9f --- /dev/null +++ b/ext/json/tests/is_json_requires.inc @@ -0,0 +1,17 @@ +getCode()} {$e->getMessage()}". PHP_EOL; + } catch (Exception $e) { + echo "Exception: {$e->getCode()} {$e->getMessage()}". PHP_EOL; + } catch (Error $e) { + echo "Error: {$e->getCode()} {$e->getMessage()}". PHP_EOL; + } + + var_dump(json_last_error(), json_last_error_msg()); +} + +?> \ No newline at end of file From 19bd9fcdb6584415ef0f032ac3ed5c0da1f4e1dd Mon Sep 17 00:00:00 2001 From: jcm Date: Sat, 20 Aug 2022 15:18:26 +0200 Subject: [PATCH 19/25] Mute conflicting cases --- ext/json/tests/is_json_004.phpt | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/ext/json/tests/is_json_004.phpt b/ext/json/tests/is_json_004.phpt index 843adcdab6f4b..f485485c6c118 100644 --- a/ext/json/tests/is_json_004.phpt +++ b/ext/json/tests/is_json_004.phpt @@ -10,13 +10,13 @@ echo "Testing Invalid UTF-8" . PHP_EOL; is_json_trycatchdump("\"a\xb0b\""); is_json_trycatchdump("\"a\xd0\xf2b\""); -is_json_trycatchdump("\"\x61\xf0\x80\x80\x41\""); -is_json_trycatchdump("[\"\xc1\xc1\",\"a\"]"); +//is_json_trycatchdump("\"\x61\xf0\x80\x80\x41\""); +//is_json_trycatchdump("[\"\xc1\xc1\",\"a\"]"); is_json_trycatchdump("\"a\xb0b\"", 512, JSON_THROW_ON_ERROR); is_json_trycatchdump("\"a\xd0\xf2b\"", 512, JSON_THROW_ON_ERROR); -is_json_trycatchdump("\"\x61\xf0\x80\x80\x41\"", 512, JSON_THROW_ON_ERROR); -is_json_trycatchdump("[\"\xc1\xc1\",\"a\"]", 512, JSON_THROW_ON_ERROR); +//is_json_trycatchdump("\"\x61\xf0\x80\x80\x41\"", 512, JSON_THROW_ON_ERROR); +//is_json_trycatchdump("[\"\xc1\xc1\",\"a\"]", 512, JSON_THROW_ON_ERROR); is_json_trycatchdump("\"a\xb0b\"", 512, JSON_INVALID_UTF8_IGNORE); is_json_trycatchdump("\"a\xd0\xf2b\"", 512, JSON_INVALID_UTF8_IGNORE); @@ -37,18 +37,6 @@ string(56) "Malformed UTF-8 characters, possibly incorrectly encoded" bool(false) int(5) string(56) "Malformed UTF-8 characters, possibly incorrectly encoded" -bool(false) -int(5) -string(56) "Malformed UTF-8 characters, possibly incorrectly encoded" -bool(false) -int(5) -string(56) "Malformed UTF-8 characters, possibly incorrectly encoded" -JsonException: 5 Malformed UTF-8 characters, possibly incorrectly encoded -int(5) -string(56) "Malformed UTF-8 characters, possibly incorrectly encoded" -JsonException: 5 Malformed UTF-8 characters, possibly incorrectly encoded -int(5) -string(56) "Malformed UTF-8 characters, possibly incorrectly encoded" JsonException: 5 Malformed UTF-8 characters, possibly incorrectly encoded int(5) string(56) "Malformed UTF-8 characters, possibly incorrectly encoded" From b185b70218fca71857fa1ad13a8d7cc28ff3224a Mon Sep 17 00:00:00 2001 From: jcm Date: Sat, 20 Aug 2022 15:49:44 +0200 Subject: [PATCH 20/25] crossing my fingers on this --- ext/json/json_parser.y | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ext/json/json_parser.y b/ext/json/json_parser.y index aa8d18c6a5cee..fa9efe66ef82d 100644 --- a/ext/json/json_parser.y +++ b/ext/json/json_parser.y @@ -121,6 +121,8 @@ members: } else { parser->methods.object_create(parser, &$$); } + } else { + ZVAL_EMPTY_ARRAY(&$$); } } | member @@ -182,6 +184,8 @@ elements: } else { parser->methods.array_create(parser, &$$); } + } else { + ZVAL_EMPTY_ARRAY(&$$); } } | element From a1436ebcc57589049f54f3ef698ab59437f3c5bc Mon Sep 17 00:00:00 2001 From: jcm Date: Sat, 20 Aug 2022 16:08:19 +0200 Subject: [PATCH 21/25] activate problematic tests - keep breathing juan --- ext/json/tests/is_json_004.phpt | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/ext/json/tests/is_json_004.phpt b/ext/json/tests/is_json_004.phpt index f485485c6c118..843adcdab6f4b 100644 --- a/ext/json/tests/is_json_004.phpt +++ b/ext/json/tests/is_json_004.phpt @@ -10,13 +10,13 @@ echo "Testing Invalid UTF-8" . PHP_EOL; is_json_trycatchdump("\"a\xb0b\""); is_json_trycatchdump("\"a\xd0\xf2b\""); -//is_json_trycatchdump("\"\x61\xf0\x80\x80\x41\""); -//is_json_trycatchdump("[\"\xc1\xc1\",\"a\"]"); +is_json_trycatchdump("\"\x61\xf0\x80\x80\x41\""); +is_json_trycatchdump("[\"\xc1\xc1\",\"a\"]"); is_json_trycatchdump("\"a\xb0b\"", 512, JSON_THROW_ON_ERROR); is_json_trycatchdump("\"a\xd0\xf2b\"", 512, JSON_THROW_ON_ERROR); -//is_json_trycatchdump("\"\x61\xf0\x80\x80\x41\"", 512, JSON_THROW_ON_ERROR); -//is_json_trycatchdump("[\"\xc1\xc1\",\"a\"]", 512, JSON_THROW_ON_ERROR); +is_json_trycatchdump("\"\x61\xf0\x80\x80\x41\"", 512, JSON_THROW_ON_ERROR); +is_json_trycatchdump("[\"\xc1\xc1\",\"a\"]", 512, JSON_THROW_ON_ERROR); is_json_trycatchdump("\"a\xb0b\"", 512, JSON_INVALID_UTF8_IGNORE); is_json_trycatchdump("\"a\xd0\xf2b\"", 512, JSON_INVALID_UTF8_IGNORE); @@ -37,6 +37,18 @@ string(56) "Malformed UTF-8 characters, possibly incorrectly encoded" bool(false) int(5) string(56) "Malformed UTF-8 characters, possibly incorrectly encoded" +bool(false) +int(5) +string(56) "Malformed UTF-8 characters, possibly incorrectly encoded" +bool(false) +int(5) +string(56) "Malformed UTF-8 characters, possibly incorrectly encoded" +JsonException: 5 Malformed UTF-8 characters, possibly incorrectly encoded +int(5) +string(56) "Malformed UTF-8 characters, possibly incorrectly encoded" +JsonException: 5 Malformed UTF-8 characters, possibly incorrectly encoded +int(5) +string(56) "Malformed UTF-8 characters, possibly incorrectly encoded" JsonException: 5 Malformed UTF-8 characters, possibly incorrectly encoded int(5) string(56) "Malformed UTF-8 characters, possibly incorrectly encoded" From 4158f92205bfea35d0ed2e2dcbd4b824f3133c81 Mon Sep 17 00:00:00 2001 From: jcm Date: Sun, 21 Aug 2022 14:23:26 +0200 Subject: [PATCH 22/25] QA - is_json() vs json_decode() --- ext/json/tests/is_json_005.phpt | 63 +++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 ext/json/tests/is_json_005.phpt diff --git a/ext/json/tests/is_json_005.phpt b/ext/json/tests/is_json_005.phpt new file mode 100644 index 0000000000000..b83a48192cf97 --- /dev/null +++ b/ext/json/tests/is_json_005.phpt @@ -0,0 +1,63 @@ +--TEST-- +is_json() - Tests is_json() performance +--INI-- +memory_limit=128M +--FILE-- + {$is_json_memory_usage} MB < {$json_decode_memory_usage} MB = ". (($is_json_memory_usage < $json_decode_memory_usage) ? "TRUE" : "FALSE") . PHP_EOL; +echo "is_json() uses less memory peak than json_decode() => {$is_json_memory_peak_usage} MB < {$json_decode_memory_peak_usage} MB = ". (($is_json_memory_peak_usage < $json_decode_memory_peak_usage) ? "TRUE" : "FALSE") . PHP_EOL; +echo "is_json() is faster than json_decode() => {$is_json_time} Seconds < {$json_decode_time} Seconds = ". (((float)$is_json_time < (float)$json_decode_time) ? "TRUE" : "FALSE") . PHP_EOL; + +return; + +?> +--EXPECTF-- +is_json() uses less memory than json_decode() => %d MB < %d MB = TRUE +is_json() uses less memory peak than json_decode() => %d MB < %d MB = TRUE +is_json() is faster than json_decode() => %f Seconds < %f Seconds = TRUE \ No newline at end of file From 669c9fe69787abd991bd055d1acc31004dfe42ea Mon Sep 17 00:00:00 2001 From: jcm Date: Sun, 21 Aug 2022 15:42:29 +0200 Subject: [PATCH 23/25] new line added to test 005 --- ext/json/tests/is_json_005.phpt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/json/tests/is_json_005.phpt b/ext/json/tests/is_json_005.phpt index b83a48192cf97..932fd0cf519b0 100644 --- a/ext/json/tests/is_json_005.phpt +++ b/ext/json/tests/is_json_005.phpt @@ -60,4 +60,4 @@ return; --EXPECTF-- is_json() uses less memory than json_decode() => %d MB < %d MB = TRUE is_json() uses less memory peak than json_decode() => %d MB < %d MB = TRUE -is_json() is faster than json_decode() => %f Seconds < %f Seconds = TRUE \ No newline at end of file +is_json() is faster than json_decode() => %f Seconds < %f Seconds = TRUE From b72c9c41b3870a51e4999652cfe066ca14963f58 Mon Sep 17 00:00:00 2001 From: jcm Date: Sun, 21 Aug 2022 17:21:33 +0200 Subject: [PATCH 24/25] Bug fix when checking valid flags --- ext/json/json.c | 12 +++++++++--- ext/json/tests/is_json_002.phpt | 29 ++++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/ext/json/json.c b/ext/json/json.c index c3f91fda94721..d5f538416a0c8 100644 --- a/ext/json/json.c +++ b/ext/json/json.c @@ -257,10 +257,16 @@ PHP_FUNCTION(is_json) Z_PARAM_LONG(options) ZEND_PARSE_PARAMETERS_END(); + if (options != 0) { - if (!(options &= (PHP_JSON_THROW_ON_ERROR | PHP_JSON_INVALID_UTF8_IGNORE))) { - zend_argument_value_error(3, "must be a valid flag (JSON_THROW_ON_ERROR, JSON_INVALID_UTF8_IGNORE)"); - RETURN_THROWS(); + zend_long tmp_options = options; + tmp_options ^= (PHP_JSON_INVALID_UTF8_IGNORE | PHP_JSON_THROW_ON_ERROR); + + if (tmp_options != 0) { + if (!((tmp_options == PHP_JSON_INVALID_UTF8_IGNORE) || (tmp_options == PHP_JSON_THROW_ON_ERROR))) { + zend_argument_value_error(3, "must be a valid flag (JSON_THROW_ON_ERROR, JSON_INVALID_UTF8_IGNORE)"); + RETURN_THROWS(); + } } } diff --git a/ext/json/tests/is_json_002.phpt b/ext/json/tests/is_json_002.phpt index 68fcb3660d05d..efa7ed299b9eb 100644 --- a/ext/json/tests/is_json_002.phpt +++ b/ext/json/tests/is_json_002.phpt @@ -15,6 +15,9 @@ is_json_trycatchdump('{"key1":"value1", "key2":"value2"}', 1); is_json_trycatchdump('{"key1":"value1", "key2":"value2"}', 2); is_json_trycatchdump("-", 0); is_json_trycatchdump("-", 512, JSON_BIGINT_AS_STRING); +is_json_trycatchdump("-", 512, JSON_BIGINT_AS_STRING | JSON_INVALID_UTF8_IGNORE); +is_json_trycatchdump("-", 512, JSON_INVALID_UTF8_IGNORE); +is_json_trycatchdump("{}", 512, JSON_INVALID_UTF8_IGNORE); echo PHP_EOL . "*** Flag JSON_THROW_ON_ERROR On" . PHP_EOL; @@ -26,7 +29,10 @@ is_json_trycatchdump('{"key1":"value1", "key2":"value2"}', 1, JSON_THROW_ON_ERRO is_json_trycatchdump('{"key1":"value1", "key2":"value2"}', 2, JSON_THROW_ON_ERROR); is_json_trycatchdump("-", 0, JSON_THROW_ON_ERROR); is_json_trycatchdump("-", 512, JSON_THROW_ON_ERROR | JSON_BIGINT_AS_STRING); - +is_json_trycatchdump("-", 512, JSON_THROW_ON_ERROR | JSON_BIGINT_AS_STRING | JSON_INVALID_UTF8_IGNORE); +is_json_trycatchdump("-", 512, JSON_THROW_ON_ERROR | JSON_INVALID_UTF8_IGNORE); +is_json_trycatchdump("{}", 512, JSON_THROW_ON_ERROR | JSON_INVALID_UTF8_IGNORE); +is_json_trycatchdump("{}", 512, JSON_THROW_ON_ERROR); ?> --EXPECTF-- *** Flag JSON_THROW_ON_ERROR Off @@ -56,6 +62,15 @@ string(8) "No error" Error: 0 is_json(): Argument #3 ($flags) must be a valid flag (JSON_THROW_ON_ERROR, JSON_INVALID_UTF8_IGNORE) int(0) string(8) "No error" +Error: 0 is_json(): Argument #3 ($flags) must be a valid flag (JSON_THROW_ON_ERROR, JSON_INVALID_UTF8_IGNORE) +int(0) +string(8) "No error" +bool(false) +int(4) +string(12) "Syntax error" +bool(true) +int(0) +string(8) "No error" *** Flag JSON_THROW_ON_ERROR On @@ -81,6 +96,18 @@ string(8) "No error" Error: 0 is_json(): Argument #2 ($depth) must be greater than 0 int(0) string(8) "No error" +Error: 0 is_json(): Argument #3 ($flags) must be a valid flag (JSON_THROW_ON_ERROR, JSON_INVALID_UTF8_IGNORE) +int(0) +string(8) "No error" +Error: 0 is_json(): Argument #3 ($flags) must be a valid flag (JSON_THROW_ON_ERROR, JSON_INVALID_UTF8_IGNORE) +int(0) +string(8) "No error" JsonException: 4 Syntax error int(0) string(8) "No error" +bool(true) +int(0) +string(8) "No error" +bool(true) +int(0) +string(8) "No error" From a96ebaead63348969c13019672e3123ebc5354bc Mon Sep 17 00:00:00 2001 From: Juan Morales Date: Sun, 21 Aug 2022 20:14:41 +0200 Subject: [PATCH 25/25] Update is_json_requires.inc New line --- ext/json/tests/is_json_requires.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/json/tests/is_json_requires.inc b/ext/json/tests/is_json_requires.inc index 5ef7e97a7dd9f..5f379c44e8d7b 100644 --- a/ext/json/tests/is_json_requires.inc +++ b/ext/json/tests/is_json_requires.inc @@ -14,4 +14,4 @@ function is_json_trycatchdump($json, $depth = 512, $flags = 0) { var_dump(json_last_error(), json_last_error_msg()); } -?> \ No newline at end of file +?>