@@ -52,7 +52,7 @@ PHONGO_API zend_class_entry *php_phongo_utcdatetime_ce;
5252
5353zend_object_handlers php_phongo_handler_utcdatetime ;
5454
55- /* Initialize the object from an integer and return whether it was successful. */
55+ /* Initialize the object and return whether it was successful. */
5656static bool php_phongo_utcdatetime_init (php_phongo_utcdatetime_t * intern , int64_t milliseconds )
5757{
5858 intern -> milliseconds = milliseconds ;
@@ -61,8 +61,39 @@ static bool php_phongo_utcdatetime_init(php_phongo_utcdatetime_t *intern, int64_
6161 return true;
6262}
6363
64- /* Initialize the object from a HashTable and return whether it was successful. */
65- static bool php_phongo_utcdatetime_init_from_hash (php_phongo_utcdatetime_t * intern , HashTable * props )
64+ /* Initialize the object from a numeric string and return whether it was
65+ * successful. An exception will be thrown on error. */
66+ static bool php_phongo_utcdatetime_init_from_string (php_phongo_utcdatetime_t * intern , const char * s_milliseconds , phongo_zpp_char_len s_milliseconds_len TSRMLS_DC )
67+ {
68+ int64_t milliseconds ;
69+ char * endptr = NULL ;
70+
71+ errno = 0 ;
72+
73+ #if defined(PHP_WIN32 )
74+ milliseconds = _atoi64 (s );
75+ #else
76+ milliseconds = bson_ascii_strtoll (s_milliseconds , & endptr , 10 );
77+ #endif
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+ if (errno || (endptr && endptr != ((const char * )s_milliseconds + s_milliseconds_len ))) {
87+ phongo_throw_exception (PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC , "Error parsing \"%s\" as 64-bit integer for %s initialization" , s_milliseconds , ZSTR_VAL (php_phongo_utcdatetime_ce -> name ));
88+ return false;
89+ }
90+
91+ return php_phongo_utcdatetime_init (intern , milliseconds );
92+ }
93+
94+ /* Initialize the object from a HashTable and return whether it was successful.
95+ * An exception will be thrown on error. */
96+ static bool php_phongo_utcdatetime_init_from_hash (php_phongo_utcdatetime_t * intern , HashTable * props TSRMLS_DC )
6697{
6798#if PHP_VERSION_ID >= 70000
6899 zval * milliseconds ;
@@ -72,7 +103,7 @@ static bool php_phongo_utcdatetime_init_from_hash(php_phongo_utcdatetime_t *inte
72103 }
73104
74105 if ((milliseconds = zend_hash_str_find (props , "milliseconds" , sizeof ("milliseconds" )- 1 )) && Z_TYPE_P (milliseconds ) == IS_STRING ) {
75- return php_phongo_utcdatetime_init (intern , STRTOLL ( Z_STRVAL_P (milliseconds )) );
106+ return php_phongo_utcdatetime_init_from_string (intern , Z_STRVAL_P (milliseconds ), Z_STRLEN_P ( milliseconds ) TSRMLS_CC );
76107 }
77108#else
78109 zval * * milliseconds ;
@@ -82,13 +113,16 @@ static bool php_phongo_utcdatetime_init_from_hash(php_phongo_utcdatetime_t *inte
82113 }
83114
84115 if (zend_hash_find (props , "milliseconds" , sizeof ("milliseconds" ), (void * * ) & milliseconds ) == SUCCESS && Z_TYPE_PP (milliseconds ) == IS_STRING ) {
85- return php_phongo_utcdatetime_init (intern , STRTOLL ( Z_STRVAL_PP (milliseconds )) );
116+ return php_phongo_utcdatetime_init_from_string (intern , Z_STRVAL_PP (milliseconds ), Z_STRLEN_PP ( milliseconds ) TSRMLS_CC );
86117 }
87118#endif
119+
120+ phongo_throw_exception (PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC , "%s initialization requires \"milliseconds\" integer or numeric string field" , ZSTR_VAL (php_phongo_utcdatetime_ce -> name ));
88121 return false;
89122}
90123
91- /* Initialize the object from the current time and return whether it was successful. */
124+ /* Initialize the object from the current time and return whether it was
125+ * successful. */
92126static bool php_phongo_utcdatetime_init_from_current_time (php_phongo_utcdatetime_t * intern )
93127{
94128 int64_t sec , usec ;
@@ -104,7 +138,8 @@ static bool php_phongo_utcdatetime_init_from_current_time(php_phongo_utcdatetime
104138 return true;
105139}
106140
107- /* Initialize the object from a DateTime object and return whether it was successful. */
141+ /* Initialize the object from a DateTime object and return whether it was
142+ * successful. */
108143static bool php_phongo_utcdatetime_init_from_date (php_phongo_utcdatetime_t * intern , php_date_obj * datetime_obj )
109144{
110145 int64_t sec , usec ;
@@ -168,7 +203,7 @@ PHP_METHOD(UTCDateTime, __construct)
168203 return ;
169204 }
170205
171- php_phongo_utcdatetime_init (intern , STRTOLL ( s_milliseconds ) );
206+ php_phongo_utcdatetime_init_from_string (intern , s_milliseconds , s_milliseconds_len );
172207 }
173208#else
174209# error Unsupported architecture (integers are neither 32-bit nor 64-bit)
@@ -196,9 +231,7 @@ PHP_METHOD(UTCDateTime, __set_state)
196231 intern = Z_UTCDATETIME_OBJ_P (return_value );
197232 props = Z_ARRVAL_P (array );
198233
199- if (!php_phongo_utcdatetime_init_from_hash (intern , props )) {
200- php_error (E_ERROR , "Invalid serialization data for UTCDateTime object" );
201- }
234+ php_phongo_utcdatetime_init_from_hash (intern , props TSRMLS_CC );
202235}
203236/* }}} */
204237
@@ -237,9 +270,7 @@ PHP_METHOD(UTCDateTime, __wakeup)
237270 intern = Z_UTCDATETIME_OBJ_P (getThis ());
238271 props = zend_std_get_properties (getThis () TSRMLS_CC );
239272
240- if (!php_phongo_utcdatetime_init_from_hash (intern , props )) {
241- php_error (E_ERROR , "Invalid serialization data for UTCDateTime object" );
242- }
273+ php_phongo_utcdatetime_init_from_hash (intern , props TSRMLS_CC );
243274}
244275/* }}} */
245276
0 commit comments