Skip to content

Commit 0a32ce9

Browse files
committed
PHPC-460: Timestamp serialization and var_export
1 parent dcd1920 commit 0a32ce9

10 files changed

+364
-65
lines changed

php_phongo.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2054,6 +2054,7 @@ void php_phongo_new_timestamp_from_increment_and_timestamp(zval *object, uint32_
20542054
intern = Z_TIMESTAMP_OBJ_P(object);
20552055
intern->increment = increment;
20562056
intern->timestamp = timestamp;
2057+
intern->initialized = true;
20572058
} /* }}} */
20582059
void php_phongo_new_javascript_from_javascript(int init, zval *object, const char *code, size_t code_len TSRMLS_DC) /* {{{ */
20592060
{

php_phongo_structs.h

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

203203
typedef struct {
204204
PHONGO_ZEND_OBJECT_PRE
205+
bool initialized;
205206
uint32_t increment;
206207
uint32_t timestamp;
207208
PHONGO_ZEND_OBJECT_POST

src/BSON/Timestamp.c

Lines changed: 124 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,37 @@ PHONGO_API zend_class_entry *php_phongo_timestamp_ce;
4646

4747
zend_object_handlers php_phongo_handler_timestamp;
4848

49+
/* Initialize the object from a string and return whether it was successful. */
50+
static bool php_phongo_timestamp_init(php_phongo_timestamp_t *intern, phongo_long increment, phongo_long timestamp)
51+
{
52+
intern->increment = increment;
53+
intern->timestamp = timestamp;
54+
intern->initialized = true;
55+
56+
return true;
57+
}
58+
59+
/* Initialize the object from a HashTable and return whether it was successful. */
60+
static bool php_phongo_timestamp_init_from_hash(php_phongo_timestamp_t *intern, HashTable *props)
61+
{
62+
#if PHP_VERSION_ID >= 70000
63+
zval *increment, *timestamp;
64+
65+
if ((increment = zend_hash_str_find(props, "increment", sizeof("increment")-1)) && Z_TYPE_P(increment) == IS_LONG &&
66+
(timestamp = zend_hash_str_find(props, "timestamp", sizeof("timestamp")-1)) && Z_TYPE_P(timestamp) == IS_LONG) {
67+
return php_phongo_timestamp_init(intern, Z_LVAL_P(increment), Z_LVAL_P(timestamp));
68+
}
69+
#else
70+
zval **increment, **timestamp;
71+
72+
if (zend_hash_find(props, "increment", sizeof("increment"), (void**) &increment) == SUCCESS && Z_TYPE_PP(increment) == IS_LONG &&
73+
zend_hash_find(props, "timestamp", sizeof("timestamp"), (void**) &timestamp) == SUCCESS && Z_TYPE_PP(timestamp) == IS_LONG) {
74+
return php_phongo_timestamp_init(intern, Z_LVAL_PP(increment), Z_LVAL_PP(timestamp));
75+
}
76+
#endif
77+
return false;
78+
}
79+
4980
/* {{{ proto BSON\Timestamp Timestamp::__construct(integer $increment, int $timestamp)
5081
Construct a new BSON Timestamp (4bytes increment, 4bytes timestamp) */
5182
PHP_METHOD(Timestamp, __construct)
@@ -75,10 +106,33 @@ PHP_METHOD(Timestamp, __construct)
75106
return;
76107
}
77108

78-
intern->increment = increment;
79-
intern->timestamp = timestamp;
109+
php_phongo_timestamp_init(intern, increment, timestamp);
110+
}
111+
/* }}} */
112+
113+
/* {{{ proto Timestamp::__set_state(array $properties)
114+
*/
115+
PHP_METHOD(Timestamp, __set_state)
116+
{
117+
php_phongo_timestamp_t *intern;
118+
HashTable *props;
119+
zval *array;
120+
121+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) == FAILURE) {
122+
RETURN_FALSE;
123+
}
124+
125+
object_init_ex(return_value, php_phongo_timestamp_ce);
126+
127+
intern = Z_TIMESTAMP_OBJ_P(return_value);
128+
props = Z_ARRVAL_P(array);
129+
130+
if (!php_phongo_timestamp_init_from_hash(intern, props)) {
131+
php_error(E_ERROR, "Invalid serialization data for Timestamp object");
132+
}
80133
}
81134
/* }}} */
135+
82136
/* {{{ proto string Timestamp::__toString()
83137
Returns [increment:timestamp] */
84138
PHP_METHOD(Timestamp, __toString)
@@ -100,21 +154,45 @@ PHP_METHOD(Timestamp, __toString)
100154
}
101155
/* }}} */
102156

157+
/* {{{ proto Timestamp::__wakeup()
158+
*/
159+
PHP_METHOD(Timestamp, __wakeup)
160+
{
161+
php_phongo_timestamp_t *intern;
162+
HashTable *props;
163+
164+
if (zend_parse_parameters_none() == FAILURE) {
165+
return;
166+
}
167+
168+
intern = Z_TIMESTAMP_OBJ_P(getThis());
169+
props = zend_std_get_properties(getThis() TSRMLS_CC);
170+
171+
if (!php_phongo_timestamp_init_from_hash(intern, props)) {
172+
php_error(E_ERROR, "Invalid serialization data for Timestamp object");
173+
}
174+
}
175+
/* }}} */
176+
103177
/* {{{ BSON\Timestamp */
104178

105179
ZEND_BEGIN_ARG_INFO_EX(ai_Timestamp___construct, 0, 0, 2)
106180
ZEND_ARG_INFO(0, increment)
107181
ZEND_ARG_INFO(0, timestamp)
108182
ZEND_END_ARG_INFO();
109183

110-
ZEND_BEGIN_ARG_INFO_EX(ai_Timestamp___toString, 0, 0, 0)
111-
ZEND_END_ARG_INFO();
184+
ZEND_BEGIN_ARG_INFO_EX(ai_Timestamp___set_state, 0, 0, 1)
185+
ZEND_ARG_ARRAY_INFO(0, properties, 0)
186+
ZEND_END_ARG_INFO()
112187

188+
ZEND_BEGIN_ARG_INFO_EX(ai_Timestamp_void, 0, 0, 0)
189+
ZEND_END_ARG_INFO()
113190

114191
static zend_function_entry php_phongo_timestamp_me[] = {
115192
PHP_ME(Timestamp, __construct, ai_Timestamp___construct, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
116-
PHP_ME(Timestamp, __toString, ai_Timestamp___toString, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
117-
PHP_ME(Manager, __wakeUp, NULL, ZEND_ACC_PUBLIC)
193+
PHP_ME(Timestamp, __set_state, ai_Timestamp___set_state, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
194+
PHP_ME(Timestamp, __toString, ai_Timestamp_void, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
195+
PHP_ME(Timestamp, __wakeup, ai_Timestamp_void, ZEND_ACC_PUBLIC)
118196
PHP_FE_END
119197
};
120198

@@ -177,6 +255,45 @@ HashTable *php_phongo_timestamp_get_debug_info(zval *object, int *is_temp TSRMLS
177255

178256
return Z_ARRVAL(retval);
179257
} /* }}} */
258+
259+
HashTable *php_phongo_timestamp_get_properties(zval *object TSRMLS_DC) /* {{{ */
260+
{
261+
php_phongo_timestamp_t *intern;
262+
HashTable *props;
263+
264+
intern = Z_TIMESTAMP_OBJ_P(object);
265+
props = zend_std_get_properties(object TSRMLS_CC);
266+
267+
if (!intern->initialized) {
268+
return props;
269+
}
270+
271+
#if PHP_VERSION_ID >= 70000
272+
{
273+
zval increment, timestamp;
274+
275+
ZVAL_LONG(&increment, intern->increment);
276+
zend_hash_str_update(props, "increment", sizeof("increment")-1, &increment);
277+
278+
ZVAL_LONG(&timestamp, intern->timestamp);
279+
zend_hash_str_update(props, "timestamp", sizeof("timestamp")-1, &timestamp);
280+
}
281+
#else
282+
{
283+
zval *increment, *timestamp;
284+
285+
MAKE_STD_ZVAL(increment);
286+
ZVAL_LONG(increment, intern->increment);
287+
zend_hash_update(props, "increment", sizeof("increment"), &increment, sizeof(increment), NULL);
288+
289+
MAKE_STD_ZVAL(timestamp);
290+
ZVAL_LONG(timestamp, intern->timestamp);
291+
zend_hash_update(props, "timestamp", sizeof("timestamp"), &timestamp, sizeof(timestamp), NULL);
292+
}
293+
#endif
294+
295+
return props;
296+
} /* }}} */
180297
/* }}} */
181298

182299
/* {{{ PHP_MINIT_FUNCTION */
@@ -189,11 +306,10 @@ PHP_MINIT_FUNCTION(Timestamp)
189306
php_phongo_timestamp_ce = zend_register_internal_class(&ce TSRMLS_CC);
190307
php_phongo_timestamp_ce->create_object = php_phongo_timestamp_create_object;
191308
PHONGO_CE_FINAL(php_phongo_timestamp_ce);
192-
PHONGO_CE_DISABLE_SERIALIZATION(php_phongo_timestamp_ce);
193309

194310
zend_class_implements(php_phongo_timestamp_ce TSRMLS_CC, 1, php_phongo_type_ce);
195311
memcpy(&php_phongo_handler_timestamp, phongo_get_std_object_handlers(), sizeof(zend_object_handlers));
196-
php_phongo_handler_timestamp.get_debug_info = php_phongo_timestamp_get_debug_info;
312+
php_phongo_handler_timestamp.get_properties = php_phongo_timestamp_get_properties;
197313
#if PHP_VERSION_ID >= 70000
198314
php_phongo_handler_timestamp.free_obj = php_phongo_timestamp_free_object;
199315
php_phongo_handler_timestamp.offset = XtOffsetOf(php_phongo_timestamp_t, std);

tests/bson/bson-timestamp-005.phpt

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
--TEST--
2+
MongoDB\BSON\Timestamp serialization
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+
[1234, 5678],
11+
[2147483647, 0],
12+
[0, 2147483647],
13+
];
14+
15+
foreach ($tests as $test) {
16+
list($increment, $timestamp) = $test;
17+
18+
var_dump($ts = new MongoDB\BSON\Timestamp($increment, $timestamp));
19+
var_dump($s = serialize($ts));
20+
var_dump(unserialize($s));
21+
echo "\n";
22+
}
23+
24+
?>
25+
===DONE===
26+
<?php exit(0); ?>
27+
--EXPECTF--
28+
object(MongoDB\BSON\Timestamp)#%d (%d) {
29+
["increment"]=>
30+
int(1234)
31+
["timestamp"]=>
32+
int(5678)
33+
}
34+
string(80) "O:22:"MongoDB\BSON\Timestamp":2:{s:9:"increment";i:1234;s:9:"timestamp";i:5678;}"
35+
object(MongoDB\BSON\Timestamp)#%d (%d) {
36+
["increment"]=>
37+
int(1234)
38+
["timestamp"]=>
39+
int(5678)
40+
}
41+
42+
object(MongoDB\BSON\Timestamp)#%d (%d) {
43+
["increment"]=>
44+
int(2147483647)
45+
["timestamp"]=>
46+
int(0)
47+
}
48+
string(83) "O:22:"MongoDB\BSON\Timestamp":2:{s:9:"increment";i:2147483647;s:9:"timestamp";i:0;}"
49+
object(MongoDB\BSON\Timestamp)#%d (%d) {
50+
["increment"]=>
51+
int(2147483647)
52+
["timestamp"]=>
53+
int(0)
54+
}
55+
56+
object(MongoDB\BSON\Timestamp)#%d (%d) {
57+
["increment"]=>
58+
int(0)
59+
["timestamp"]=>
60+
int(2147483647)
61+
}
62+
string(83) "O:22:"MongoDB\BSON\Timestamp":2:{s:9:"increment";i:0;s:9:"timestamp";i:2147483647;}"
63+
object(MongoDB\BSON\Timestamp)#%d (%d) {
64+
["increment"]=>
65+
int(0)
66+
["timestamp"]=>
67+
int(2147483647)
68+
}
69+
70+
===DONE===

tests/bson/bson-timestamp-006.phpt

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
--TEST--
2+
MongoDB\BSON\Timestamp serialization (64-bit)
3+
--SKIPIF--
4+
<?php if (8 !== PHP_INT_SIZE) { die('skip Only for 64-bit platform'); } ?>
5+
<?php require __DIR__ . "/../utils/basic-skipif.inc"; ?>
6+
--FILE--
7+
<?php
8+
require_once __DIR__ . "/../utils/basic.inc";
9+
10+
$tests = [
11+
[4294967295, 0],
12+
[0, 4294967295],
13+
];
14+
15+
foreach ($tests as $test) {
16+
list($increment, $timestamp) = $test;
17+
18+
var_dump($ts = new MongoDB\BSON\Timestamp($increment, $timestamp));
19+
var_dump($s = serialize($ts));
20+
var_dump(unserialize($s));
21+
echo "\n";
22+
}
23+
24+
?>
25+
===DONE===
26+
<?php exit(0); ?>
27+
--EXPECTF--
28+
object(MongoDB\BSON\Timestamp)#%d (%d) {
29+
["increment"]=>
30+
int(4294967295)
31+
["timestamp"]=>
32+
int(0)
33+
}
34+
string(83) "O:22:"MongoDB\BSON\Timestamp":2:{s:9:"increment";i:4294967295;s:9:"timestamp";i:0;}"
35+
object(MongoDB\BSON\Timestamp)#%d (%d) {
36+
["increment"]=>
37+
int(4294967295)
38+
["timestamp"]=>
39+
int(0)
40+
}
41+
42+
object(MongoDB\BSON\Timestamp)#%d (%d) {
43+
["increment"]=>
44+
int(0)
45+
["timestamp"]=>
46+
int(4294967295)
47+
}
48+
string(83) "O:22:"MongoDB\BSON\Timestamp":2:{s:9:"increment";i:0;s:9:"timestamp";i:4294967295;}"
49+
object(MongoDB\BSON\Timestamp)#%d (%d) {
50+
["increment"]=>
51+
int(0)
52+
["timestamp"]=>
53+
int(4294967295)
54+
}
55+
56+
===DONE===
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
--TEST--
2+
MongoDB\BSON\Timestamp::__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+
[1234, 5678],
11+
[2147483647, 0],
12+
[0, 2147483647],
13+
];
14+
15+
foreach ($tests as $test) {
16+
list($increment, $timestamp) = $test;
17+
18+
var_export(MongoDB\BSON\Timestamp::__set_state([
19+
'increment' => $increment,
20+
'timestamp' => $timestamp,
21+
]));
22+
echo "\n\n";
23+
}
24+
25+
?>
26+
===DONE===
27+
<?php exit(0); ?>
28+
--EXPECT--
29+
MongoDB\BSON\Timestamp::__set_state(array(
30+
'increment' => 1234,
31+
'timestamp' => 5678,
32+
))
33+
34+
MongoDB\BSON\Timestamp::__set_state(array(
35+
'increment' => 2147483647,
36+
'timestamp' => 0,
37+
))
38+
39+
MongoDB\BSON\Timestamp::__set_state(array(
40+
'increment' => 0,
41+
'timestamp' => 2147483647,
42+
))
43+
44+
===DONE===

0 commit comments

Comments
 (0)