Skip to content

Commit 06ee895

Browse files
committed
PHPC-460: Binary serialization and var_export
1 parent 9b29049 commit 06ee895

File tree

5 files changed

+181
-59
lines changed

5 files changed

+181
-59
lines changed

src/BSON/Binary.c

Lines changed: 116 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,41 @@ PHONGO_API zend_class_entry *php_phongo_binary_ce;
4646

4747
zend_object_handlers php_phongo_handler_binary;
4848

49+
/* Initialize the object from a string and return whether it was successful. */
50+
static bool php_phongo_binary_init(php_phongo_binary_t *intern, const char *data, phongo_zpp_char_len data_len, phongo_long type)
51+
{
52+
if (type < 0 || type > UINT8_MAX) {
53+
return false;
54+
}
55+
56+
intern->data = estrndup(data, data_len);
57+
intern->data_len = data_len;
58+
intern->type = (uint8_t) type;
59+
60+
return true;
61+
}
62+
63+
/* Initialize the object from a HashTable and return whether it was successful. */
64+
static bool php_phongo_binary_init_from_hash(php_phongo_binary_t *intern, HashTable *props)
65+
{
66+
#if PHP_VERSION_ID >= 70000
67+
zval *data, *type;
68+
69+
if ((data = zend_hash_str_find(props, "data", sizeof("data")-1)) && Z_TYPE_P(data) == IS_STRING &&
70+
(type = zend_hash_str_find(props, "type", sizeof("type")-1)) && Z_TYPE_P(type) == IS_LONG) {
71+
return php_phongo_binary_init(intern, Z_STRVAL_P(data), Z_STRLEN_P(data), Z_LVAL_P(type));
72+
}
73+
#else
74+
zval **data, **type;
75+
76+
if (zend_hash_find(props, "data", sizeof("data"), (void**) &data) == SUCCESS && Z_TYPE_PP(data) == IS_STRING &&
77+
zend_hash_find(props, "type", sizeof("type"), (void**) &type) == SUCCESS && Z_TYPE_PP(type) == IS_LONG) {
78+
return php_phongo_binary_init(intern, Z_STRVAL_PP(data), Z_STRLEN_PP(data), Z_LVAL_PP(type));
79+
}
80+
#endif
81+
return false;
82+
}
83+
4984
/* {{{ proto BSON\Binary Binary::__construct(string $data, int $type)
5085
Construct a new BSON Binary type */
5186
PHP_METHOD(Binary, __construct)
@@ -66,16 +101,55 @@ PHP_METHOD(Binary, __construct)
66101
}
67102
zend_restore_error_handling(&error_handling TSRMLS_CC);
68103

69-
if (type < 0 || type > UINT8_MAX) {
104+
if (!php_phongo_binary_init(intern, data, data_len, type)) {
70105
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Expected type to be an unsigned 8-bit integer, %" PHONGO_LONG_FORMAT " given", type);
106+
}
107+
}
108+
/* }}} */
109+
110+
/* {{{ proto Binary::__set_state(array $properties)
111+
*/
112+
PHP_METHOD(Binary, __set_state)
113+
{
114+
php_phongo_binary_t *intern;
115+
HashTable *props;
116+
zval *array;
117+
118+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) == FAILURE) {
119+
RETURN_FALSE;
120+
}
121+
122+
object_init_ex(return_value, php_phongo_binary_ce);
123+
124+
intern = Z_BINARY_OBJ_P(return_value);
125+
props = Z_ARRVAL_P(array);
126+
127+
if (!php_phongo_binary_init_from_hash(intern, props)) {
128+
php_error(E_ERROR, "Invalid serialization data for Binary object");
129+
}
130+
}
131+
/* }}} */
132+
133+
/* {{{ proto Binary::__wakeup()
134+
*/
135+
PHP_METHOD(Binary, __wakeup)
136+
{
137+
php_phongo_binary_t *intern;
138+
HashTable *props;
139+
140+
if (zend_parse_parameters_none() == FAILURE) {
71141
return;
72142
}
73143

74-
intern->data = estrndup(data, data_len);
75-
intern->data_len = data_len;
76-
intern->type = (uint8_t) type;
144+
intern = Z_BINARY_OBJ_P(getThis());
145+
props = zend_std_get_properties(getThis() TSRMLS_CC);
146+
147+
if (!php_phongo_binary_init_from_hash(intern, props)) {
148+
php_error(E_ERROR, "Invalid serialization data for Binary object");
149+
}
77150
}
78151
/* }}} */
152+
79153
/* {{{ proto string Binary::getData()
80154
*/
81155
PHP_METHOD(Binary, getData)
@@ -117,18 +191,19 @@ ZEND_BEGIN_ARG_INFO_EX(ai_Binary___construct, 0, 0, 2)
117191
ZEND_ARG_INFO(0, type)
118192
ZEND_END_ARG_INFO();
119193

120-
ZEND_BEGIN_ARG_INFO_EX(ai_Binary_getData, 0, 0, 0)
194+
ZEND_BEGIN_ARG_INFO_EX(ai_Binary___set_state, 0, 0, 1)
195+
ZEND_ARG_ARRAY_INFO(0, properties, 0)
121196
ZEND_END_ARG_INFO();
122197

123-
ZEND_BEGIN_ARG_INFO_EX(ai_Binary_getType, 0, 0, 0)
198+
ZEND_BEGIN_ARG_INFO_EX(ai_Binary_void, 0, 0, 0)
124199
ZEND_END_ARG_INFO();
125200

126-
127201
static zend_function_entry php_phongo_binary_me[] = {
128202
PHP_ME(Binary, __construct, ai_Binary___construct, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
129-
PHP_ME(Binary, getData, ai_Binary_getData, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
130-
PHP_ME(Binary, getType, ai_Binary_getType, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
131-
PHP_ME(Manager, __wakeUp, NULL, ZEND_ACC_PUBLIC)
203+
PHP_ME(Binary, __set_state, ai_Binary___set_state, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
204+
PHP_ME(Binary, getData, ai_Binary_void, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
205+
PHP_ME(Binary, getType, ai_Binary_void, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
206+
PHP_ME(Binary, __wakeup, ai_Binary_void, ZEND_ACC_PUBLIC)
132207
PHP_FE_END
133208
};
134209

@@ -174,23 +249,43 @@ phongo_create_object_retval php_phongo_binary_create_object(zend_class_entry *cl
174249
#endif
175250
} /* }}} */
176251

177-
HashTable *php_phongo_binary_get_debug_info(zval *object, int *is_temp TSRMLS_DC) /* {{{ */
252+
HashTable *php_phongo_binary_get_properties(zval *object TSRMLS_DC) /* {{{ */
178253
{
179254
php_phongo_binary_t *intern;
255+
HashTable *props;
256+
257+
intern = Z_BINARY_OBJ_P(object);
258+
props = zend_std_get_properties(object TSRMLS_CC);
259+
260+
if (!intern->data) {
261+
return props;
262+
}
263+
180264
#if PHP_VERSION_ID >= 70000
181-
zval retval;
265+
{
266+
zval data, type;
267+
268+
ZVAL_STRINGL(&data, intern->data, intern->data_len);
269+
zend_hash_str_update(props, "data", sizeof("data")-1, &data);
270+
271+
ZVAL_LONG(&type, intern->type);
272+
zend_hash_str_update(props, "type", sizeof("type")-1, &type);
273+
}
182274
#else
183-
zval retval = zval_used_for_init;
184-
#endif
275+
{
276+
zval *data, *type;
185277

186-
intern = Z_BINARY_OBJ_P(object);
187-
*is_temp = 1;
188-
array_init_size(&retval, 2);
278+
MAKE_STD_ZVAL(data);
279+
ZVAL_STRINGL(data, intern->data, intern->data_len, 1);
280+
zend_hash_update(props, "data", sizeof("data"), &data, sizeof(data), NULL);
189281

190-
ADD_ASSOC_STRINGL(&retval, "data", intern->data, intern->data_len);
191-
ADD_ASSOC_LONG_EX(&retval, "type", intern->type);
282+
MAKE_STD_ZVAL(type);
283+
ZVAL_LONG(type, intern->type);
284+
zend_hash_update(props, "type", sizeof("type"), &type, sizeof(type), NULL);
285+
}
286+
#endif
192287

193-
return Z_ARRVAL(retval);
288+
return props;
194289
} /* }}} */
195290
/* }}} */
196291

@@ -204,12 +299,11 @@ PHP_MINIT_FUNCTION(Binary)
204299
php_phongo_binary_ce = zend_register_internal_class(&ce TSRMLS_CC);
205300
php_phongo_binary_ce->create_object = php_phongo_binary_create_object;
206301
PHONGO_CE_FINAL(php_phongo_binary_ce);
207-
PHONGO_CE_DISABLE_SERIALIZATION(php_phongo_binary_ce);
208302

209303
zend_class_implements(php_phongo_binary_ce TSRMLS_CC, 1, php_phongo_type_ce);
210304

211305
memcpy(&php_phongo_handler_binary, phongo_get_std_object_handlers(), sizeof(zend_object_handlers));
212-
php_phongo_handler_binary.get_debug_info = php_phongo_binary_get_debug_info;
306+
php_phongo_handler_binary.get_properties = php_phongo_binary_get_properties;
213307
#if PHP_VERSION_ID >= 70000
214308
php_phongo_handler_binary.free_obj = php_phongo_binary_free_object;
215309
php_phongo_handler_binary.offset = XtOffsetOf(php_phongo_binary_t, std);

tests/bson/bson-binary-002.phpt

2.12 KB
Binary file not shown.
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
--TEST--
2+
MongoDB\BSON\Binary::__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+
$tests = [
10+
['foobar', MongoDB\BSON\Binary::TYPE_GENERIC],
11+
['', MongoDB\BSON\Binary::TYPE_GENERIC],
12+
["\0foo", MongoDB\BSON\Binary::TYPE_GENERIC],
13+
[hex2bin('123e4567e89b12d3a456426655440000'), MongoDB\BSON\Binary::TYPE_UUID],
14+
[md5('foobar', true), MongoDB\BSON\Binary::TYPE_MD5],
15+
];
16+
17+
foreach ($tests as $test) {
18+
list($data, $type) = $test;
19+
20+
var_export(MongoDB\BSON\Binary::__set_state([
21+
'data' => $data,
22+
'type' => $type,
23+
]));
24+
echo "\n\n";
25+
}
26+
27+
?>
28+
===DONE===
29+
<?php exit(0); ?>
30+
--EXPECT--
31+
MongoDB\BSON\Binary::__set_state(array(
32+
'data' => 'foobar',
33+
'type' => 0,
34+
))
35+
36+
MongoDB\BSON\Binary::__set_state(array(
37+
'data' => '',
38+
'type' => 0,
39+
))
40+
41+
MongoDB\BSON\Binary::__set_state(array(
42+
'data' => '' . "\0" . 'foo',
43+
'type' => 0,
44+
))
45+
46+
MongoDB\BSON\Binary::__set_state(array(
47+
'data' => '>Egè›Ó¤VBfUD' . "\0" . '' . "\0" . '',
48+
'type' => 4,
49+
))
50+
51+
MongoDB\BSON\Binary::__set_state(array(
52+
'data' => '8Xö"0¬<‘_0 fCÆ?',
53+
'type' => 5,
54+
))
55+
56+
===DONE===

tests/bson/bson-binary_error-003.phpt

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
--TEST--
2-
BSON BSON\Binary cannot be serialized
2+
BSON BSON\Binary constructor requires unsigned 8-bit integer for type
33
--SKIPIF--
44
<?php require __DIR__ . "/../utils/basic-skipif.inc"?>
55
--FILE--
@@ -9,20 +9,19 @@ require_once __DIR__ . "/../utils/basic.inc";
99
use MongoDB\BSON as BSON;
1010

1111
echo throws(function() {
12-
serialize(new BSON\Binary('foo', BSON\Binary::TYPE_GENERIC));
13-
}, 'Exception'), "\n";
12+
new BSON\Binary('foo', -1);
13+
}, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n";
1414

1515
echo throws(function() {
16-
$classname = BSON_NAMESPACE . '\Binary';
17-
unserialize(sprintf('C:%d:"%s":0:{}', strlen($classname), $classname));
18-
}, 'Exception'), "\n";
16+
new BSON\Binary('foo', 256);
17+
}, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n";
1918

2019
?>
2120
===DONE===
2221
<?php exit(0); ?>
2322
--EXPECTF--
24-
OK: Got Exception
25-
Serialization of '%SBSON\Binary' is not allowed
26-
OK: Got Exception
27-
Unserialization of '%SBSON\Binary' is not allowed
23+
OK: Got MongoDB\Driver\Exception\InvalidArgumentException
24+
Expected type to be an unsigned 8-bit integer, -1 given
25+
OK: Got MongoDB\Driver\Exception\InvalidArgumentException
26+
Expected type to be an unsigned 8-bit integer, 256 given
2827
===DONE===

tests/bson/bson-binary_error-004.phpt

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

0 commit comments

Comments
 (0)