Skip to content

Commit

Permalink
4.0.0: Fix bugs noticed while writing documentation
Browse files Browse the repository at this point in the history
* Make the `SIMDJSON_ERR_*` constants case-sensitive in all PHP versions.
  (The code it was based on was missing the flag needed to mark constants
  as case sensitive before PHP 8)
* Fix a bug that prevented using JSON pointer in `simdjson_key_count`,
  `simdjson_key_exists`, and `simdjson_key_value` with a leading slash
  https://www.rfc-editor.org/rfc/rfc6901.html.

  Fix a bug that was introduced when working around test failures
  following a change in json pointer validation in the underlying C simdjson library.
* "" in a JSON pointer $key continues to refer to the entire document.
* "/" in a JSON pointer $key now properly refer to the key that is the empty string.
* Continue to allow the non-standard omission of the leading "/" for
  compatibility with earlier PECL releases.
  This may be deprecated in a subsequent release.
  • Loading branch information
TysonAndre committed Oct 19, 2022
1 parent 7e41838 commit 4ac4c44
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 16 deletions.
44 changes: 33 additions & 11 deletions package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,25 @@
<active>yes</active>
</lead>
-->
<date>2022-10-17</date>
<date>2022-10-19</date>
<version>
<release>3.0.0</release>
<api>3.0.0</api>
<release>4.0.0</release>
<api>4.0.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="https://www.apache.org/licenses/LICENSE-2.0.html">Apache 2.0</license>
<notes>
* Add SimdJsonValueError. In php 8.0+, it extends ValueError, and it extends Error in older php versions.
This provides an API similar to the JSON module, which started throwing ValueError for invalid depths in php 8.0.
* Throw SimdJsonValueError instead of emitting notices if $depth is too small or too large in all simdjson PHP functions.
simdjson_is_valid(), simdjson_key_count() and simdjson_key_exists() now have non-null return types.
* Throw a SimdJsonException in simdjson_key_exists on error conditions such as invalid json, to be consistent with other simdjson PHP functions.
* Add an optional boolean `$throw_if_uncountable = false` to simdjson_key_count.
When this is overridden to be true, simdjson_key_count will throw a SimdJsonException if the JSON pointer refers to a value that exists but is neither an array nor an object instead of returning 0.
* Rename the parameter $assoc to $associative in simdjson_decode and simdjson_key_value, to match naming practices used in json_decode()
* Make the `SIMDJSON_ERR_*` constants case-sensitive in all PHP versions.
(The code it was based on was missing the flag needed to mark constants as case sensitive before PHP 8)
* Fix a bug that prevented using JSON pointer in `simdjson_key_count`, `simdjson_key_exists`, and `simdjson_key_value` with a leading slash https://www.rfc-editor.org/rfc/rfc6901.html.

This bug was introduced when working around test failures following a change in json pointer validation in the underlying C simdjson library.
* "" in a JSON pointer continues to refer to the entire document.
* "/" in a JSON pointer now properly refers to the key that is the empty string.
* Continue to allow the non-standard omission of the leading "/" for compatibility with earlier PECL releases. This may be deprecated in a subsequent release.
</notes>
<contents>
<dir name="/">
Expand Down Expand Up @@ -83,6 +83,7 @@
<file name="key_value_exception.phpt" role="test"/>
<file name="key_value_int.phpt" role="test"/>
<file name="key_value_result.phpt" role="test"/>
<file name="key_value_slash.phpt" role="test"/>
<file name="uint64_overflow.phpt" role="test"/>
<file name="_files/result.json" role="test"/>
<dir name="compat">
Expand Down Expand Up @@ -124,6 +125,27 @@
<providesextension>simdjson</providesextension>
<extsrcrelease/>
<changelog>
<release>
<version>
<release>3.0.0</release>
<api>3.0.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="https://www.apache.org/licenses/LICENSE-2.0.html">Apache 2.0</license>
<notes>
* Add SimdJsonValueError. In php 8.0+, it extends ValueError, and it extends Error in older php versions.
This provides an API similar to the JSON module, which started throwing ValueError for invalid depths in php 8.0.
* Throw SimdJsonValueError instead of emitting notices if $depth is too small or too large in all simdjson PHP functions.
simdjson_is_valid(), simdjson_key_count() and simdjson_key_exists() now have non-null return types.
* Throw a SimdJsonException in simdjson_key_exists on error conditions such as invalid json, to be consistent with other simdjson PHP functions.
* Add an optional boolean `$throw_if_uncountable = false` to simdjson_key_count.
When this is overridden to be true, simdjson_key_count will throw a SimdJsonException if the JSON pointer refers to a value that exists but is neither an array nor an object instead of returning 0.
* Rename the parameter $assoc to $associative in simdjson_decode and simdjson_key_value, to match naming practices used in json_decode()
</notes>
</release>
<release>
<date>2022-10-14</date>
<version>
Expand Down
4 changes: 2 additions & 2 deletions php_simdjson.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,8 +244,8 @@ ZEND_TSRMLS_CACHE_UPDATE();

/** {{{ PHP_MINIT_FUNCTION
*/
#define SIMDJSON_REGISTER_ERROR_CODE_CONSTANT(errcode) REGISTER_LONG_CONSTANT("SIMDJSON_ERR_" #errcode, simdjson::errcode, CONST_PERSISTENT)
#define SIMDJSON_REGISTER_CUSTOM_ERROR_CODE_CONSTANT(errcode, val) REGISTER_LONG_CONSTANT("SIMDJSON_ERR_" #errcode, (val), CONST_PERSISTENT)
#define SIMDJSON_REGISTER_ERROR_CODE_CONSTANT(errcode) REGISTER_LONG_CONSTANT("SIMDJSON_ERR_" #errcode, simdjson::errcode, CONST_PERSISTENT | CONST_CS)
#define SIMDJSON_REGISTER_CUSTOM_ERROR_CODE_CONSTANT(errcode, val) REGISTER_LONG_CONSTANT("SIMDJSON_ERR_" #errcode, (val), CONST_PERSISTENT | CONST_CS)
PHP_MINIT_FUNCTION (simdjson) {
simdjson_exception_ce = register_class_SimdJsonException(spl_ce_RuntimeException);
#if PHP_VERSION_ID >= 80000
Expand Down
4 changes: 2 additions & 2 deletions php_simdjson.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,12 @@ BEGIN_EXTERN_C()
extern zend_module_entry simdjson_module_entry;
#define phpext_simdjson_ptr &simdjson_module_entry

#define PHP_SIMDJSON_VERSION "3.0.0"
#define PHP_SIMDJSON_VERSION "4.0.0"
/**
* PHP_SIMDJSON_VERSION_ID has the same format as PHP_VERSION_ID: Major version * 10000 + Minor version * 100 + Patch version.
* This is meant for use by PECL extensions that depend on simdjson.
*/
#define PHP_SIMDJSON_VERSION_ID 30000
#define PHP_SIMDJSON_VERSION_ID 40000

#define SIMDJSON_SUPPORT_URL "https://github.com/crazyxman/simdjson_php"

Expand Down
4 changes: 3 additions & 1 deletion src/simdjson_bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@ PHP_SIMDJSON_API void php_simdjson_throw_jsonexception(simdjson_php_error_code e
static inline simdjson::simdjson_result<simdjson::dom::element>
get_key_with_optional_prefix(simdjson::dom::element &doc, std::string_view json_pointer)
{
auto std_pointer = (json_pointer.empty() ? "" : "/") + std::string(json_pointer.begin(), json_pointer.end());
/* https://www.rfc-editor.org/rfc/rfc6901.html */
/* TODO: Deprecate in a subsequent minor release and remove in a major release to comply with the standard. */
auto std_pointer = ((!json_pointer.empty() && json_pointer[0] != '/') ? "/" : "") + std::string(json_pointer.begin(), json_pointer.end());
return doc.at_pointer(std_pointer);
}

Expand Down
114 changes: 114 additions & 0 deletions tests/key_value_slash.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
--TEST--
simdjson_key_value with int test
--SKIPIF--
<?php if (PHP_VERSION_ID < 70100) echo "skip requires php 7.1+ for empty string as object key\n";
--FILE--
<?php
require_once __DIR__ . '/dump.inc';
$json = '{"":true,"code":123,"values":[{}],"obj":{"z": false}}';
$pointers = [
'/code',
'/',
'',
'/code',
'/code/0',
'/code/x',
'/values',
'/values/0',
'/values/1',
'/values/-1',
'/obj',
'/obj/z',
];
foreach ($pointers as $pointer) {
echo "Test ", var_export($pointer, true), "\n";
dump(function () use ($json, $pointer) { return simdjson_key_value($json, $pointer, false); });
dump(function () use ($json, $pointer) { return simdjson_key_value($json, $pointer, true); });
}

?>
--EXPECT--
Test '/code'
int(123)
int(123)
Test '/'
bool(true)
bool(true)
Test ''
object(stdClass)#2 (4) {
[""]=>
bool(true)
["code"]=>
int(123)
["values"]=>
array(1) {
[0]=>
object(stdClass)#3 (0) {
}
}
["obj"]=>
object(stdClass)#4 (1) {
["z"]=>
bool(false)
}
}
array(4) {
[""]=>
bool(true)
["code"]=>
int(123)
["values"]=>
array(1) {
[0]=>
array(0) {
}
}
["obj"]=>
array(1) {
["z"]=>
bool(false)
}
}
Test '/code'
int(123)
int(123)
Test '/code/0'
Caught SimdJsonException: Invalid JSON pointer syntax.
Caught SimdJsonException: Invalid JSON pointer syntax.
Test '/code/x'
Caught SimdJsonException: Invalid JSON pointer syntax.
Caught SimdJsonException: Invalid JSON pointer syntax.
Test '/values'
array(1) {
[0]=>
object(stdClass)#2 (0) {
}
}
array(1) {
[0]=>
array(0) {
}
}
Test '/values/0'
object(stdClass)#2 (0) {
}
array(0) {
}
Test '/values/1'
Caught SimdJsonException: Attempted to access an element of a JSON array that is beyond its length.
Caught SimdJsonException: Attempted to access an element of a JSON array that is beyond its length.
Test '/values/-1'
Caught SimdJsonException: The JSON element does not have the requested type.
Caught SimdJsonException: The JSON element does not have the requested type.
Test '/obj'
object(stdClass)#2 (1) {
["z"]=>
bool(false)
}
array(1) {
["z"]=>
bool(false)
}
Test '/obj/z'
bool(false)
bool(false)

0 comments on commit 4ac4c44

Please sign in to comment.