Skip to content

Commit 525dadb

Browse files
Merge v1.20 into v1.x (#1656)
2 parents 04c29be + 08364be commit 525dadb

10 files changed

+402
-4
lines changed

src/BSON/PackedArray.c

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,85 @@ static HashTable* php_phongo_packedarray_get_properties_hash(zend_object* object
8181
return props;
8282
}
8383

84+
static bool php_phongo_packedarray_to_json(zval* return_value, bson_json_mode_t mode, const bson_t* bson)
85+
{
86+
char* json = NULL;
87+
size_t json_len;
88+
bson_json_opts_t* opts = bson_json_opts_new(mode, BSON_MAX_LEN_UNLIMITED);
89+
bool ret = false;
90+
91+
bson_json_opts_set_outermost_array(opts, true);
92+
93+
json = bson_as_json_with_opts(bson, &json_len, opts);
94+
95+
if (json) {
96+
ZVAL_STRINGL(return_value, json, json_len);
97+
bson_free(json);
98+
ret = true;
99+
} else {
100+
ZVAL_UNDEF(return_value);
101+
phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Could not convert BSON array to a JSON string");
102+
}
103+
104+
bson_json_opts_destroy(opts);
105+
106+
return ret;
107+
}
108+
84109
PHONGO_DISABLED_CONSTRUCTOR(MongoDB_BSON_PackedArray)
85110

111+
static PHP_METHOD(MongoDB_BSON_PackedArray, fromJSON)
112+
{
113+
zval zv;
114+
php_phongo_packedarray_t* intern;
115+
zend_string* json;
116+
bson_t* bson;
117+
bson_error_t error;
118+
119+
PHONGO_PARSE_PARAMETERS_START(1, 1)
120+
Z_PARAM_STR(json)
121+
PHONGO_PARSE_PARAMETERS_END();
122+
123+
bson = bson_new_from_json((const uint8_t*) ZSTR_VAL(json), ZSTR_LEN(json), &error);
124+
if (!bson) {
125+
phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "%s", error.domain == BSON_ERROR_JSON ? error.message : "Error parsing JSON");
126+
return;
127+
}
128+
129+
// Check if BSON contains only numeric keys
130+
if (!bson_empty(bson)) {
131+
bson_iter_t iter;
132+
uint32_t expected_key = 0;
133+
char expected_key_str[11];
134+
const char* key_str;
135+
136+
if (!bson_iter_init(&iter, bson)) {
137+
phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Received invalid JSON array");
138+
bson_destroy(bson);
139+
return;
140+
}
141+
142+
while (bson_iter_next(&iter)) {
143+
key_str = bson_iter_key(&iter);
144+
snprintf(expected_key_str, sizeof(expected_key_str), "%" PRIu32, expected_key);
145+
146+
if (strcmp(key_str, expected_key_str)) {
147+
phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Received invalid JSON array: expected key %" PRIu32 ", but found \"%s\"", expected_key, key_str);
148+
bson_destroy(bson);
149+
return;
150+
}
151+
152+
expected_key++;
153+
}
154+
}
155+
156+
object_init_ex(&zv, php_phongo_packedarray_ce);
157+
intern = Z_PACKEDARRAY_OBJ_P(&zv);
158+
intern->bson = bson;
159+
160+
RETURN_ZVAL(&zv, 1, 1);
161+
}
162+
86163
static PHP_METHOD(MongoDB_BSON_PackedArray, fromPHP)
87164
{
88165
zval zv;
@@ -192,6 +269,28 @@ static PHP_METHOD(MongoDB_BSON_PackedArray, has)
192269
RETURN_BOOL(php_phongo_packedarray_has(intern, index));
193270
}
194271

272+
static PHP_METHOD(MongoDB_BSON_PackedArray, toCanonicalExtendedJSON)
273+
{
274+
php_phongo_packedarray_t* intern;
275+
276+
PHONGO_PARSE_PARAMETERS_NONE();
277+
278+
intern = Z_PACKEDARRAY_OBJ_P(getThis());
279+
280+
php_phongo_packedarray_to_json(return_value, BSON_JSON_MODE_CANONICAL, intern->bson);
281+
}
282+
283+
static PHP_METHOD(MongoDB_BSON_PackedArray, toRelaxedExtendedJSON)
284+
{
285+
php_phongo_packedarray_t* intern;
286+
287+
PHONGO_PARSE_PARAMETERS_NONE();
288+
289+
intern = Z_PACKEDARRAY_OBJ_P(getThis());
290+
291+
php_phongo_packedarray_to_json(return_value, BSON_JSON_MODE_RELAXED, intern->bson);
292+
}
293+
195294
static PHP_METHOD(MongoDB_BSON_PackedArray, toPHP)
196295
{
197296
php_phongo_packedarray_t* intern;

src/BSON/PackedArray.stub.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ final class PackedArray implements \IteratorAggregate, \Serializable, \ArrayAcce
1111
{
1212
private function __construct() {}
1313

14+
final static public function fromJSON(string $json): PackedArray {}
15+
1416
final static public function fromPHP(array $value): PackedArray {}
1517

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

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

26+
final public function toCanonicalExtendedJSON(): string {}
27+
28+
final public function toRelaxedExtendedJSON(): string {}
29+
2430
public function offsetExists(mixed $offset): bool {}
2531

2632
public function offsetGet(mixed $offset): mixed {}

src/BSON/PackedArray_arginfo.h

Lines changed: 18 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
--TEST--
2+
MongoDB\BSON\PackedArray::fromJSON(): Decoding JSON
3+
--FILE--
4+
<?php
5+
6+
require_once __DIR__ . '/../utils/basic.inc';
7+
8+
$tests = [
9+
'[]',
10+
'[ 1, 2, 3 ]',
11+
'[[ 1, 2, 3 ]]',
12+
'[{ "bar": 1 }]',
13+
];
14+
15+
foreach ($tests as $json) {
16+
printf("Test %s\n", $json);
17+
$bson = MongoDB\BSON\PackedArray::fromJSON($json);
18+
hex_dump((string) $bson);
19+
}
20+
21+
?>
22+
===DONE===
23+
<?php exit(0); ?>
24+
--EXPECT--
25+
Test []
26+
0 : 05 00 00 00 00 [.....]
27+
Test [ 1, 2, 3 ]
28+
0 : 1a 00 00 00 10 30 00 01 00 00 00 10 31 00 02 00 [.....0......1...]
29+
10 : 00 00 10 32 00 03 00 00 00 00 [...2......]
30+
Test [[ 1, 2, 3 ]]
31+
0 : 22 00 00 00 04 30 00 1a 00 00 00 10 30 00 01 00 ["....0......0...]
32+
10 : 00 00 10 31 00 02 00 00 00 10 32 00 03 00 00 00 [...1......2.....]
33+
20 : 00 00 [..]
34+
Test [{ "bar": 1 }]
35+
0 : 16 00 00 00 03 30 00 0e 00 00 00 10 62 61 72 00 [.....0......bar.]
36+
10 : 01 00 00 00 00 00 [......]
37+
===DONE===
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
--TEST--
2+
MongoDB\BSON\PackedArray::fromJSON(): Decoding extended JSON types
3+
--FILE--
4+
<?php
5+
6+
require_once __DIR__ . '/../utils/basic.inc';
7+
8+
$tests = [
9+
'[{ "$oid": "56315a7c6118fd1b920270b1" }]',
10+
'[{ "$binary": "Zm9v", "$type": "00" }]',
11+
'[{ "$date": "2015-10-28T00:00:00Z" }]',
12+
'[{ "$timestamp": { "t": 1446084619, "i": 0 }}]',
13+
'[{ "$regex": "pattern", "$options": "i" }]',
14+
'[{ "$undefined": true }]',
15+
'[{ "$minKey": 1 }]',
16+
'[{ "$maxKey": 1 }]',
17+
'[{ "$numberLong": "1234" }]',
18+
];
19+
20+
foreach ($tests as $json) {
21+
printf("Test %s\n", $json);
22+
$bson = MongoDB\BSON\PackedArray::fromJSON($json);
23+
hex_dump((string) $bson);
24+
}
25+
26+
?>
27+
===DONE===
28+
<?php exit(0); ?>
29+
--EXPECT--
30+
Test [{ "$oid": "56315a7c6118fd1b920270b1" }]
31+
0 : 14 00 00 00 07 30 00 56 31 5a 7c 61 18 fd 1b 92 [.....0.V1Z|a....]
32+
10 : 02 70 b1 00 [.p..]
33+
Test [{ "$binary": "Zm9v", "$type": "00" }]
34+
0 : 10 00 00 00 05 30 00 03 00 00 00 00 66 6f 6f 00 [.....0......foo.]
35+
Test [{ "$date": "2015-10-28T00:00:00Z" }]
36+
0 : 10 00 00 00 09 30 00 00 80 be ab 50 01 00 00 00 [.....0.....P....]
37+
Test [{ "$timestamp": { "t": 1446084619, "i": 0 }}]
38+
0 : 10 00 00 00 11 30 00 00 00 00 00 0b 80 31 56 00 [.....0.......1V.]
39+
Test [{ "$regex": "pattern", "$options": "i" }]
40+
0 : 12 00 00 00 0b 30 00 70 61 74 74 65 72 6e 00 69 [.....0.pattern.i]
41+
10 : 00 00 [..]
42+
Test [{ "$undefined": true }]
43+
0 : 08 00 00 00 06 30 00 00 [.....0..]
44+
Test [{ "$minKey": 1 }]
45+
0 : 08 00 00 00 ff 30 00 00 [.....0..]
46+
Test [{ "$maxKey": 1 }]
47+
0 : 08 00 00 00 7f 30 00 00 [.....0..]
48+
Test [{ "$numberLong": "1234" }]
49+
0 : 10 00 00 00 12 30 00 d2 04 00 00 00 00 00 00 00 [.....0..........]
50+
===DONE===
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
--TEST--
2+
MongoDB\BSON\PackedArray::fromJSON(): invalid JSON
3+
--FILE--
4+
<?php
5+
6+
require_once __DIR__ . '/../utils/basic.inc';
7+
8+
echo throws(function() {
9+
MongoDB\BSON\PackedArray::fromJSON('foo');
10+
}, 'MongoDB\Driver\Exception\UnexpectedValueException'), PHP_EOL;
11+
12+
echo throws(function() {
13+
MongoDB\BSON\PackedArray::fromJSON('{ "foo": "bar" }');
14+
}, 'MongoDB\Driver\Exception\UnexpectedValueException'), PHP_EOL;
15+
16+
echo throws(function() {
17+
MongoDB\BSON\PackedArray::fromJSON('{ "00": "bar", "1": "bar" }');
18+
}, 'MongoDB\Driver\Exception\UnexpectedValueException'), PHP_EOL;
19+
20+
echo throws(function() {
21+
MongoDB\BSON\PackedArray::fromJSON('{ "0": "bar", "foo": "bar" }');
22+
}, 'MongoDB\Driver\Exception\UnexpectedValueException'), PHP_EOL;
23+
24+
?>
25+
===DONE===
26+
<?php exit(0); ?>
27+
--EXPECT--
28+
OK: Got MongoDB\Driver\Exception\UnexpectedValueException
29+
Got parse error at "o", position 1: "SPECIAL_EXPECTED"
30+
OK: Got MongoDB\Driver\Exception\UnexpectedValueException
31+
Received invalid JSON array: expected key 0, but found "foo"
32+
OK: Got MongoDB\Driver\Exception\UnexpectedValueException
33+
Received invalid JSON array: expected key 0, but found "00"
34+
OK: Got MongoDB\Driver\Exception\UnexpectedValueException
35+
Received invalid JSON array: expected key 1, but found "foo"
36+
===DONE===
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
--TEST--
2+
MongoDB\BSON\PackedArray::toCanonicalExtendedJSON(): Encoding JSON
3+
--FILE--
4+
<?php
5+
6+
require_once __DIR__ . '/../utils/basic.inc';
7+
8+
$tests = [
9+
[],
10+
[ null ],
11+
[ true ],
12+
[ 'foo' ],
13+
[ 123 ],
14+
[ 1.0, ],
15+
[ NAN ],
16+
[ INF ],
17+
[ -INF ],
18+
[ [ 'foo', 'bar' ]],
19+
[ [ 'foo' => 'bar' ]],
20+
];
21+
22+
foreach ($tests as $value) {
23+
echo MongoDB\BSON\PackedArray::fromPHP($value)->toCanonicalExtendedJSON(), "\n";
24+
}
25+
26+
?>
27+
===DONE===
28+
<?php exit(0); ?>
29+
--EXPECT--
30+
[ ]
31+
[ null ]
32+
[ true ]
33+
[ "foo" ]
34+
[ { "$numberInt" : "123" } ]
35+
[ { "$numberDouble" : "1.0" } ]
36+
[ { "$numberDouble" : "NaN" } ]
37+
[ { "$numberDouble" : "Infinity" } ]
38+
[ { "$numberDouble" : "-Infinity" } ]
39+
[ [ "foo", "bar" ] ]
40+
[ { "foo" : "bar" } ]
41+
===DONE===

0 commit comments

Comments
 (0)