Skip to content

Commit dcd1920

Browse files
committed
PHPC-460: Regex serialization and var_export
1 parent ef1eee4 commit dcd1920

File tree

4 files changed

+179
-47
lines changed

4 files changed

+179
-47
lines changed

src/BSON/Regex.c

Lines changed: 126 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,38 @@ PHONGO_API zend_class_entry *php_phongo_regex_ce;
4646

4747
zend_object_handlers php_phongo_handler_regex;
4848

49+
/* Initialize the object from a string and return whether it was successful. */
50+
static bool php_phongo_regex_init(php_phongo_regex_t *intern, const char *pattern, phongo_zpp_char_len pattern_len, const char *flags, phongo_zpp_char_len flags_len)
51+
{
52+
intern->pattern = estrndup(pattern, pattern_len);
53+
intern->pattern_len = pattern_len;
54+
intern->flags = estrndup(flags, flags_len);
55+
intern->flags_len = flags_len;
56+
57+
return true;
58+
}
59+
60+
/* Initialize the object from a HashTable and return whether it was successful. */
61+
static bool php_phongo_regex_init_from_hash(php_phongo_regex_t *intern, HashTable *props)
62+
{
63+
#if PHP_VERSION_ID >= 70000
64+
zval *pattern, *flags;
65+
66+
if ((pattern = zend_hash_str_find(props, "pattern", sizeof("pattern")-1)) && Z_TYPE_P(pattern) == IS_STRING &&
67+
(flags = zend_hash_str_find(props, "flags", sizeof("flags")-1)) && Z_TYPE_P(flags) == IS_STRING) {
68+
return php_phongo_regex_init(intern, Z_STRVAL_P(pattern), Z_STRLEN_P(pattern), Z_STRVAL_P(flags), Z_STRLEN_P(flags));
69+
}
70+
#else
71+
zval **pattern, **flags;
72+
73+
if (zend_hash_find(props, "pattern", sizeof("pattern"), (void**) &pattern) == SUCCESS && Z_TYPE_PP(pattern) == IS_STRING &&
74+
zend_hash_find(props, "flags", sizeof("flags"), (void**) &flags) == SUCCESS && Z_TYPE_PP(flags) == IS_STRING) {
75+
return php_phongo_regex_init(intern, Z_STRVAL_PP(pattern), Z_STRLEN_PP(pattern), Z_STRVAL_PP(flags), Z_STRLEN_PP(flags));
76+
}
77+
#endif
78+
return false;
79+
}
80+
4981
/* {{{ proto BSON\Regex Regex::__construct(string $pattern, string $flags)
5082
Constructs a new regular expression. */
5183
PHP_METHOD(Regex, __construct)
@@ -67,11 +99,7 @@ PHP_METHOD(Regex, __construct)
6799
}
68100
zend_restore_error_handling(&error_handling TSRMLS_CC);
69101

70-
71-
intern->pattern = estrndup(pattern, pattern_len);
72-
intern->pattern_len = pattern_len;
73-
intern->flags = estrndup(flags, flags_len);
74-
intern->flags_len = flags_len;
102+
php_phongo_regex_init(intern, pattern, pattern_len, flags, flags_len);
75103
}
76104
/* }}} */
77105
/* {{{ proto void Regex::getPattern()
@@ -108,6 +136,30 @@ PHP_METHOD(Regex, getFlags)
108136
PHONGO_RETURN_STRINGL(intern->flags, intern->flags_len);
109137
}
110138
/* }}} */
139+
140+
/* {{{ proto Regex::__set_state(array $properties)
141+
*/
142+
PHP_METHOD(Regex, __set_state)
143+
{
144+
php_phongo_regex_t *intern;
145+
HashTable *props;
146+
zval *array;
147+
148+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) == FAILURE) {
149+
RETURN_FALSE;
150+
}
151+
152+
object_init_ex(return_value, php_phongo_regex_ce);
153+
154+
intern = Z_REGEX_OBJ_P(return_value);
155+
props = Z_ARRVAL_P(array);
156+
157+
if (!php_phongo_regex_init_from_hash(intern, props)) {
158+
php_error(E_ERROR, "Invalid serialization data for Regex object");
159+
}
160+
}
161+
/* }}} */
162+
111163
/* {{{ proto void Regex::__toString()
112164
*/
113165
PHP_METHOD(Regex, __toString)
@@ -130,6 +182,25 @@ PHP_METHOD(Regex, __toString)
130182
}
131183
/* }}} */
132184

185+
/* {{{ proto Regex::__wakeup()
186+
*/
187+
PHP_METHOD(Regex, __wakeup)
188+
{
189+
php_phongo_regex_t *intern;
190+
HashTable *props;
191+
192+
if (zend_parse_parameters_none() == FAILURE) {
193+
return;
194+
}
195+
196+
intern = Z_REGEX_OBJ_P(getThis());
197+
props = zend_std_get_properties(getThis() TSRMLS_CC);
198+
199+
if (!php_phongo_regex_init_from_hash(intern, props)) {
200+
php_error(E_ERROR, "Invalid serialization data for Regex object");
201+
}
202+
}
203+
/* }}} */
133204

134205
/* {{{ BSON\Regex */
135206

@@ -138,22 +209,20 @@ ZEND_BEGIN_ARG_INFO_EX(ai_Regex___construct, 0, 0, 2)
138209
ZEND_ARG_INFO(0, flags)
139210
ZEND_END_ARG_INFO();
140211

141-
ZEND_BEGIN_ARG_INFO_EX(ai_Regex_getPattern, 0, 0, 0)
142-
ZEND_END_ARG_INFO();
143-
144-
ZEND_BEGIN_ARG_INFO_EX(ai_Regex_getFlags, 0, 0, 0)
145-
ZEND_END_ARG_INFO();
146-
147-
ZEND_BEGIN_ARG_INFO_EX(ai_Regex___toString, 0, 0, 0)
148-
ZEND_END_ARG_INFO();
212+
ZEND_BEGIN_ARG_INFO_EX(ai_Regex___set_state, 0, 0, 1)
213+
ZEND_ARG_ARRAY_INFO(0, properties, 0)
214+
ZEND_END_ARG_INFO()
149215

216+
ZEND_BEGIN_ARG_INFO_EX(ai_Regex_void, 0, 0, 0)
217+
ZEND_END_ARG_INFO()
150218

151219
static zend_function_entry php_phongo_regex_me[] = {
152220
PHP_ME(Regex, __construct, ai_Regex___construct, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
153-
PHP_ME(Regex, getPattern, ai_Regex_getPattern, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
154-
PHP_ME(Regex, getFlags, ai_Regex_getFlags, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
155-
PHP_ME(Regex, __toString, ai_Regex___toString, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
156-
PHP_ME(Manager, __wakeUp, NULL, ZEND_ACC_PUBLIC)
221+
PHP_ME(Regex, __set_state, ai_Regex___set_state, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
222+
PHP_ME(Regex, __toString, ai_Regex_void, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
223+
PHP_ME(Regex, __wakeup, ai_Regex_void, ZEND_ACC_PUBLIC)
224+
PHP_ME(Regex, getPattern, ai_Regex_void, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
225+
PHP_ME(Regex, getFlags, ai_Regex_void, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
157226
PHP_FE_END
158227
};
159228

@@ -224,6 +293,45 @@ HashTable *php_phongo_regex_get_debug_info(zval *object, int *is_temp TSRMLS_DC)
224293

225294
return Z_ARRVAL(retval);
226295
} /* }}} */
296+
297+
HashTable *php_phongo_regex_get_properties(zval *object TSRMLS_DC) /* {{{ */
298+
{
299+
php_phongo_regex_t *intern;
300+
HashTable *props;
301+
302+
intern = Z_REGEX_OBJ_P(object);
303+
props = zend_std_get_properties(object TSRMLS_CC);
304+
305+
if (!intern->pattern) {
306+
return props;
307+
}
308+
309+
#if PHP_VERSION_ID >= 70000
310+
{
311+
zval pattern, flags;
312+
313+
ZVAL_STRINGL(&pattern, intern->pattern, intern->pattern_len);
314+
zend_hash_str_update(props, "pattern", sizeof("pattern")-1, &pattern);
315+
316+
ZVAL_STRINGL(&flags, intern->flags, intern->flags_len);
317+
zend_hash_str_update(props, "flags", sizeof("flags")-1, &flags);
318+
}
319+
#else
320+
{
321+
zval *pattern, *flags;
322+
323+
MAKE_STD_ZVAL(pattern);
324+
ZVAL_STRINGL(pattern, intern->pattern, intern->pattern_len, 1);
325+
zend_hash_update(props, "pattern", sizeof("pattern"), &pattern, sizeof(pattern), NULL);
326+
327+
MAKE_STD_ZVAL(flags);
328+
ZVAL_STRINGL(flags, intern->flags, intern->flags_len, 1);
329+
zend_hash_update(props, "flags", sizeof("flags"), &flags, sizeof(flags), NULL);
330+
}
331+
#endif
332+
333+
return props;
334+
} /* }}} */
227335
/* }}} */
228336

229337
/* {{{ PHP_MINIT_FUNCTION */
@@ -236,11 +344,10 @@ PHP_MINIT_FUNCTION(Regex)
236344
php_phongo_regex_ce = zend_register_internal_class(&ce TSRMLS_CC);
237345
php_phongo_regex_ce->create_object = php_phongo_regex_create_object;
238346
PHONGO_CE_FINAL(php_phongo_regex_ce);
239-
PHONGO_CE_DISABLE_SERIALIZATION(php_phongo_regex_ce);
240347

241348
zend_class_implements(php_phongo_regex_ce TSRMLS_CC, 1, php_phongo_type_ce);
242349
memcpy(&php_phongo_handler_regex, phongo_get_std_object_handlers(), sizeof(zend_object_handlers));
243-
php_phongo_handler_regex.get_debug_info = php_phongo_regex_get_debug_info;
350+
php_phongo_handler_regex.get_properties = php_phongo_regex_get_properties;
244351
#if PHP_VERSION_ID >= 70000
245352
php_phongo_handler_regex.free_obj = php_phongo_regex_free_object;
246353
php_phongo_handler_regex.offset = XtOffsetOf(php_phongo_regex_t, std);

tests/bson/bson-regex-003.phpt

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
--TEST--
2+
MongoDB\BSON\Regex 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($regex = new MongoDB\BSON\Regex('regexp', 'i'));
10+
var_dump($s = serialize($regex));
11+
var_dump(unserialize($s));
12+
13+
?>
14+
===DONE===
15+
<?php exit(0); ?>
16+
--EXPECTF--
17+
object(MongoDB\BSON\Regex)#%d (%d) {
18+
["pattern"]=>
19+
string(6) "regexp"
20+
["flags"]=>
21+
string(1) "i"
22+
}
23+
string(77) "O:18:"MongoDB\BSON\Regex":2:{s:7:"pattern";s:6:"regexp";s:5:"flags";s:1:"i";}"
24+
object(MongoDB\BSON\Regex)#%d (%d) {
25+
["pattern"]=>
26+
string(6) "regexp"
27+
["flags"]=>
28+
string(1) "i"
29+
}
30+
===DONE===
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
--TEST--
2+
MongoDB\BSON\Regex::__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\Regex::__set_state([
10+
'pattern' => 'regexp',
11+
'flags' => 'i',
12+
]));
13+
echo "\n";
14+
15+
?>
16+
===DONE===
17+
<?php exit(0); ?>
18+
--EXPECT--
19+
MongoDB\BSON\Regex::__set_state(array(
20+
'pattern' => 'regexp',
21+
'flags' => 'i',
22+
))
23+
===DONE===

tests/bson/bson-regex_error-003.phpt

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

0 commit comments

Comments
 (0)