Skip to content

Commit 1516d3b

Browse files
committed
Prevent Persistable implementations to return PackedArray instances
1 parent 07ebeeb commit 1516d3b

File tree

4 files changed

+57
-4
lines changed

4 files changed

+57
-4
lines changed

src/BSON/Persistable.stub.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,11 @@
99

1010
interface Persistable extends Serializable, Unserializable
1111
{
12+
#if PHP_VERSION_ID >= 80000
13+
/** @tentative-return-type */
14+
public function bsonSerialize(): array|\stdClass|Document;
15+
#else
16+
/** @return array|\stdClass|Document */
17+
public function bsonSerialize();
18+
#endif
1219
}

src/BSON/Persistable_arginfo.h

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,30 @@
11
/* This is a generated file, edit the .stub.php file instead.
2-
* Stub hash: babd07f95f47c3b66228ef23b66ab0446cd5c308 */
2+
* Stub hash: e61c06a90093af5468c6c29f6cbf16c5db8d54d1 */
33

4+
#if PHP_VERSION_ID >= 80000
5+
ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_MongoDB_BSON_Persistable_bsonSerialize, 0, 0, stdClass|MongoDB\\BSON\\Document, MAY_BE_ARRAY)
6+
ZEND_END_ARG_INFO()
7+
#endif
48

9+
#if !(PHP_VERSION_ID >= 80000)
10+
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_BSON_Persistable_bsonSerialize, 0, 0, 0)
11+
ZEND_END_ARG_INFO()
12+
#endif
13+
14+
15+
#if PHP_VERSION_ID >= 80000
16+
#endif
17+
#if !(PHP_VERSION_ID >= 80000)
18+
#endif
519

620

721
static const zend_function_entry class_MongoDB_BSON_Persistable_methods[] = {
22+
#if PHP_VERSION_ID >= 80000
23+
ZEND_ABSTRACT_ME_WITH_FLAGS(MongoDB_BSON_Persistable, bsonSerialize, arginfo_class_MongoDB_BSON_Persistable_bsonSerialize, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
24+
#endif
25+
#if !(PHP_VERSION_ID >= 80000)
26+
ZEND_ABSTRACT_ME_WITH_FLAGS(MongoDB_BSON_Persistable, bsonSerialize, arginfo_class_MongoDB_BSON_Persistable_bsonSerialize, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
27+
#endif
828
ZEND_FE_END
929
};
1030

src/phongo_bson_encode.c

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,20 @@ static void php_phongo_bson_append_object(bson_t* bson, php_phongo_field_path* f
135135
}
136136

137137
// TODO PHP_VERSION_ID < 80000: obsolete once the tentative return type of bsonSerialize() is enforced
138-
if (
138+
if (instanceof_function(Z_OBJCE_P(object), php_phongo_persistable_ce)) {
139+
if (
140+
Z_TYPE(obj_data) != IS_ARRAY && !(Z_TYPE(obj_data) == IS_OBJECT && (instanceof_function(Z_OBJCE(obj_data), zend_standard_class_def) || instanceof_function(Z_OBJCE(obj_data), php_phongo_document_ce)))) {
141+
phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE,
142+
"Expected %s::%s() to return an array, stdClass, or %s, %s given",
143+
ZSTR_VAL(Z_OBJCE_P(object)->name),
144+
BSON_SERIALIZE_FUNC_NAME,
145+
ZSTR_VAL(php_phongo_document_ce->name),
146+
PHONGO_ZVAL_CLASS_OR_TYPE_NAME(obj_data));
147+
zval_ptr_dtor(&obj_data);
148+
149+
return;
150+
}
151+
} else if (
139152
Z_TYPE(obj_data) != IS_ARRAY && !(Z_TYPE(obj_data) == IS_OBJECT && (instanceof_function(Z_OBJCE(obj_data), zend_standard_class_def) || instanceof_function(Z_OBJCE(obj_data), php_phongo_document_ce) || instanceof_function(Z_OBJCE(obj_data), php_phongo_packedarray_ce)))) {
140153
phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE,
141154
"Expected %s::%s() to return an array, stdClass, %s, or %s, %s given",
@@ -462,6 +475,18 @@ static void php_phongo_zval_to_bson_internal(zval* data, php_phongo_field_path*
462475
}
463476

464477
if (instanceof_function(Z_OBJCE_P(data), php_phongo_persistable_ce)) {
478+
if (Z_TYPE(obj_data) == IS_OBJECT && instanceof_function(Z_OBJCE(obj_data), php_phongo_packedarray_ce)) {
479+
phongo_throw_exception(
480+
PHONGO_ERROR_UNEXPECTED_VALUE,
481+
"Expected %s::%s() to return an array, stdClass, or %s, %s given",
482+
ZSTR_VAL(Z_OBJCE_P(data)->name),
483+
BSON_SERIALIZE_FUNC_NAME,
484+
ZSTR_VAL(php_phongo_document_ce->name),
485+
PHONGO_ZVAL_CLASS_OR_TYPE_NAME(obj_data));
486+
487+
goto cleanup;
488+
}
489+
465490
bson_append_binary(bson, PHONGO_ODM_FIELD_NAME, -1, 0x80, (const uint8_t*) Z_OBJCE_P(data)->name->val, Z_OBJCE_P(data)->name->len);
466491
/* Ensure that we ignore an existing key with the same name
467492
* if one exists in the bsonSerialize() return value. */

tests/bson/bson-fromPHP-001.phpt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ $tests = array(
3434
array('foo' => 'bar'),
3535
(object) array(1, 2, 3),
3636
(object) array('foo' => 'bar'),
37+
# The PackedArray check will fail for instances of Persistable
3738
MongoDB\BSON\PackedArray::fromPHP([1, 2, 3]),
3839
MongoDB\BSON\Document::fromPHP(['foo' => 'bar']),
3940
);
@@ -74,7 +75,7 @@ Testing top-level objects
7475
{ "foo" : "bar" }
7576
{ "__pclass" : { "$binary" : "TXlQZXJzaXN0YWJsZURvY3VtZW50", "$type" : "80" }, "foo" : "bar" }
7677
{ "0" : 1, "1" : 2, "2" : 3 }
77-
{ "__pclass" : { "$binary" : "TXlQZXJzaXN0YWJsZURvY3VtZW50", "$type" : "80" }, "0" : 1, "1" : 2, "2" : 3 }
78+
Expected MyPersistableDocument::bsonSerialize() to return an array, stdClass, or MongoDB\BSON\Document, MongoDB\BSON\PackedArray given
7879
{ "foo" : "bar" }
7980
{ "__pclass" : { "$binary" : "TXlQZXJzaXN0YWJsZURvY3VtZW50", "$type" : "80" }, "foo" : "bar" }
8081

@@ -88,7 +89,7 @@ Testing nested objects
8889
{ "nested" : { "foo" : "bar" } }
8990
{ "nested" : { "__pclass" : { "$binary" : "TXlQZXJzaXN0YWJsZURvY3VtZW50", "$type" : "80" }, "foo" : "bar" } }
9091
{ "nested" : [ 1, 2, 3 ] }
91-
{ "nested" : { "__pclass" : { "$binary" : "TXlQZXJzaXN0YWJsZURvY3VtZW50", "$type" : "80" }, "0" : 1, "1" : 2, "2" : 3 } }
92+
Expected MyPersistableDocument::bsonSerialize() to return an array, stdClass, or MongoDB\BSON\Document, MongoDB\BSON\PackedArray given
9293
{ "nested" : { "foo" : "bar" } }
9394
{ "nested" : { "__pclass" : { "$binary" : "TXlQZXJzaXN0YWJsZURvY3VtZW50", "$type" : "80" }, "foo" : "bar" } }
9495
===DONE===

0 commit comments

Comments
 (0)