Skip to content

Commit 9b29049

Browse files
committed
PHPC-460: ObjectID serialization and var_export
1 parent 4b24338 commit 9b29049

File tree

6 files changed

+177
-56
lines changed

6 files changed

+177
-56
lines changed

php_phongo.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1382,6 +1382,7 @@ void php_phongo_objectid_new_from_oid(zval *object, const bson_oid_t *oid TSRMLS
13821382

13831383
intern = Z_OBJECTID_OBJ_P(object);
13841384
bson_oid_to_string(oid, intern->oid);
1385+
intern->initialized = true;
13851386
} /* }}} */
13861387

13871388
php_phongo_server_description_type_t php_phongo_server_description_type(mongoc_server_description_t *sd)

php_phongo_structs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ typedef struct {
185185

186186
typedef struct {
187187
PHONGO_ZEND_OBJECT_PRE
188+
bool initialized;
188189
char oid[25];
189190
PHONGO_ZEND_OBJECT_POST
190191
} php_phongo_objectid_t;

src/BSON/ObjectID.c

Lines changed: 128 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,59 @@ PHONGO_API zend_class_entry *php_phongo_objectid_ce;
4646

4747
zend_object_handlers php_phongo_handler_objectid;
4848

49+
/* Initialize the object with a generated value and return whether it was successful. */
50+
static bool php_phongo_objectid_init(php_phongo_objectid_t *intern)
51+
{
52+
bson_oid_t oid;
53+
54+
intern->initialized = true;
55+
56+
bson_oid_init(&oid, NULL);
57+
bson_oid_to_string(&oid, intern->oid);
58+
59+
return true;
60+
}
61+
62+
/* Initialize the object from a hex string and return whether it was successful. */
63+
static bool php_phongo_objectid_init_from_hex_string(php_phongo_objectid_t *intern, const char *oid, phongo_zpp_char_len oid_len)
64+
{
65+
char *tid = zend_str_tolower_dup(oid, oid_len);
66+
67+
if (bson_oid_is_valid(tid, oid_len)) {
68+
bson_oid_t oid;
69+
70+
bson_oid_init_from_string(&oid, tid);
71+
bson_oid_to_string(&oid, intern->oid);
72+
intern->initialized = true;
73+
74+
efree(tid);
75+
return true;
76+
}
77+
78+
efree(tid);
79+
return false;
80+
}
81+
82+
/* Initialize the object from a HashTable and return whether it was successful. */
83+
static bool php_phongo_objectid_init_from_hash(php_phongo_objectid_t *intern, HashTable *props)
84+
{
85+
#if PHP_VERSION_ID >= 70000
86+
zval *z_oid;
87+
88+
z_oid = zend_hash_str_find(props, "oid", sizeof("oid")-1);
89+
90+
if (z_oid && Z_TYPE_P(z_oid) == IS_STRING) {
91+
return php_phongo_objectid_init_from_hex_string(intern, Z_STRVAL_P(z_oid), Z_STRLEN_P(z_oid));
92+
}
93+
#else
94+
zval **z_oid;
95+
96+
if (zend_hash_find(props, "oid", sizeof("oid"), (void**) &z_oid) == SUCCESS && Z_TYPE_PP(z_oid) == IS_STRING) {
97+
return php_phongo_objectid_init_from_hex_string(intern, Z_STRVAL_PP(z_oid), Z_STRLEN_PP(z_oid));
98+
}
99+
#endif
100+
return false;
101+
}
49102

50103
/* {{{ proto BSON\ObjectID ObjectID::__construct(string $id)
51104
Constructs a new Object ID, optionally from a string */
@@ -67,24 +120,38 @@ PHP_METHOD(ObjectID, __construct)
67120
zend_restore_error_handling(&error_handling TSRMLS_CC);
68121

69122
if (id) {
70-
char *tid = zend_str_tolower_dup(id, id_len);
71-
if (bson_oid_is_valid(tid, id_len)) {
72-
bson_oid_t oid;
73-
74-
bson_oid_init_from_string(&oid, tid);
75-
bson_oid_to_string(&oid, intern->oid);
76-
} else {
123+
if (!php_phongo_objectid_init_from_hex_string(intern, id, id_len)) {
77124
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "%s", "Invalid BSON ID provided");
78125
}
79-
efree(tid);
80126
} else {
81-
bson_oid_t oid;
127+
php_phongo_objectid_init(intern);
128+
}
129+
}
130+
/* }}} */
82131

83-
bson_oid_init(&oid, NULL);
84-
bson_oid_to_string(&oid, intern->oid);
132+
/* {{{ proto ObjectID::__set_state(array $properties)
133+
*/
134+
PHP_METHOD(ObjectID, __set_state)
135+
{
136+
php_phongo_objectid_t *intern;
137+
HashTable *props;
138+
zval *array;
139+
140+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) == FAILURE) {
141+
RETURN_FALSE;
142+
}
143+
144+
object_init_ex(return_value, php_phongo_objectid_ce);
145+
146+
intern = Z_OBJECTID_OBJ_P(return_value);
147+
props = Z_ARRVAL_P(array);
148+
149+
if (!php_phongo_objectid_init_from_hash(intern, props)) {
150+
php_error(E_ERROR, "Invalid serialization data for ObjectID object");
85151
}
86152
}
87153
/* }}} */
154+
88155
/* {{{ proto void ObjectID::__toString()
89156
*/
90157
PHP_METHOD(ObjectID, __toString)
@@ -103,21 +170,44 @@ PHP_METHOD(ObjectID, __toString)
103170
}
104171
/* }}} */
105172

173+
/* {{{ proto ObjectID::__wakeup()
174+
*/
175+
PHP_METHOD(ObjectID, __wakeup)
176+
{
177+
php_phongo_objectid_t *intern;
178+
HashTable *props;
179+
180+
if (zend_parse_parameters_none() == FAILURE) {
181+
return;
182+
}
183+
184+
intern = Z_OBJECTID_OBJ_P(getThis());
185+
props = zend_std_get_properties(getThis() TSRMLS_CC);
186+
187+
if (!php_phongo_objectid_init_from_hash(intern, props)) {
188+
php_error(E_ERROR, "Invalid serialization data for ObjectID object");
189+
}
190+
}
191+
/* }}} */
106192

107193
/* {{{ BSON\ObjectID */
108194

109195
ZEND_BEGIN_ARG_INFO_EX(ai_ObjectID___construct, 0, 0, 0)
110196
ZEND_ARG_INFO(0, id)
111197
ZEND_END_ARG_INFO();
112198

113-
ZEND_BEGIN_ARG_INFO_EX(ai_ObjectID___toString, 0, 0, 0)
199+
ZEND_BEGIN_ARG_INFO_EX(ai_ObjectID___set_state, 0, 0, 1)
200+
ZEND_ARG_ARRAY_INFO(0, properties, 0)
114201
ZEND_END_ARG_INFO();
115202

203+
ZEND_BEGIN_ARG_INFO_EX(ai_ObjectID_void, 0, 0, 0)
204+
ZEND_END_ARG_INFO()
116205

117206
static zend_function_entry php_phongo_objectid_me[] = {
118207
PHP_ME(ObjectID, __construct, ai_ObjectID___construct, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
119-
PHP_ME(ObjectID, __toString, ai_ObjectID___toString, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
120-
PHP_ME(Manager, __wakeUp, NULL, ZEND_ACC_PUBLIC)
208+
PHP_ME(ObjectID, __set_state, ai_ObjectID___set_state, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
209+
PHP_ME(ObjectID, __toString, ai_ObjectID_void, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
210+
PHP_ME(ObjectID, __wakeup, ai_ObjectID_void, ZEND_ACC_PUBLIC)
121211
PHP_FE_END
122212
};
123213

@@ -171,25 +261,36 @@ static int php_phongo_objectid_compare_objects(zval *o1, zval *o2 TSRMLS_DC) /*
171261
return strcmp(intern1->oid, intern2->oid);
172262
} /* }}} */
173263

174-
HashTable *php_phongo_objectid_get_debug_info(zval *object, int *is_temp TSRMLS_DC) /* {{{ */
264+
HashTable *php_phongo_objectid_get_properties(zval *object TSRMLS_DC) /* {{{ */
175265
{
176-
php_phongo_objectid_t *intern;
177-
#if PHP_VERSION_ID >= 70000
178-
zval retval;
179-
#else
180-
zval retval = zval_used_for_init;
181-
#endif
266+
php_phongo_objectid_t *intern;
267+
HashTable *props;
182268

183-
184-
*is_temp = 1;
185269
intern = Z_OBJECTID_OBJ_P(object);
270+
props = zend_std_get_properties(object TSRMLS_CC);
186271

187-
array_init(&retval);
272+
if (!intern->oid) {
273+
return props;
274+
}
188275

189-
ADD_ASSOC_STRINGL(&retval, "oid", intern->oid, 24);
276+
#if PHP_VERSION_ID >= 70000
277+
{
278+
zval zv;
279+
280+
ZVAL_STRING(&zv, intern->oid);
281+
zend_hash_str_update(props, "oid", sizeof("oid")-1, &zv);
282+
}
283+
#else
284+
{
285+
zval *zv;
190286

191-
return Z_ARRVAL(retval);
287+
MAKE_STD_ZVAL(zv);
288+
ZVAL_STRING(zv, intern->oid, 1);
289+
zend_hash_update(props, "oid", sizeof("oid"), &zv, sizeof(zv), NULL);
290+
}
291+
#endif
192292

293+
return props;
193294
} /* }}} */
194295
/* }}} */
195296

@@ -203,13 +304,12 @@ PHP_MINIT_FUNCTION(ObjectID)
203304
php_phongo_objectid_ce = zend_register_internal_class(&ce TSRMLS_CC);
204305
php_phongo_objectid_ce->create_object = php_phongo_objectid_create_object;
205306
PHONGO_CE_FINAL(php_phongo_objectid_ce);
206-
PHONGO_CE_DISABLE_SERIALIZATION(php_phongo_objectid_ce);
207307

208308
zend_class_implements(php_phongo_objectid_ce TSRMLS_CC, 1, php_phongo_type_ce);
209309

210310
memcpy(&php_phongo_handler_objectid, phongo_get_std_object_handlers(), sizeof(zend_object_handlers));
211311
php_phongo_handler_objectid.compare_objects = php_phongo_objectid_compare_objects;
212-
php_phongo_handler_objectid.get_debug_info = php_phongo_objectid_get_debug_info;
312+
php_phongo_handler_objectid.get_properties = php_phongo_objectid_get_properties;
213313
#if PHP_VERSION_ID >= 70000
214314
php_phongo_handler_objectid.free_obj = php_phongo_objectid_free_object;
215315
php_phongo_handler_objectid.offset = XtOffsetOf(php_phongo_objectid_t, std);

tests/bson/bson-objectid-005.phpt

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
--TEST--
2+
MongoDB\BSON\ObjectID serialization
3+
--SKIPIF--
4+
<?php require __DIR__ . "/../utils/basic-skipif.inc"?>
5+
--FILE--
6+
<?php
7+
require_once __DIR__ . "/../utils/basic.inc";
8+
9+
var_dump($oid = new MongoDB\BSON\ObjectID('576c25db6118fd406e6e6471'));
10+
var_dump($s = serialize($oid));
11+
var_dump(unserialize($s));
12+
13+
?>
14+
===DONE===
15+
<?php exit(0); ?>
16+
--EXPECTF--
17+
object(MongoDB\BSON\ObjectID)#%d (%d) {
18+
["oid"]=>
19+
string(24) "576c25db6118fd406e6e6471"
20+
}
21+
string(75) "O:21:"MongoDB\BSON\ObjectID":1:{s:3:"oid";s:24:"576c25db6118fd406e6e6471";}"
22+
object(MongoDB\BSON\ObjectID)#%d (%d) {
23+
["oid"]=>
24+
string(24) "576c25db6118fd406e6e6471"
25+
}
26+
===DONE===
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
--TEST--
2+
MongoDB\BSON\ObjectID::__set_state()
3+
--SKIPIF--
4+
<?php require __DIR__ . "/../utils/basic-skipif.inc"?>
5+
--FILE--
6+
<?php
7+
require_once __DIR__ . "/../utils/basic.inc";
8+
9+
var_export(MongoDB\BSON\ObjectID::__set_state([
10+
'oid' => '576c25db6118fd406e6e6471',
11+
]));
12+
echo "\n";
13+
14+
?>
15+
===DONE===
16+
<?php exit(0); ?>
17+
--EXPECT--
18+
MongoDB\BSON\ObjectID::__set_state(array(
19+
'oid' => '576c25db6118fd406e6e6471',
20+
))
21+
===DONE===

tests/bson/bson-objectid_error-003.phpt

Lines changed: 0 additions & 28 deletions
This file was deleted.

0 commit comments

Comments
 (0)