diff --git a/src/bson-encode.c b/src/bson-encode.c index 5f22d67c8..70524084d 100644 --- a/src/bson-encode.c +++ b/src/bson-encode.c @@ -401,6 +401,11 @@ void php_phongo_zval_to_bson(zval *data, php_phongo_bson_flags_t flags, bson_t * * properties, we'll need to filter them out later. */ bool ht_data_from_properties = false; + /* If the object is an instance of MongoDB\BSON\Persistable, we will need to + * inject the PHP class name as a BSON key and ignore any existing key in + * the return value of bsonSerialize(). */ + bool skip_odm_field = false; + ZVAL_UNDEF(&obj_data); switch(Z_TYPE_P(data)) { @@ -455,11 +460,12 @@ void php_phongo_zval_to_bson(zval *data, php_phongo_bson_flags_t flags, bson_t * if (instanceof_function(Z_OBJCE_P(data), php_phongo_persistable_ce TSRMLS_CC)) { #if PHP_VERSION_ID >= 70000 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); - zend_hash_str_del(ht_data, PHONGO_ODM_FIELD_NAME, sizeof(PHONGO_ODM_FIELD_NAME)-1); #else bson_append_binary(bson, PHONGO_ODM_FIELD_NAME, -1, 0x80, (const uint8_t *)Z_OBJCE_P(data)->name, strlen(Z_OBJCE_P(data)->name)); - zend_hash_del(ht_data, PHONGO_ODM_FIELD_NAME, sizeof(PHONGO_ODM_FIELD_NAME)); #endif + /* Ensure that we ignore an existing key with the same name + * if one exists in the bsonSerialize() return value. */ + skip_odm_field = true; } break; @@ -504,6 +510,10 @@ void php_phongo_zval_to_bson(zval *data, php_phongo_bson_flags_t flags, bson_t * goto cleanup; } + if (skip_odm_field && !strcmp(ZSTR_VAL(string_key), PHONGO_ODM_FIELD_NAME)) { + continue; + } + if (flags & PHONGO_BSON_ADD_ID) { if (!strcmp(ZSTR_VAL(string_key), "_id")) { flags &= ~PHONGO_BSON_ADD_ID; @@ -556,6 +566,10 @@ void php_phongo_zval_to_bson(zval *data, php_phongo_bson_flags_t flags, bson_t * goto cleanup; } + if (skip_odm_field && !strcmp(string_key, PHONGO_ODM_FIELD_NAME)) { + continue; + } + if (flags & PHONGO_BSON_ADD_ID) { if (!strcmp(string_key, "_id")) { flags &= ~PHONGO_BSON_ADD_ID; diff --git a/tests/bson/bug1006-001.phpt b/tests/bson/bug1006-001.phpt new file mode 100644 index 000000000..b57bf2c64 --- /dev/null +++ b/tests/bson/bug1006-001.phpt @@ -0,0 +1,54 @@ +--TEST-- +PHPC-1005: Do not modify memory of Persistable::bsonSerialize() return value +--FILE-- +data = [ + '__pclass' => 'baz', + 'foo' => 'bar', + ]; + } + + function bsonSerialize() + { + return $this->data; + } + + function bsonUnserialize(array $data) + { + } +} + +$obj = new MyClass; +var_dump($obj->data); +hex_dump(fromPHP($obj)); +var_dump($obj->data); + +?> +===DONE=== + +--EXPECT-- +array(2) { + ["__pclass"]=> + string(3) "baz" + ["foo"]=> + string(3) "bar" +} + 0 : 28 00 00 00 05 5f 5f 70 63 6c 61 73 73 00 07 00 [(....__pclass...] + 10 : 00 00 80 4d 79 43 6c 61 73 73 02 66 6f 6f 00 04 [...MyClass.foo..] + 20 : 00 00 00 62 61 72 00 00 [...bar..] +array(2) { + ["__pclass"]=> + string(3) "baz" + ["foo"]=> + string(3) "bar" +} +===DONE===