Skip to content

Merge v1.20 into v1.x #1656

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 99 additions & 0 deletions src/BSON/PackedArray.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,85 @@ static HashTable* php_phongo_packedarray_get_properties_hash(zend_object* object
return props;
}

static bool php_phongo_packedarray_to_json(zval* return_value, bson_json_mode_t mode, const bson_t* bson)
{
char* json = NULL;
size_t json_len;
bson_json_opts_t* opts = bson_json_opts_new(mode, BSON_MAX_LEN_UNLIMITED);
bool ret = false;

bson_json_opts_set_outermost_array(opts, true);

json = bson_as_json_with_opts(bson, &json_len, opts);

if (json) {
ZVAL_STRINGL(return_value, json, json_len);
bson_free(json);
ret = true;
} else {
ZVAL_UNDEF(return_value);
phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Could not convert BSON array to a JSON string");
}

bson_json_opts_destroy(opts);

return ret;
}

PHONGO_DISABLED_CONSTRUCTOR(MongoDB_BSON_PackedArray)

static PHP_METHOD(MongoDB_BSON_PackedArray, fromJSON)
{
zval zv;
php_phongo_packedarray_t* intern;
zend_string* json;
bson_t* bson;
bson_error_t error;

PHONGO_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_STR(json)
PHONGO_PARSE_PARAMETERS_END();

bson = bson_new_from_json((const uint8_t*) ZSTR_VAL(json), ZSTR_LEN(json), &error);
if (!bson) {
phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "%s", error.domain == BSON_ERROR_JSON ? error.message : "Error parsing JSON");
return;
}

// Check if BSON contains only numeric keys
if (!bson_empty(bson)) {
bson_iter_t iter;
uint32_t expected_key = 0;
char expected_key_str[11];
const char* key_str;

if (!bson_iter_init(&iter, bson)) {
phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Received invalid JSON array");
bson_destroy(bson);
return;
}

while (bson_iter_next(&iter)) {
key_str = bson_iter_key(&iter);
snprintf(expected_key_str, sizeof(expected_key_str), "%" PRIu32, expected_key);

if (strcmp(key_str, expected_key_str)) {
phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Received invalid JSON array: expected key %" PRIu32 ", but found \"%s\"", expected_key, key_str);
bson_destroy(bson);
return;
}

expected_key++;
}
}

object_init_ex(&zv, php_phongo_packedarray_ce);
intern = Z_PACKEDARRAY_OBJ_P(&zv);
intern->bson = bson;

RETURN_ZVAL(&zv, 1, 1);
}

static PHP_METHOD(MongoDB_BSON_PackedArray, fromPHP)
{
zval zv;
Expand Down Expand Up @@ -192,6 +269,28 @@ static PHP_METHOD(MongoDB_BSON_PackedArray, has)
RETURN_BOOL(php_phongo_packedarray_has(intern, index));
}

static PHP_METHOD(MongoDB_BSON_PackedArray, toCanonicalExtendedJSON)
{
php_phongo_packedarray_t* intern;

PHONGO_PARSE_PARAMETERS_NONE();

intern = Z_PACKEDARRAY_OBJ_P(getThis());

php_phongo_packedarray_to_json(return_value, BSON_JSON_MODE_CANONICAL, intern->bson);
}

static PHP_METHOD(MongoDB_BSON_PackedArray, toRelaxedExtendedJSON)
{
php_phongo_packedarray_t* intern;

PHONGO_PARSE_PARAMETERS_NONE();

intern = Z_PACKEDARRAY_OBJ_P(getThis());

php_phongo_packedarray_to_json(return_value, BSON_JSON_MODE_RELAXED, intern->bson);
}

static PHP_METHOD(MongoDB_BSON_PackedArray, toPHP)
{
php_phongo_packedarray_t* intern;
Expand Down
6 changes: 6 additions & 0 deletions src/BSON/PackedArray.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ final class PackedArray implements \IteratorAggregate, \Serializable, \ArrayAcce
{
private function __construct() {}

final static public function fromJSON(string $json): PackedArray {}

final static public function fromPHP(array $value): PackedArray {}

final public function get(int $index): mixed {}
Expand All @@ -21,6 +23,10 @@ final public function has(int $index): bool {}

final public function toPHP(?array $typeMap = null): array|object {}

final public function toCanonicalExtendedJSON(): string {}

final public function toRelaxedExtendedJSON(): string {}

public function offsetExists(mixed $offset): bool {}

public function offsetGet(mixed $offset): mixed {}
Expand Down
22 changes: 18 additions & 4 deletions src/BSON/PackedArray_arginfo.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 37 additions & 0 deletions tests/bson/bson-packedarray-fromJSON-001.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
--TEST--
MongoDB\BSON\PackedArray::fromJSON(): Decoding JSON
--FILE--
<?php

require_once __DIR__ . '/../utils/basic.inc';

$tests = [
'[]',
'[ 1, 2, 3 ]',
'[[ 1, 2, 3 ]]',
'[{ "bar": 1 }]',
];

foreach ($tests as $json) {
printf("Test %s\n", $json);
$bson = MongoDB\BSON\PackedArray::fromJSON($json);
hex_dump((string) $bson);
}

?>
===DONE===
<?php exit(0); ?>
--EXPECT--
Test []
0 : 05 00 00 00 00 [.....]
Test [ 1, 2, 3 ]
0 : 1a 00 00 00 10 30 00 01 00 00 00 10 31 00 02 00 [.....0......1...]
10 : 00 00 10 32 00 03 00 00 00 00 [...2......]
Test [[ 1, 2, 3 ]]
0 : 22 00 00 00 04 30 00 1a 00 00 00 10 30 00 01 00 ["....0......0...]
10 : 00 00 10 31 00 02 00 00 00 10 32 00 03 00 00 00 [...1......2.....]
20 : 00 00 [..]
Test [{ "bar": 1 }]
0 : 16 00 00 00 03 30 00 0e 00 00 00 10 62 61 72 00 [.....0......bar.]
10 : 01 00 00 00 00 00 [......]
===DONE===
50 changes: 50 additions & 0 deletions tests/bson/bson-packedarray-fromJSON-002.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
--TEST--
MongoDB\BSON\PackedArray::fromJSON(): Decoding extended JSON types
--FILE--
<?php

require_once __DIR__ . '/../utils/basic.inc';

$tests = [
'[{ "$oid": "56315a7c6118fd1b920270b1" }]',
'[{ "$binary": "Zm9v", "$type": "00" }]',
'[{ "$date": "2015-10-28T00:00:00Z" }]',
'[{ "$timestamp": { "t": 1446084619, "i": 0 }}]',
'[{ "$regex": "pattern", "$options": "i" }]',
'[{ "$undefined": true }]',
'[{ "$minKey": 1 }]',
'[{ "$maxKey": 1 }]',
'[{ "$numberLong": "1234" }]',
];

foreach ($tests as $json) {
printf("Test %s\n", $json);
$bson = MongoDB\BSON\PackedArray::fromJSON($json);
hex_dump((string) $bson);
}

?>
===DONE===
<?php exit(0); ?>
--EXPECT--
Test [{ "$oid": "56315a7c6118fd1b920270b1" }]
0 : 14 00 00 00 07 30 00 56 31 5a 7c 61 18 fd 1b 92 [.....0.V1Z|a....]
10 : 02 70 b1 00 [.p..]
Test [{ "$binary": "Zm9v", "$type": "00" }]
0 : 10 00 00 00 05 30 00 03 00 00 00 00 66 6f 6f 00 [.....0......foo.]
Test [{ "$date": "2015-10-28T00:00:00Z" }]
0 : 10 00 00 00 09 30 00 00 80 be ab 50 01 00 00 00 [.....0.....P....]
Test [{ "$timestamp": { "t": 1446084619, "i": 0 }}]
0 : 10 00 00 00 11 30 00 00 00 00 00 0b 80 31 56 00 [.....0.......1V.]
Test [{ "$regex": "pattern", "$options": "i" }]
0 : 12 00 00 00 0b 30 00 70 61 74 74 65 72 6e 00 69 [.....0.pattern.i]
10 : 00 00 [..]
Test [{ "$undefined": true }]
0 : 08 00 00 00 06 30 00 00 [.....0..]
Test [{ "$minKey": 1 }]
0 : 08 00 00 00 ff 30 00 00 [.....0..]
Test [{ "$maxKey": 1 }]
0 : 08 00 00 00 7f 30 00 00 [.....0..]
Test [{ "$numberLong": "1234" }]
0 : 10 00 00 00 12 30 00 d2 04 00 00 00 00 00 00 00 [.....0..........]
===DONE===
36 changes: 36 additions & 0 deletions tests/bson/bson-packedarray-fromJSON_error-001.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
--TEST--
MongoDB\BSON\PackedArray::fromJSON(): invalid JSON
--FILE--
<?php

require_once __DIR__ . '/../utils/basic.inc';

echo throws(function() {
MongoDB\BSON\PackedArray::fromJSON('foo');
}, 'MongoDB\Driver\Exception\UnexpectedValueException'), PHP_EOL;

echo throws(function() {
MongoDB\BSON\PackedArray::fromJSON('{ "foo": "bar" }');
}, 'MongoDB\Driver\Exception\UnexpectedValueException'), PHP_EOL;

echo throws(function() {
MongoDB\BSON\PackedArray::fromJSON('{ "00": "bar", "1": "bar" }');
}, 'MongoDB\Driver\Exception\UnexpectedValueException'), PHP_EOL;

echo throws(function() {
MongoDB\BSON\PackedArray::fromJSON('{ "0": "bar", "foo": "bar" }');
}, 'MongoDB\Driver\Exception\UnexpectedValueException'), PHP_EOL;

?>
===DONE===
<?php exit(0); ?>
--EXPECT--
OK: Got MongoDB\Driver\Exception\UnexpectedValueException
Got parse error at "o", position 1: "SPECIAL_EXPECTED"
OK: Got MongoDB\Driver\Exception\UnexpectedValueException
Received invalid JSON array: expected key 0, but found "foo"
OK: Got MongoDB\Driver\Exception\UnexpectedValueException
Received invalid JSON array: expected key 0, but found "00"
OK: Got MongoDB\Driver\Exception\UnexpectedValueException
Received invalid JSON array: expected key 1, but found "foo"
===DONE===
41 changes: 41 additions & 0 deletions tests/bson/bson-packedarray-toCanonicalExtendedJSON-001.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
--TEST--
MongoDB\BSON\PackedArray::toCanonicalExtendedJSON(): Encoding JSON
--FILE--
<?php

require_once __DIR__ . '/../utils/basic.inc';

$tests = [
[],
[ null ],
[ true ],
[ 'foo' ],
[ 123 ],
[ 1.0, ],
[ NAN ],
[ INF ],
[ -INF ],
[ [ 'foo', 'bar' ]],
[ [ 'foo' => 'bar' ]],
];

foreach ($tests as $value) {
echo MongoDB\BSON\PackedArray::fromPHP($value)->toCanonicalExtendedJSON(), "\n";
}

?>
===DONE===
<?php exit(0); ?>
--EXPECT--
[ ]
[ null ]
[ true ]
[ "foo" ]
[ { "$numberInt" : "123" } ]
[ { "$numberDouble" : "1.0" } ]
[ { "$numberDouble" : "NaN" } ]
[ { "$numberDouble" : "Infinity" } ]
[ { "$numberDouble" : "-Infinity" } ]
[ [ "foo", "bar" ] ]
[ { "foo" : "bar" } ]
===DONE===
Loading