@@ -67,6 +67,48 @@ static bool php_phongo_timestamp_init(php_phongo_timestamp_t *intern, phongo_lon
6767 return true;
6868}
6969
70+ /* Initialize the object from numeric strings and return whether it was
71+ * successful. An exception will be thrown on error. */
72+ static bool php_phongo_timestamp_init_from_string (php_phongo_timestamp_t * intern , const char * s_increment , phongo_zpp_char_len s_increment_len , const char * s_timestamp , phongo_zpp_char_len s_timestamp_len TSRMLS_DC )
73+ {
74+ int64_t increment , timestamp ;
75+ char * endptr = NULL ;
76+
77+ errno = 0 ;
78+
79+ /* errno will set errno if conversion fails; however, we do not need to
80+ * specify the type of error.
81+ *
82+ * Note: bson_ascii_strtoll() does not properly detect out-of-range values
83+ * (see: CDRIVER-1377). strtoll() would be preferable, but it is not
84+ * available on all platforms (e.g. HP-UX), and atoll() provides no error
85+ * reporting at all. */
86+
87+ #if defined(PHP_WIN32 )
88+ increment = _atoi64 (s_increment );
89+ #else
90+ increment = bson_ascii_strtoll (s_increment , & endptr , 10 );
91+ #endif
92+
93+ if (errno || (endptr && endptr != ((const char * )s_increment + s_increment_len ))) {
94+ phongo_throw_exception (PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC , "Error parsing \"%s\" as 64-bit integer increment for %s initialization" , s_increment , ZSTR_VAL (php_phongo_timestamp_ce -> name ));
95+ return false;
96+ }
97+
98+ #if defined(PHP_WIN32 )
99+ timestamp = _atoi64 (s_timestamp );
100+ #else
101+ timestamp = bson_ascii_strtoll (s_timestamp , & endptr , 10 );
102+ #endif
103+
104+ if (errno || (endptr && endptr != ((const char * )s_timestamp + s_timestamp_len ))) {
105+ phongo_throw_exception (PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC , "Error parsing \"%s\" as 64-bit integer timestamp for %s initialization" , s_timestamp , ZSTR_VAL (php_phongo_timestamp_ce -> name ));
106+ return false;
107+ }
108+
109+ return php_phongo_timestamp_init (intern , increment , timestamp TSRMLS_CC );
110+ }
111+
70112/* Initialize the object from a HashTable and return whether it was successful.
71113 * An exception will be thrown on error. */
72114static bool php_phongo_timestamp_init_from_hash (php_phongo_timestamp_t * intern , HashTable * props TSRMLS_DC )
@@ -78,20 +120,28 @@ static bool php_phongo_timestamp_init_from_hash(php_phongo_timestamp_t *intern,
78120 (timestamp = zend_hash_str_find (props , "timestamp" , sizeof ("timestamp" )- 1 )) && Z_TYPE_P (timestamp ) == IS_LONG ) {
79121 return php_phongo_timestamp_init (intern , Z_LVAL_P (increment ), Z_LVAL_P (timestamp ) TSRMLS_CC );
80122 }
123+ if ((increment = zend_hash_str_find (props , "increment" , sizeof ("increment" )- 1 )) && Z_TYPE_P (increment ) == IS_STRING &&
124+ (timestamp = zend_hash_str_find (props , "timestamp" , sizeof ("timestamp" )- 1 )) && Z_TYPE_P (timestamp ) == IS_STRING ) {
125+ return php_phongo_timestamp_init_from_string (intern , Z_STRVAL_P (increment ), Z_STRLEN_P (increment ), Z_STRVAL_P (timestamp ), Z_STRLEN_P (timestamp ) TSRMLS_CC );
126+ }
81127#else
82128 zval * * increment , * * timestamp ;
83129
84130 if (zend_hash_find (props , "increment" , sizeof ("increment" ), (void * * ) & increment ) == SUCCESS && Z_TYPE_PP (increment ) == IS_LONG &&
85131 zend_hash_find (props , "timestamp" , sizeof ("timestamp" ), (void * * ) & timestamp ) == SUCCESS && Z_TYPE_PP (timestamp ) == IS_LONG ) {
86132 return php_phongo_timestamp_init (intern , Z_LVAL_PP (increment ), Z_LVAL_PP (timestamp ) TSRMLS_CC );
87133 }
134+ if (zend_hash_find (props , "increment" , sizeof ("increment" ), (void * * ) & increment ) == SUCCESS && Z_TYPE_PP (increment ) == IS_STRING &&
135+ zend_hash_find (props , "timestamp" , sizeof ("timestamp" ), (void * * ) & timestamp ) == SUCCESS && Z_TYPE_PP (timestamp ) == IS_STRING ) {
136+ return php_phongo_timestamp_init_from_string (intern , Z_STRVAL_PP (increment ), Z_STRLEN_PP (increment ), Z_STRVAL_PP (timestamp ), Z_STRLEN_PP (timestamp ) TSRMLS_CC );
137+ }
88138#endif
89139
90- phongo_throw_exception (PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC , "%s initialization requires \"increment\" and \"timestamp\" integer fields" , ZSTR_VAL (php_phongo_timestamp_ce -> name ));
140+ phongo_throw_exception (PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC , "%s initialization requires \"increment\" and \"timestamp\" integer or numeric string fields" , ZSTR_VAL (php_phongo_timestamp_ce -> name ));
91141 return false;
92142}
93143
94- /* {{{ proto void Timestamp::__construct(integer $increment, int $timestamp)
144+ /* {{{ proto void Timestamp::__construct(integer $increment, integer $timestamp)
95145 Construct a new BSON timestamp type, which consists of a 4-byte increment and
96146 4-byte timestamp. */
97147PHP_METHOD (Timestamp , __construct )
@@ -261,6 +311,10 @@ HashTable *php_phongo_timestamp_get_properties(zval *object TSRMLS_DC) /* {{{ */
261311{
262312 php_phongo_timestamp_t * intern ;
263313 HashTable * props ;
314+ char s_increment [24 ];
315+ char s_timestamp [24 ];
316+ int s_increment_len ;
317+ int s_timestamp_len ;
264318
265319 intern = Z_TIMESTAMP_OBJ_P (object );
266320 props = zend_std_get_properties (object TSRMLS_CC );
@@ -269,26 +323,29 @@ HashTable *php_phongo_timestamp_get_properties(zval *object TSRMLS_DC) /* {{{ */
269323 return props ;
270324 }
271325
326+ s_increment_len = snprintf (s_increment , sizeof (s_increment ), "%" PRId64 , intern -> increment );
327+ s_timestamp_len = snprintf (s_timestamp , sizeof (s_timestamp ), "%" PRId64 , intern -> timestamp );
328+
272329#if PHP_VERSION_ID >= 70000
273330 {
274331 zval increment , timestamp ;
275332
276- ZVAL_LONG (& increment , intern -> increment );
333+ ZVAL_STRINGL (& increment , s_increment , s_increment_len );
277334 zend_hash_str_update (props , "increment" , sizeof ("increment" )- 1 , & increment );
278335
279- ZVAL_LONG (& timestamp , intern -> timestamp );
336+ ZVAL_STRINGL (& timestamp , s_timestamp , s_timestamp_len );
280337 zend_hash_str_update (props , "timestamp" , sizeof ("timestamp" )- 1 , & timestamp );
281338 }
282339#else
283340 {
284341 zval * increment , * timestamp ;
285342
286343 MAKE_STD_ZVAL (increment );
287- ZVAL_LONG (increment , intern -> increment );
344+ ZVAL_STRINGL (increment , s_increment , s_increment_len , 1 );
288345 zend_hash_update (props , "increment" , sizeof ("increment" ), & increment , sizeof (increment ), NULL );
289346
290347 MAKE_STD_ZVAL (timestamp );
291- ZVAL_LONG (timestamp , intern -> timestamp );
348+ ZVAL_STRINGL (timestamp , s_timestamp , s_timestamp_len , 1 );
292349 zend_hash_update (props , "timestamp" , sizeof ("timestamp" ), & timestamp , sizeof (timestamp ), NULL );
293350 }
294351#endif
0 commit comments