From e4b63c9e0418dd70fa3c1ad7ae43fad43aaa8bd8 Mon Sep 17 00:00:00 2001 From: Lonny Kapelushnik Date: Fri, 28 Sep 2012 12:15:20 +0000 Subject: [PATCH 1/4] Bug 54567 DateTimeZone serialize/unserialize Make DateTimeZone serializable and implement __set_state --- ext/date/php_date.c | 115 ++++++++++++++++++ ext/date/php_date.h | 3 + ext/date/tests/014.phpt | 6 +- ext/date/tests/DateTimeZone_clone_basic1.phpt | 12 +- ext/date/tests/DateTimeZone_clone_basic2.phpt | 24 +++- ext/date/tests/DateTimeZone_clone_basic3.phpt | 30 ++++- .../tests/DateTimeZone_construct_basic.phpt | 18 ++- ext/date/tests/DateTimeZone_serialize.phpt | 20 +-- ext/date/tests/DateTimeZone_verify.phpt | 26 +++- ext/date/tests/timezone_open_basic1.phpt | 18 ++- 10 files changed, 241 insertions(+), 31 deletions(-) diff --git a/ext/date/php_date.c b/ext/date/php_date.c index fd6453f5d8cf6..0ea28ec7d0329 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -452,6 +452,8 @@ const zend_function_entry date_funcs_date[] = { const zend_function_entry date_funcs_timezone[] = { PHP_ME(DateTimeZone, __construct, arginfo_timezone_open, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC) + PHP_ME(DateTimeZone, __wakeup, NULL, ZEND_ACC_PUBLIC) + PHP_ME(DateTimeZone, __set_state, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) PHP_ME_MAPPING(getName, timezone_name_get, arginfo_timezone_method_name_get, 0) PHP_ME_MAPPING(getOffset, timezone_offset_get, arginfo_timezone_method_offset_get, 0) PHP_ME_MAPPING(getTransitions, timezone_transitions_get, arginfo_timezone_method_transitions_get, 0) @@ -569,6 +571,7 @@ static HashTable *date_object_get_gc(zval *object, zval ***table, int *n TSRMLS_ static HashTable *date_object_get_properties(zval *object TSRMLS_DC); static HashTable *date_object_get_gc_interval(zval *object, zval ***table, int *n TSRMLS_DC); static HashTable *date_object_get_properties_interval(zval *object TSRMLS_DC); +static HashTable *date_object_get_properties_timezone(zval *object TSRMLS_DC); zval *date_interval_read_property(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC); void date_interval_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC); @@ -1944,6 +1947,7 @@ static void date_register_classes(TSRMLS_D) date_ce_timezone = zend_register_internal_class_ex(&ce_timezone, NULL, NULL TSRMLS_CC); memcpy(&date_object_handlers_timezone, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); date_object_handlers_timezone.clone_obj = date_object_clone_timezone; + date_object_handlers_timezone.get_properties = date_object_get_properties_timezone; #define REGISTER_TIMEZONE_CLASS_CONST_STRING(const_name, value) \ zend_declare_class_constant_long(date_ce_timezone, const_name, sizeof(const_name)-1, value TSRMLS_CC); @@ -2178,6 +2182,50 @@ static zend_object_value date_object_clone_timezone(zval *this_ptr TSRMLS_DC) return new_ov; } +static HashTable *date_object_get_properties_timezone(zval *object TSRMLS_DC) +{ + HashTable *props; + zval *zv; + php_timezone_obj *tzobj; + + + tzobj = (php_timezone_obj *) zend_object_store_get_object(object TSRMLS_CC); + + props = zend_std_get_properties(object TSRMLS_CC); + + if (!tzobj->initialized || GC_G(gc_active)) { + return props; + } + + MAKE_STD_ZVAL(zv); + ZVAL_LONG(zv, tzobj->type); + zend_hash_update(props, "timezone_type", 14, &zv, sizeof(zval), NULL); + + MAKE_STD_ZVAL(zv); + switch (tzobj->type) { + case TIMELIB_ZONETYPE_ID: + ZVAL_STRING(zv, tzobj->tzi.tz->name, 1); + break; + case TIMELIB_ZONETYPE_OFFSET: { + char *tmpstr = emalloc(sizeof("UTC+05:00")); + + snprintf(tmpstr, sizeof("+05:00"), "%c%02d:%02d", + tzobj->tzi.z.utc_offset > 0 ? '-' : '+', + abs(tzobj->tzi.z.utc_offset / 60), + abs((tzobj->tzi.z.utc_offset % 60))); + + ZVAL_STRING(zv, tmpstr, 0); + } + break; + case TIMELIB_ZONETYPE_ABBR: + ZVAL_STRING(zv, tzobj->tzi.tz->timezone_abbr, 1); + break; + } + zend_hash_update(props, "timezone", 9, &zv, sizeof(zval), NULL); + + return props; +} + static inline zend_object_value date_object_new_interval_ex(zend_class_entry *class_type, php_interval_obj **ptr TSRMLS_DC) { php_interval_obj *intern; @@ -3241,6 +3289,73 @@ PHP_METHOD(DateTimeZone, __construct) } /* }}} */ +static int php_date_timezone_initialize_from_hash(zval **return_value, php_timezone_obj **tzobj, HashTable *myht TSRMLS_DC) +{ + zval **z_timezone = NULL; + zval **z_timezone_type = NULL; + timelib_tzinfo *tzi; + + if (zend_hash_find(myht, "timezone_type", 14, (void**) &z_timezone_type) == SUCCESS) { + if (zend_hash_find(myht, "timezone", 9, (void**) &z_timezone) == SUCCESS) { + convert_to_long(*z_timezone_type); + switch (Z_LVAL_PP(z_timezone_type)) { + case TIMELIB_ZONETYPE_OFFSET: + (*tzobj)->type = TIMELIB_ZONETYPE_OFFSET; + (*tzobj)->tzi.utc_offset = Z_LVAL_PP(z_timezone); + break; + case TIMELIB_ZONETYPE_ABBR: + (*tzobj)->type = TIMELIB_ZONETYPE_ABBR; + (*tzobj)->tzi.z.utc_offset = Z_LVAL_PP(z_timezone); + break; + case TIMELIB_ZONETYPE_ID: + if (SUCCESS == timezone_initialize(&tzi, Z_STRVAL_PP(z_timezone) TSRMLS_CC)) { + (*tzobj)->type = TIMELIB_ZONETYPE_ID; + (*tzobj)->tzi.tz = tzi; + (*tzobj)->initialized = 1; + return 1; + } + } + } + } + return 0; +} + +/* {{{ proto DateTimeZone::__set_state() + * */ +PHP_METHOD(DateTimeZone, __set_state) +{ + php_timezone_obj *tzobj; + zval *array; + HashTable *myht; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) == FAILURE) { + RETURN_FALSE; + } + + myht = HASH_OF(array); + + php_date_instantiate(date_ce_timezone, return_value TSRMLS_CC); + tzobj = (php_timezone_obj *) zend_object_store_get_object(return_value TSRMLS_CC); + php_date_timezone_initialize_from_hash(&return_value, &tzobj, myht TSRMLS_CC); +} +/* }}} */ + +/* {{{ proto DateTimeZone::__wakeup() + * */ +PHP_METHOD(DateTimeZone, __wakeup) +{ + zval *object = getThis(); + php_timezone_obj *tzobj; + HashTable *myht; + + tzobj = (php_timezone_obj *) zend_object_store_get_object(object TSRMLS_CC); + + myht = Z_OBJPROP_P(object); + + php_date_timezone_initialize_from_hash(&return_value, &tzobj, myht TSRMLS_CC); +} +/* }}} */ + /* {{{ proto string timezone_name_get(DateTimeZone object) Returns the name of the timezone. */ diff --git a/ext/date/php_date.h b/ext/date/php_date.h index f0b662b5d9f35..8d34d94a69dd1 100644 --- a/ext/date/php_date.h +++ b/ext/date/php_date.h @@ -71,6 +71,8 @@ PHP_FUNCTION(date_timestamp_set); PHP_FUNCTION(date_timestamp_get); PHP_METHOD(DateTimeZone, __construct); +PHP_METHOD(DateTimeZone, __wakeup); +PHP_METHOD(DateTimeZone, __set_state); PHP_FUNCTION(timezone_open); PHP_FUNCTION(timezone_name_get); PHP_FUNCTION(timezone_name_from_abbr); @@ -129,6 +131,7 @@ struct _php_timezone_obj { int dst; } z; } tzi; + HashTable *props; }; struct _php_interval_obj { diff --git a/ext/date/tests/014.phpt b/ext/date/tests/014.phpt index be0847777fc6b..5e609c86851b0 100644 --- a/ext/date/tests/014.phpt +++ b/ext/date/tests/014.phpt @@ -26,7 +26,11 @@ object(DateTime)#%d (3) { ["timezone"]=> string(3) "UTC" } -object(DateTimeZone)#%d (0) { +object(DateTimeZone)#%d (2) { + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(3) "UTC" } Warning: timezone_offset_get() expects exactly 2 parameters, 0 given in %s on line %d diff --git a/ext/date/tests/DateTimeZone_clone_basic1.phpt b/ext/date/tests/DateTimeZone_clone_basic1.phpt index 6de5d4b463daa..a89005aaece9d 100644 --- a/ext/date/tests/DateTimeZone_clone_basic1.phpt +++ b/ext/date/tests/DateTimeZone_clone_basic1.phpt @@ -29,9 +29,17 @@ if ($clone != $orig) { ===DONE=== --EXPECTF-- *** Testing clone on DateTime objects *** -object(DateTimeZone)#%d (0) { +object(DateTimeZone)#%d (2) { + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(3) "UTC" } -object(DateTimeZone)#%d (0) { +object(DateTimeZone)#%d (2) { + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(3) "UTC" } TEST PASSED : Objects equal but not indetical ===DONE=== diff --git a/ext/date/tests/DateTimeZone_clone_basic2.phpt b/ext/date/tests/DateTimeZone_clone_basic2.phpt index a499510ff977d..92f833082f738 100644 --- a/ext/date/tests/DateTimeZone_clone_basic2.phpt +++ b/ext/date/tests/DateTimeZone_clone_basic2.phpt @@ -31,19 +31,27 @@ var_dump($d2_clone); ===DONE=== --EXPECTF-- *** Testing clone on objects whoose class derived from DateTimeZone class *** -object(DateTimeZoneExt1)#%d (2) { +object(DateTimeZoneExt1)#%d (4) { ["property1"]=> int(99) ["property2"]=> string(5) "Hello" + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(13) "Europe/London" } -object(DateTimeZoneExt1)#%d (2) { +object(DateTimeZoneExt1)#%d (4) { ["property1"]=> int(99) ["property2"]=> string(5) "Hello" + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(13) "Europe/London" } -object(DateTimeZoneExt2)#%d (4) { +object(DateTimeZoneExt2)#%d (6) { ["property3"]=> bool(true) ["property4"]=> @@ -52,8 +60,12 @@ object(DateTimeZoneExt2)#%d (4) { int(99) ["property2"]=> string(5) "Hello" + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(13) "Europe/London" } -object(DateTimeZoneExt2)#%d (4) { +object(DateTimeZoneExt2)#%d (6) { ["property3"]=> bool(true) ["property4"]=> @@ -62,5 +74,9 @@ object(DateTimeZoneExt2)#%d (4) { int(99) ["property2"]=> string(5) "Hello" + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(13) "Europe/London" } ===DONE=== diff --git a/ext/date/tests/DateTimeZone_clone_basic3.phpt b/ext/date/tests/DateTimeZone_clone_basic3.phpt index e85f42e876780..128c8ff40bcdd 100644 --- a/ext/date/tests/DateTimeZone_clone_basic3.phpt +++ b/ext/date/tests/DateTimeZone_clone_basic3.phpt @@ -30,11 +30,19 @@ var_dump($d2_clone); *** Testing clone on DateTime objects *** -- Create a DateTimeZone object -- -object(DateTimeZone)#%d (0) { +object(DateTimeZone)#%d (2) { + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(13) "Europe/London" } -- Add some properties -- -object(DateTimeZone)#%d (2) { +object(DateTimeZone)#%d (4) { + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(13) "Europe/London" ["property1"]=> int(99) ["property2"]=> @@ -42,7 +50,11 @@ object(DateTimeZone)#%d (2) { } -- clone it -- -object(DateTimeZone)#%d (2) { +object(DateTimeZone)#%d (4) { + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(13) "Europe/London" ["property1"]=> int(99) ["property2"]=> @@ -50,7 +62,11 @@ object(DateTimeZone)#%d (2) { } -- Add some more properties -- -object(DateTimeZone)#%d (4) { +object(DateTimeZone)#%d (6) { + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(13) "Europe/London" ["property1"]=> int(99) ["property2"]=> @@ -62,7 +78,11 @@ object(DateTimeZone)#%d (4) { } -- clone it -- -object(DateTimeZone)#%d (4) { +object(DateTimeZone)#%d (6) { + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(13) "Europe/London" ["property1"]=> int(99) ["property2"]=> diff --git a/ext/date/tests/DateTimeZone_construct_basic.phpt b/ext/date/tests/DateTimeZone_construct_basic.phpt index b681e8f9c3649..2f18f81c038a4 100644 --- a/ext/date/tests/DateTimeZone_construct_basic.phpt +++ b/ext/date/tests/DateTimeZone_construct_basic.phpt @@ -21,10 +21,22 @@ var_dump( new DateTimeZone("America/Los_Angeles") ); ===DONE=== --EXPECTF-- *** Testing new DateTimeZone() : basic functionality *** -object(DateTimeZone)#%d (0) { +object(DateTimeZone)#%d (2) { + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(3) "UTC" } -object(DateTimeZone)#%d (0) { +object(DateTimeZone)#%d (2) { + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(13) "Europe/London" } -object(DateTimeZone)#%d (0) { +object(DateTimeZone)#%d (2) { + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(19) "America/Los_Angeles" } ===DONE=== diff --git a/ext/date/tests/DateTimeZone_serialize.phpt b/ext/date/tests/DateTimeZone_serialize.phpt index 08dd9344661a0..49b9349bb8351 100644 --- a/ext/date/tests/DateTimeZone_serialize.phpt +++ b/ext/date/tests/DateTimeZone_serialize.phpt @@ -18,12 +18,18 @@ var_dump( $tz2->getName() ); ?> ===DONE=== --EXPECTF-- -object(DateTimeZone)#%d (0) { +object(DateTimeZone)#%d (2) { + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(16) "America/New_York" } -string(24) "O:12:"DateTimeZone":0:{}" -object(DateTimeZone)#%d (0) { +string(88) "O:12:"DateTimeZone":2:{s:13:"timezone_type";i:3;s:8:"timezone";s:16:"America/New_York";}" +object(DateTimeZone)#%d (2) { + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(16) "America/New_York" } - -Warning: DateTimeZone::getName(): The DateTimeZone object has not been correctly initialized by its constructor in %s on line %d -bool(false) -===DONE=== \ No newline at end of file +string(16) "America/New_York" +===DONE=== diff --git a/ext/date/tests/DateTimeZone_verify.phpt b/ext/date/tests/DateTimeZone_verify.phpt index 3ca09131a7271..1304000cc4168 100644 --- a/ext/date/tests/DateTimeZone_verify.phpt +++ b/ext/date/tests/DateTimeZone_verify.phpt @@ -26,7 +26,7 @@ object(ReflectionClass)#%d (1) { string(12) "DateTimeZone" } ..and get names of all its methods -array(7) { +array(9) { [0]=> &object(ReflectionMethod)#%d (2) { ["name"]=> @@ -35,41 +35,55 @@ array(7) { string(12) "DateTimeZone" } [1]=> + &object(ReflectionMethod)#3 (2) { + ["name"]=> + string(8) "__wakeup" + ["class"]=> + string(12) "DateTimeZone" + } + [2]=> + &object(ReflectionMethod)#4 (2) { + ["name"]=> + string(11) "__set_state" + ["class"]=> + string(12) "DateTimeZone" + } + [3]=> &object(ReflectionMethod)#%d (2) { ["name"]=> string(7) "getName" ["class"]=> string(12) "DateTimeZone" } - [2]=> + [4]=> &object(ReflectionMethod)#%d (2) { ["name"]=> string(9) "getOffset" ["class"]=> string(12) "DateTimeZone" } - [3]=> + [5]=> &object(ReflectionMethod)#%d (2) { ["name"]=> string(14) "getTransitions" ["class"]=> string(12) "DateTimeZone" } - [4]=> + [6]=> &object(ReflectionMethod)#%d (2) { ["name"]=> string(11) "getLocation" ["class"]=> string(12) "DateTimeZone" } - [5]=> + [7]=> &object(ReflectionMethod)#%d (2) { ["name"]=> string(17) "listAbbreviations" ["class"]=> string(12) "DateTimeZone" } - [6]=> + [8]=> &object(ReflectionMethod)#%d (2) { ["name"]=> string(15) "listIdentifiers" diff --git a/ext/date/tests/timezone_open_basic1.phpt b/ext/date/tests/timezone_open_basic1.phpt index 7a989362b06de..7fcfcb34cb177 100644 --- a/ext/date/tests/timezone_open_basic1.phpt +++ b/ext/date/tests/timezone_open_basic1.phpt @@ -18,10 +18,22 @@ var_dump( timezone_open("America/Los_Angeles") ); ===DONE=== --EXPECTF-- *** Testing timezone_open() : basic functionality *** -object(DateTimeZone)#%d (0) { +object(DateTimeZone)#%d (2) { + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(3) "UTC" } -object(DateTimeZone)#%d (0) { +object(DateTimeZone)#%d (2) { + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(13) "Europe/London" } -object(DateTimeZone)#%d (0) { +object(DateTimeZone)#%d (2) { + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(19) "America/Los_Angeles" } ===DONE=== \ No newline at end of file From e76aa19095e31fd58857db955b382a28eee7b117 Mon Sep 17 00:00:00 2001 From: Lonny Kapelushnik Date: Sat, 29 Sep 2012 22:10:58 -0400 Subject: [PATCH 2/4] Fixed the test to use %d instead of an actual number --- ext/date/tests/DateTimeZone_verify.phpt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ext/date/tests/DateTimeZone_verify.phpt b/ext/date/tests/DateTimeZone_verify.phpt index 1304000cc4168..241d91e665583 100644 --- a/ext/date/tests/DateTimeZone_verify.phpt +++ b/ext/date/tests/DateTimeZone_verify.phpt @@ -35,14 +35,14 @@ array(9) { string(12) "DateTimeZone" } [1]=> - &object(ReflectionMethod)#3 (2) { + &object(ReflectionMethod)#%d (2) { ["name"]=> string(8) "__wakeup" ["class"]=> string(12) "DateTimeZone" } [2]=> - &object(ReflectionMethod)#4 (2) { + &object(ReflectionMethod)#%d (2) { ["name"]=> string(11) "__set_state" ["class"]=> @@ -122,4 +122,4 @@ array(14) { ["PER_COUNTRY"]=> int(4096) } -===DONE=== \ No newline at end of file +===DONE=== From c2e11f077625c22ede1455e5d4fbb26afa884ac9 Mon Sep 17 00:00:00 2001 From: Lonny Kapelushnik Date: Wed, 14 Nov 2012 05:04:46 +0000 Subject: [PATCH 3/4] Made separate tests for each TZ type Fixed handling of unserializing types 1 and 3 --- ext/date/lib/parse_date.re | 66 +++++++++---------- ext/date/lib/timelib.h | 1 + ext/date/php_date.c | 31 +++++---- .../tests/DateTimeZone_serialize_type_1.phpt | 35 ++++++++++ .../tests/DateTimeZone_serialize_type_2.phpt | 35 ++++++++++ ...hpt => DateTimeZone_serialize_type_3.phpt} | 0 6 files changed, 124 insertions(+), 44 deletions(-) create mode 100644 ext/date/tests/DateTimeZone_serialize_type_1.phpt create mode 100644 ext/date/tests/DateTimeZone_serialize_type_2.phpt rename ext/date/tests/{DateTimeZone_serialize.phpt => DateTimeZone_serialize_type_3.phpt} (100%) diff --git a/ext/date/lib/parse_date.re b/ext/date/lib/parse_date.re index 8e1972d99f106..06ab7e36bb9c2 100644 --- a/ext/date/lib/parse_date.re +++ b/ext/date/lib/parse_date.re @@ -530,39 +530,6 @@ static timelib_ull timelib_get_unsigned_nr(char **ptr, int max_length) return dir * timelib_get_nr(ptr, max_length); } -static long timelib_parse_tz_cor(char **ptr) -{ - char *begin = *ptr, *end; - long tmp; - - while (isdigit(**ptr) || **ptr == ':') { - ++*ptr; - } - end = *ptr; - switch (end - begin) { - case 1: - case 2: - return HOUR(strtol(begin, NULL, 10)); - break; - case 3: - case 4: - if (begin[1] == ':') { - tmp = HOUR(strtol(begin, NULL, 10)) + strtol(begin + 2, NULL, 10); - return tmp; - } else if (begin[2] == ':') { - tmp = HOUR(strtol(begin, NULL, 10)) + strtol(begin + 3, NULL, 10); - return tmp; - } else { - tmp = strtol(begin, NULL, 10); - return HOUR(tmp / 100) + tmp % 100; - } - case 5: - tmp = HOUR(strtol(begin, NULL, 10)) + strtol(begin + 3, NULL, 10); - return tmp; - } - return 0; -} - static timelib_sll timelib_lookup_relative_text(char **ptr, int *behavior) { char *word; @@ -2271,6 +2238,39 @@ const timelib_tz_lookup_table *timelib_timezone_abbreviations_list(void) return timelib_timezone_lookup; } +long timelib_parse_tz_cor(char **ptr) +{ + char *begin = *ptr, *end; + long tmp; + + while (isdigit(**ptr) || **ptr == ':') { + ++*ptr; + } + end = *ptr; + switch (end - begin) { + case 1: + case 2: + return HOUR(strtol(begin, NULL, 10)); + break; + case 3: + case 4: + if (begin[1] == ':') { + tmp = HOUR(strtol(begin, NULL, 10)) + strtol(begin + 2, NULL, 10); + return tmp; + } else if (begin[2] == ':') { + tmp = HOUR(strtol(begin, NULL, 10)) + strtol(begin + 3, NULL, 10); + return tmp; + } else { + tmp = strtol(begin, NULL, 10); + return HOUR(tmp / 100) + tmp % 100; + } + case 5: + tmp = HOUR(strtol(begin, NULL, 10)) + strtol(begin + 3, NULL, 10); + return tmp; + } + return 0; +} + #ifdef DEBUG_PARSER_STUB int main(void) { diff --git a/ext/date/lib/timelib.h b/ext/date/lib/timelib.h index 478dec32d04b8..d941cf6d0864f 100644 --- a/ext/date/lib/timelib.h +++ b/ext/date/lib/timelib.h @@ -73,6 +73,7 @@ timelib_time *timelib_parse_from_format(char *format, char *s, int len, timelib_ void timelib_fill_holes(timelib_time *parsed, timelib_time *now, int options); char *timelib_timezone_id_from_abbr(const char *abbr, long gmtoffset, int isdst); const timelib_tz_lookup_table *timelib_timezone_abbreviations_list(void); +long timelib_parse_tz_cor(char**); /* From parse_iso_intervals.re */ void timelib_strtointerval(char *s, int len, diff --git a/ext/date/php_date.c b/ext/date/php_date.c index 0ea28ec7d0329..9be0ae640cfdd 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -2210,15 +2210,15 @@ static HashTable *date_object_get_properties_timezone(zval *object TSRMLS_DC) char *tmpstr = emalloc(sizeof("UTC+05:00")); snprintf(tmpstr, sizeof("+05:00"), "%c%02d:%02d", - tzobj->tzi.z.utc_offset > 0 ? '-' : '+', - abs(tzobj->tzi.z.utc_offset / 60), - abs((tzobj->tzi.z.utc_offset % 60))); + tzobj->tzi.utc_offset > 0 ? '-' : '+', + abs(tzobj->tzi.utc_offset / 60), + abs((tzobj->tzi.utc_offset % 60))); ZVAL_STRING(zv, tmpstr, 0); } break; case TIMELIB_ZONETYPE_ABBR: - ZVAL_STRING(zv, tzobj->tzi.tz->timezone_abbr, 1); + ZVAL_STRING(zv, tzobj->tzi.z.abbr, 1); break; } zend_hash_update(props, "timezone", 9, &zv, sizeof(zval), NULL); @@ -3294,30 +3294,39 @@ static int php_date_timezone_initialize_from_hash(zval **return_value, php_timez zval **z_timezone = NULL; zval **z_timezone_type = NULL; timelib_tzinfo *tzi; + char **offset; if (zend_hash_find(myht, "timezone_type", 14, (void**) &z_timezone_type) == SUCCESS) { if (zend_hash_find(myht, "timezone", 9, (void**) &z_timezone) == SUCCESS) { convert_to_long(*z_timezone_type); switch (Z_LVAL_PP(z_timezone_type)) { case TIMELIB_ZONETYPE_OFFSET: + offset = malloc(sizeof(char) * (Z_STRLEN_PP(z_timezone) + 1)); + *offset = (Z_STRVAL_PP(z_timezone)); + if(**offset == '+'){ + ++*offset; + (*tzobj)->tzi.utc_offset = -1 * timelib_parse_tz_cor((char **)offset); + } else { + ++*offset; + (*tzobj)->tzi.utc_offset = timelib_parse_tz_cor((char **)offset); + } + free(offset); (*tzobj)->type = TIMELIB_ZONETYPE_OFFSET; - (*tzobj)->tzi.utc_offset = Z_LVAL_PP(z_timezone); + (*tzobj)->initialized = 1; + return SUCCESS; break; case TIMELIB_ZONETYPE_ABBR: - (*tzobj)->type = TIMELIB_ZONETYPE_ABBR; - (*tzobj)->tzi.z.utc_offset = Z_LVAL_PP(z_timezone); - break; case TIMELIB_ZONETYPE_ID: if (SUCCESS == timezone_initialize(&tzi, Z_STRVAL_PP(z_timezone) TSRMLS_CC)) { (*tzobj)->type = TIMELIB_ZONETYPE_ID; (*tzobj)->tzi.tz = tzi; (*tzobj)->initialized = 1; - return 1; + return SUCCESS; } } } } - return 0; + return FAILURE; } /* {{{ proto DateTimeZone::__set_state() @@ -3351,7 +3360,7 @@ PHP_METHOD(DateTimeZone, __wakeup) tzobj = (php_timezone_obj *) zend_object_store_get_object(object TSRMLS_CC); myht = Z_OBJPROP_P(object); - + php_date_timezone_initialize_from_hash(&return_value, &tzobj, myht TSRMLS_CC); } /* }}} */ diff --git a/ext/date/tests/DateTimeZone_serialize_type_1.phpt b/ext/date/tests/DateTimeZone_serialize_type_1.phpt new file mode 100644 index 0000000000000..51a5c53b234aa --- /dev/null +++ b/ext/date/tests/DateTimeZone_serialize_type_1.phpt @@ -0,0 +1,35 @@ +--TEST-- +Test serialization of DateTimeZone objects +--FILE-- +getTimezone(); +var_dump( $tz1 ); +$serialized = serialize($tz1); +var_dump($serialized); + +$tz2 = unserialize($serialized); +var_dump($tz2); +// Try to use unserialzied object +var_dump( $tz2->getName() ); + +?> +===DONE=== +--EXPECTF-- +object(DateTimeZone)#%d (2) { + ["timezone_type"]=> + int(1) + ["timezone"]=> + string(6) "+01:00" +} +string(77) "O:12:"DateTimeZone":2:{s:13:"timezone_type";i:1;s:8:"timezone";s:6:"+01:00";}" +object(DateTimeZone)#%d (2) { + ["timezone_type"]=> + int(1) + ["timezone"]=> + string(6) "+01:00" +} +string(6) "+01:00" +===DONE=== diff --git a/ext/date/tests/DateTimeZone_serialize_type_2.phpt b/ext/date/tests/DateTimeZone_serialize_type_2.phpt new file mode 100644 index 0000000000000..a264322f3e18e --- /dev/null +++ b/ext/date/tests/DateTimeZone_serialize_type_2.phpt @@ -0,0 +1,35 @@ +--TEST-- +Test serialization of DateTimeZone objects +--FILE-- +getName() ); + +?> +===DONE=== +--EXPECTF-- +object(DateTimeZone)#%d (2) { + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(16) "America/New_York" +} +string(88) "O:12:"DateTimeZone":2:{s:13:"timezone_type";i:3;s:8:"timezone";s:16:"America/New_York";}" +object(DateTimeZone)#%d (2) { + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(16) "America/New_York" +} +string(16) "America/New_York" +===DONE=== diff --git a/ext/date/tests/DateTimeZone_serialize.phpt b/ext/date/tests/DateTimeZone_serialize_type_3.phpt similarity index 100% rename from ext/date/tests/DateTimeZone_serialize.phpt rename to ext/date/tests/DateTimeZone_serialize_type_3.phpt From 8eda61ca704ed34a8083a036cf93a8899c91fa59 Mon Sep 17 00:00:00 2001 From: Lonny Kapelushnik Date: Mon, 14 Jan 2013 23:03:52 +0000 Subject: [PATCH 4/4] Rebased to PHP-5.4 Implemented Dmitrys change from df97c3aa0d331be668bd5d8f27fff96d4e3ac1d7 Moved the timelib_parse_tz_cor function to ext/date/lib/timelib.c --- ext/date/lib/parse_date.re | 35 ----------------------------- ext/date/lib/parse_iso_intervals.re | 35 ----------------------------- ext/date/lib/timelib.c | 34 ++++++++++++++++++++++++++++ ext/date/lib/timelib.h | 1 + ext/date/php_date.c | 12 +++++++++- 5 files changed, 46 insertions(+), 71 deletions(-) diff --git a/ext/date/lib/parse_date.re b/ext/date/lib/parse_date.re index 06ab7e36bb9c2..f3f5906b0a819 100644 --- a/ext/date/lib/parse_date.re +++ b/ext/date/lib/parse_date.re @@ -168,8 +168,6 @@ typedef struct _timelib_relunit { int multiplier; } timelib_relunit; -#define HOUR(a) (int)(a * 60) - /* The timezone table. */ const static timelib_tz_lookup_table timelib_timezone_lookup[] = { #include "timezonemap.h" @@ -2238,39 +2236,6 @@ const timelib_tz_lookup_table *timelib_timezone_abbreviations_list(void) return timelib_timezone_lookup; } -long timelib_parse_tz_cor(char **ptr) -{ - char *begin = *ptr, *end; - long tmp; - - while (isdigit(**ptr) || **ptr == ':') { - ++*ptr; - } - end = *ptr; - switch (end - begin) { - case 1: - case 2: - return HOUR(strtol(begin, NULL, 10)); - break; - case 3: - case 4: - if (begin[1] == ':') { - tmp = HOUR(strtol(begin, NULL, 10)) + strtol(begin + 2, NULL, 10); - return tmp; - } else if (begin[2] == ':') { - tmp = HOUR(strtol(begin, NULL, 10)) + strtol(begin + 3, NULL, 10); - return tmp; - } else { - tmp = strtol(begin, NULL, 10); - return HOUR(tmp / 100) + tmp % 100; - } - case 5: - tmp = HOUR(strtol(begin, NULL, 10)) + strtol(begin + 3, NULL, 10); - return tmp; - } - return 0; -} - #ifdef DEBUG_PARSER_STUB int main(void) { diff --git a/ext/date/lib/parse_iso_intervals.re b/ext/date/lib/parse_iso_intervals.re index 56aa34d8e005e..e50ab37d3ba7f 100644 --- a/ext/date/lib/parse_iso_intervals.re +++ b/ext/date/lib/parse_iso_intervals.re @@ -102,8 +102,6 @@ typedef struct Scanner { int have_end_date; } Scanner; -#define HOUR(a) (int)(a * 60) - static void add_warning(Scanner *s, char *error) { s->errors->warning_count++; @@ -176,39 +174,6 @@ static timelib_ull timelib_get_unsigned_nr(char **ptr, int max_length) return dir * timelib_get_nr(ptr, max_length); } -static long timelib_parse_tz_cor(char **ptr) -{ - char *begin = *ptr, *end; - long tmp; - - while (isdigit(**ptr) || **ptr == ':') { - ++*ptr; - } - end = *ptr; - switch (end - begin) { - case 1: - case 2: - return HOUR(strtol(begin, NULL, 10)); - break; - case 3: - case 4: - if (begin[1] == ':') { - tmp = HOUR(strtol(begin, NULL, 10)) + strtol(begin + 2, NULL, 10); - return tmp; - } else if (begin[2] == ':') { - tmp = HOUR(strtol(begin, NULL, 10)) + strtol(begin + 3, NULL, 10); - return tmp; - } else { - tmp = strtol(begin, NULL, 10); - return HOUR(tmp / 100) + tmp % 100; - } - case 5: - tmp = HOUR(strtol(begin, NULL, 10)) + strtol(begin + 3, NULL, 10); - return tmp; - } - return 0; -} - static void timelib_eat_spaces(char **ptr) { while (**ptr == ' ' || **ptr == '\t') { diff --git a/ext/date/lib/timelib.c b/ext/date/lib/timelib.c index 2f457a988244a..84354e300f231 100644 --- a/ext/date/lib/timelib.c +++ b/ext/date/lib/timelib.c @@ -30,6 +30,8 @@ #define TIMELIB_LLABS(y) (y < 0 ? (y * -1) : y) +#define HOUR(a) (int)(a * 60) + timelib_time* timelib_time_ctor(void) { timelib_time *t; @@ -284,3 +286,35 @@ void timelib_dump_rel_time(timelib_rel_time *d) printf("\n"); } +long timelib_parse_tz_cor(char **ptr) +{ + char *begin = *ptr, *end; + long tmp; + + while (isdigit(**ptr) || **ptr == ':') { + ++*ptr; + } + end = *ptr; + switch (end - begin) { + case 1: + case 2: + return HOUR(strtol(begin, NULL, 10)); + break; + case 3: + case 4: + if (begin[1] == ':') { + tmp = HOUR(strtol(begin, NULL, 10)) + strtol(begin + 2, NULL, 10); + return tmp; + } else if (begin[2] == ':') { + tmp = HOUR(strtol(begin, NULL, 10)) + strtol(begin + 3, NULL, 10); + return tmp; + } else { + tmp = strtol(begin, NULL, 10); + return HOUR(tmp / 100) + tmp % 100; + } + case 5: + tmp = HOUR(strtol(begin, NULL, 10)) + strtol(begin + 3, NULL, 10); + return tmp; + } + return 0; +} diff --git a/ext/date/lib/timelib.h b/ext/date/lib/timelib.h index d941cf6d0864f..dfb7dc0300763 100644 --- a/ext/date/lib/timelib.h +++ b/ext/date/lib/timelib.h @@ -130,6 +130,7 @@ void timelib_dump_date(timelib_time *d, int options); void timelib_dump_rel_time(timelib_rel_time *d); void timelib_decimal_hour_to_hms(double h, int *hour, int *min, int *sec); +long timelib_parse_tz_cor(char **ptr); /* from astro.c */ double timelib_ts_to_juliandate(timelib_sll ts); diff --git a/ext/date/php_date.c b/ext/date/php_date.c index 9be0ae640cfdd..e693b0e4e7250 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -572,6 +572,7 @@ static HashTable *date_object_get_properties(zval *object TSRMLS_DC); static HashTable *date_object_get_gc_interval(zval *object, zval ***table, int *n TSRMLS_DC); static HashTable *date_object_get_properties_interval(zval *object TSRMLS_DC); static HashTable *date_object_get_properties_timezone(zval *object TSRMLS_DC); +static HashTable *date_object_get_gc_timezone(zval *object, zval ***table, int *n TSRMLS_DC); zval *date_interval_read_property(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC); void date_interval_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC); @@ -1948,6 +1949,7 @@ static void date_register_classes(TSRMLS_D) memcpy(&date_object_handlers_timezone, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); date_object_handlers_timezone.clone_obj = date_object_clone_timezone; date_object_handlers_timezone.get_properties = date_object_get_properties_timezone; + date_object_handlers_timezone.get_gc = date_object_get_gc_timezone; #define REGISTER_TIMEZONE_CLASS_CONST_STRING(const_name, value) \ zend_declare_class_constant_long(date_ce_timezone, const_name, sizeof(const_name)-1, value TSRMLS_CC); @@ -2074,6 +2076,14 @@ static HashTable *date_object_get_gc(zval *object, zval ***table, int *n TSRMLS_ return zend_std_get_properties(object TSRMLS_CC); } +static HashTable *date_object_get_gc_timezone(zval *object, zval ***table, int *n TSRMLS_DC) +{ + + *table = NULL; + *n = 0; + return zend_std_get_properties(object TSRMLS_CC); +} + static HashTable *date_object_get_properties(zval *object TSRMLS_DC) { HashTable *props; @@ -2193,7 +2203,7 @@ static HashTable *date_object_get_properties_timezone(zval *object TSRMLS_DC) props = zend_std_get_properties(object TSRMLS_CC); - if (!tzobj->initialized || GC_G(gc_active)) { + if (!tzobj->initialized) { return props; }