Skip to content

Commit 9ccbea5

Browse files
committed
PHPC-779: Switch Javascript from O to C type serialization
1 parent 3dc33ac commit 9ccbea5

File tree

5 files changed

+134
-7
lines changed

5 files changed

+134
-7
lines changed

src/BSON/Javascript.c

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@
3434
#include <ext/standard/info.h>
3535
#include <Zend/zend_interfaces.h>
3636
#include <ext/spl/spl_iterators.h>
37+
#include <ext/standard/php_var.h>
38+
#if PHP_VERSION_ID >= 70000
39+
# include <zend_smart_str.h>
40+
#else
41+
# include <ext/standard/php_smart_str.h>
42+
#endif
3743
/* Our Compatability header */
3844
#include "phongo_compat.h"
3945

@@ -227,6 +233,120 @@ PHP_METHOD(Javascript, getScope)
227233
}
228234
/* }}} */
229235

236+
/* {{{ proto string Javascript::serialize()
237+
*/
238+
PHP_METHOD(Javascript, serialize)
239+
{
240+
php_phongo_javascript_t *intern;
241+
#if PHP_VERSION_ID >= 70000
242+
zval retval;
243+
#else
244+
zval *retval;
245+
#endif
246+
php_phongo_bson_state state = PHONGO_BSON_STATE_INITIALIZER;
247+
248+
php_serialize_data_t var_hash;
249+
smart_str buf = { 0 };
250+
251+
intern = Z_JAVASCRIPT_OBJ_P(getThis());
252+
253+
if (zend_parse_parameters_none() == FAILURE) {
254+
return;
255+
}
256+
257+
#if PHP_VERSION_ID >= 70000
258+
if (intern->scope && intern->scope->len) {
259+
if (!phongo_bson_to_zval_ex(bson_get_data(intern->scope), intern->scope->len, &state)) {
260+
return;
261+
}
262+
Z_ADDREF(state.zchild);
263+
} else {
264+
ZVAL_NULL(&state.zchild);
265+
}
266+
#else
267+
if (intern->scope && intern->scope->len) {
268+
if (!phongo_bson_to_zval_ex(bson_get_data(intern->scope), intern->scope->len, &state)) {
269+
return;
270+
}
271+
Z_ADDREF_P(state.zchild);
272+
} else {
273+
MAKE_STD_ZVAL(state.zchild);
274+
ZVAL_NULL(state.zchild);
275+
Z_ADDREF_P(state.zchild);
276+
}
277+
#endif
278+
279+
#if PHP_VERSION_ID >= 70000
280+
array_init_size(&retval, 2);
281+
ADD_ASSOC_STRINGL(&retval, "code", intern->code, intern->code_len);
282+
ADD_ASSOC_ZVAL(&retval, "scope", &state.zchild);
283+
#else
284+
ALLOC_INIT_ZVAL(retval);
285+
array_init_size(retval, 2);
286+
ADD_ASSOC_STRINGL(retval, "code", intern->code, intern->code_len);
287+
ADD_ASSOC_ZVAL(retval, "scope", state.zchild);
288+
#endif
289+
290+
PHP_VAR_SERIALIZE_INIT(var_hash);
291+
php_var_serialize(&buf, &retval, &var_hash TSRMLS_CC);
292+
smart_str_0(&buf);
293+
PHP_VAR_SERIALIZE_DESTROY(var_hash);
294+
295+
PHONGO_RETVAL_SMART_STR(buf);
296+
297+
smart_str_free(&buf);
298+
zval_ptr_dtor(&retval);
299+
zval_ptr_dtor(&state.zchild);
300+
}
301+
/* }}} */
302+
303+
/* {{{ proto string Javascript::unserialize(string $serialized)
304+
*/
305+
PHP_METHOD(Javascript, unserialize)
306+
{
307+
php_phongo_javascript_t *intern;
308+
zend_error_handling error_handling;
309+
char *serialized;
310+
phongo_zpp_char_len serialized_len;
311+
#if PHP_VERSION_ID >= 70000
312+
zval props;
313+
#else
314+
zval *props;
315+
#endif
316+
php_unserialize_data_t var_hash;
317+
318+
intern = Z_JAVASCRIPT_OBJ_P(getThis());
319+
320+
zend_replace_error_handling(EH_THROW, phongo_exception_from_phongo_domain(PHONGO_ERROR_INVALID_ARGUMENT), &error_handling TSRMLS_CC);
321+
322+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &serialized, &serialized_len) == FAILURE) {
323+
zend_restore_error_handling(&error_handling TSRMLS_CC);
324+
return;
325+
}
326+
zend_restore_error_handling(&error_handling TSRMLS_CC);
327+
328+
#if PHP_VERSION_ID < 70000
329+
ALLOC_INIT_ZVAL(props);
330+
#endif
331+
PHP_VAR_UNSERIALIZE_INIT(var_hash);
332+
if (!php_var_unserialize(&props, (const unsigned char**) &serialized, (unsigned char *) serialized + serialized_len, &var_hash TSRMLS_CC)) {
333+
zval_ptr_dtor(&props);
334+
phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE TSRMLS_CC, "%s unserialization failed", ZSTR_VAL(php_phongo_javascript_ce->name));
335+
336+
PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
337+
return;
338+
}
339+
PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
340+
341+
#if PHP_VERSION_ID >= 70000
342+
php_phongo_javascript_init_from_hash(intern, HASH_OF(&props) TSRMLS_CC);
343+
#else
344+
php_phongo_javascript_init_from_hash(intern, HASH_OF(props) TSRMLS_CC);
345+
#endif
346+
zval_ptr_dtor(&props);
347+
}
348+
/* }}} */
349+
230350
/* {{{ BSON\Javascript */
231351

232352
ZEND_BEGIN_ARG_INFO_EX(ai_Javascript___construct, 0, 0, 1)
@@ -238,6 +358,10 @@ ZEND_BEGIN_ARG_INFO_EX(ai_Javascript___set_state, 0, 0, 1)
238358
ZEND_ARG_ARRAY_INFO(0, properties, 0)
239359
ZEND_END_ARG_INFO()
240360

361+
ZEND_BEGIN_ARG_INFO_EX(ai_Javascript_unserialize, 0, 0, 1)
362+
ZEND_ARG_INFO(0, serialized)
363+
ZEND_END_ARG_INFO()
364+
241365
ZEND_BEGIN_ARG_INFO_EX(ai_Javascript_void, 0, 0, 0)
242366
ZEND_END_ARG_INFO()
243367

@@ -246,6 +370,8 @@ static zend_function_entry php_phongo_javascript_me[] = {
246370
PHP_ME(Javascript, __set_state, ai_Javascript___set_state, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
247371
PHP_ME(Javascript, __toString, ai_Javascript_void, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
248372
PHP_ME(Javascript, __wakeup, ai_Javascript_void, ZEND_ACC_PUBLIC)
373+
PHP_ME(Javascript, serialize, ai_Javascript_void, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
374+
PHP_ME(Javascript, unserialize, ai_Javascript_unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
249375
PHP_ME(Javascript, getCode, ai_Javascript_void, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
250376
PHP_ME(Javascript, getScope, ai_Javascript_void, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
251377
PHP_FE_END
@@ -387,6 +513,7 @@ PHP_MINIT_FUNCTION(Javascript)
387513
PHONGO_CE_FINAL(php_phongo_javascript_ce);
388514

389515
zend_class_implements(php_phongo_javascript_ce TSRMLS_CC, 1, php_phongo_type_ce);
516+
zend_class_implements(php_phongo_javascript_ce TSRMLS_CC, 1, zend_ce_serializable);
390517

391518
memcpy(&php_phongo_handler_javascript, phongo_get_std_object_handlers(), sizeof(zend_object_handlers));
392519
php_phongo_handler_javascript.get_properties = php_phongo_javascript_get_properties;

tests/bson/bson-javascript-serialization-001.phpt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ object(MongoDB\BSON\Javascript)#%d (%d) {
2929
["scope"]=>
3030
NULL
3131
}
32-
string(101) "O:23:"MongoDB\BSON\Javascript":2:{s:4:"code";s:33:"function foo(bar) { return bar; }";s:5:"scope";N;}"
32+
string(108) "C:23:"MongoDB\BSON\Javascript":72:{a:2:{s:4:"code";s:33:"function foo(bar) { return bar; }";s:5:"scope";N;}}"
3333
object(MongoDB\BSON\Javascript)#%d (%d) {
3434
["code"]=>
3535
string(33) "function foo(bar) { return bar; }"
@@ -44,7 +44,7 @@ object(MongoDB\BSON\Javascript)#%d (%d) {
4444
object(stdClass)#%d (%d) {
4545
}
4646
}
47-
string(118) "O:23:"MongoDB\BSON\Javascript":2:{s:4:"code";s:33:"function foo(bar) { return bar; }";s:5:"scope";O:8:"stdClass":0:{}}"
47+
string(125) "C:23:"MongoDB\BSON\Javascript":89:{a:2:{s:4:"code";s:33:"function foo(bar) { return bar; }";s:5:"scope";O:8:"stdClass":0:{}}}"
4848
object(MongoDB\BSON\Javascript)#%d (%d) {
4949
["code"]=>
5050
string(33) "function foo(bar) { return bar; }"
@@ -62,7 +62,7 @@ object(MongoDB\BSON\Javascript)#%d (%d) {
6262
int(42)
6363
}
6464
}
65-
string(130) "O:23:"MongoDB\BSON\Javascript":2:{s:4:"code";s:30:"function foo() { return foo; }";s:5:"scope";O:8:"stdClass":1:{s:3:"foo";i:42;}}"
65+
string(138) "C:23:"MongoDB\BSON\Javascript":101:{a:2:{s:4:"code";s:30:"function foo() { return foo; }";s:5:"scope";O:8:"stdClass":1:{s:3:"foo";i:42;}}}"
6666
object(MongoDB\BSON\Javascript)#%d (%d) {
6767
["code"]=>
6868
string(30) "function foo() { return foo; }"
@@ -85,7 +85,7 @@ object(MongoDB\BSON\Javascript)#%d (%d) {
8585
}
8686
}
8787
}
88-
string(198) "O:23:"MongoDB\BSON\Javascript":2:{s:4:"code";s:29:"function foo() { return id; }";s:5:"scope";O:8:"stdClass":1:{s:2:"id";O:21:"MongoDB\BSON\ObjectID":1:{s:3:"oid";s:24:"53e2a1c40640fd72175d4603";}}}"
88+
string(206) "C:23:"MongoDB\BSON\Javascript":169:{a:2:{s:4:"code";s:29:"function foo() { return id; }";s:5:"scope";O:8:"stdClass":1:{s:2:"id";O:21:"MongoDB\BSON\ObjectID":1:{s:3:"oid";s:24:"53e2a1c40640fd72175d4603";}}}}"
8989
object(MongoDB\BSON\Javascript)#%d (%d) {
9090
["code"]=>
9191
string(29) "function foo() { return id; }"

tests/bson/bson-javascript-serialization_error-001.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ MongoDB\BSON\Javascript unserialization requires "code" string field
66
require_once __DIR__ . '/../utils/tools.php';
77

88
echo throws(function() {
9-
unserialize('O:23:"MongoDB\BSON\Javascript":1:{s:4:"code";i:0;}');
9+
unserialize('C:23:"MongoDB\BSON\Javascript":21:{a:1:{s:4:"code";i:0;}}');
1010
}, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n";
1111

1212
?>

tests/bson/bson-javascript-serialization_error-002.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ MongoDB\BSON\Javascript unserialization expects optional scope to be array or ob
66
require_once __DIR__ . '/../utils/tools.php';
77

88
echo throws(function() {
9-
unserialize('O:23:"MongoDB\BSON\Javascript":2:{s:4:"code";s:17:"function foo() {}";s:5:"scope";s:7:"INVALID";}');
9+
unserialize('C:23:"MongoDB\BSON\Javascript":68:{a:2:{s:4:"code";s:17:"function foo() {}";s:5:"scope";s:7:"INVALID";}}');
1010
}, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n";
1111

1212
?>

tests/bson/bson-javascript-serialization_error-003.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ MongoDB\BSON\Javascript unserialization does not allow code to contain null byte
66
require_once __DIR__ . '/../utils/tools.php';
77

88
echo throws(function() {
9-
unserialize('O:23:"MongoDB\BSON\Javascript":1:{s:4:"code";s:30:"function foo() { return ' . "'\0'" . '; }";}');
9+
unserialize('C:23:"MongoDB\BSON\Javascript":55:{a:1:{s:4:"code";s:30:"function foo() { return ' . "'\0'" . '; }";}}');
1010
}, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n";
1111

1212
?>

0 commit comments

Comments
 (0)