diff --git a/ext/date/php_date.c b/ext/date/php_date.c index 0f8822a906006..a27b79429b06f 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -625,6 +625,7 @@ static zend_object_value date_object_clone_period(zval *this_ptr TSRMLS_DC); static int date_object_compare_date(zval *d1, zval *d2 TSRMLS_DC); static HashTable *date_object_get_gc(zval *object, zval ***table, int *n TSRMLS_DC); +static zval *date_object_read_property(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC); 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); @@ -1993,6 +1994,7 @@ static void date_register_classes(TSRMLS_D) memcpy(&date_object_handlers_date, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); date_object_handlers_date.clone_obj = date_object_clone_date; date_object_handlers_date.compare_objects = date_object_compare_date; + date_object_handlers_date.read_property = date_object_read_property; date_object_handlers_date.get_properties = date_object_get_properties; date_object_handlers_date.get_gc = date_object_get_gc; zend_class_implements(date_ce_date TSRMLS_CC, 1, date_ce_interface); @@ -2180,12 +2182,73 @@ static HashTable *date_object_get_gc_timezone(zval *object, zval ***table, int * return zend_std_get_properties(object TSRMLS_CC); } -static HashTable *date_object_get_properties(zval *object TSRMLS_DC) + +static inline zval *date_object_update_property_date(php_date_obj *dateobj, HashTable *props) { - HashTable *props; zval *zv; - php_date_obj *dateobj; + MAKE_STD_ZVAL(zv); + ZVAL_STRING(zv, date_format("Y-m-d H:i:s", 12, dateobj->time, 1), 0); + zend_hash_update(props, "date", sizeof("date"), &zv, sizeof(zval), NULL); + return zv; +} + +static inline zval *date_object_update_property_timezone_type(php_date_obj *dateobj, HashTable *props) +{ + zval *zv; + MAKE_STD_ZVAL(zv); + ZVAL_LONG(zv, dateobj->time->zone_type); + zend_hash_update(props, "timezone_type", sizeof("timezone_type"), &zv, sizeof(zval), NULL); + return zv; +} + +static inline zval *date_object_update_property_timezone(php_date_obj *dateobj, HashTable *props) +{ + zval *zv; + MAKE_STD_ZVAL(zv); + switch (dateobj->time->zone_type) { + case TIMELIB_ZONETYPE_ID: + ZVAL_STRING(zv, dateobj->time->tz_info->name, 1); + break; + case TIMELIB_ZONETYPE_OFFSET: { + char *tmpstr = emalloc(sizeof("UTC+05:00")); + timelib_sll utc_offset = dateobj->time->z; + + snprintf(tmpstr, sizeof("+05:00"), "%c%02d:%02d", + utc_offset > 0 ? '-' : '+', + abs(utc_offset / 60), + abs((utc_offset % 60))); + + ZVAL_STRING(zv, tmpstr, 0); + } + break; + case TIMELIB_ZONETYPE_ABBR: + ZVAL_STRING(zv, dateobj->time->tz_abbr, 1); + break; + } + zend_hash_update(props, "timezone", sizeof("timezone"), &zv, sizeof(zval), NULL); + return zv; +} + +static zval *date_object_read_property(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC) +{ + php_date_obj *dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC); + + if (!zend_binary_strcmp(Z_STRVAL_P(member), Z_STRLEN_P(member), "date", sizeof("date")-1)) { + return date_object_update_property_date(dateobj, zend_std_get_properties(object TSRMLS_CC)); + } else if (dateobj->time->is_localtime) { + if (!zend_binary_strcmp(Z_STRVAL_P(member), Z_STRLEN_P(member), "timezone_type", sizeof("timezone_type")-1)) + return date_object_update_property_timezone_type(dateobj, zend_std_get_properties(object TSRMLS_CC)); + else if (!zend_binary_strcmp(Z_STRVAL_P(member), Z_STRLEN_P(member), "timezone", sizeof("timezone")-1)) + return date_object_update_property_timezone(dateobj, zend_std_get_properties(object TSRMLS_CC)); + } + return (zend_get_std_object_handlers())->read_property(object, member, type, key TSRMLS_CC); +} + +static HashTable *date_object_get_properties(zval *object TSRMLS_DC) +{ + HashTable *props; + php_date_obj *dateobj; dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC); @@ -2195,41 +2258,12 @@ static HashTable *date_object_get_properties(zval *object TSRMLS_DC) return props; } - /* first we add the date and time in ISO format */ - MAKE_STD_ZVAL(zv); - ZVAL_STRING(zv, date_format("Y-m-d H:i:s", 12, dateobj->time, 1), 0); - zend_hash_update(props, "date", 5, &zv, sizeof(zval), NULL); - - /* then we add the timezone name (or similar) */ + date_object_update_property_date(dateobj, props); if (dateobj->time->is_localtime) { - MAKE_STD_ZVAL(zv); - ZVAL_LONG(zv, dateobj->time->zone_type); - zend_hash_update(props, "timezone_type", 14, &zv, sizeof(zval), NULL); - - MAKE_STD_ZVAL(zv); - switch (dateobj->time->zone_type) { - case TIMELIB_ZONETYPE_ID: - ZVAL_STRING(zv, dateobj->time->tz_info->name, 1); - break; - case TIMELIB_ZONETYPE_OFFSET: { - char *tmpstr = emalloc(sizeof("UTC+05:00")); - timelib_sll utc_offset = dateobj->time->z; - - snprintf(tmpstr, sizeof("+05:00"), "%c%02d:%02d", - utc_offset > 0 ? '-' : '+', - abs(utc_offset / 60), - abs((utc_offset % 60))); - - ZVAL_STRING(zv, tmpstr, 0); - } - break; - case TIMELIB_ZONETYPE_ABBR: - ZVAL_STRING(zv, dateobj->time->tz_abbr, 1); - break; - } - zend_hash_update(props, "timezone", 9, &zv, sizeof(zval), NULL); + date_object_update_property_timezone_type(dateobj, props); + date_object_update_property_timezone(dateobj, props); } - + return props; } diff --git a/ext/date/tests/bug60873.phpt b/ext/date/tests/bug60873.phpt new file mode 100644 index 0000000000000..5ffc56b6cf6fd --- /dev/null +++ b/ext/date/tests/bug60873.phpt @@ -0,0 +1,48 @@ +--TEST-- +Bug #60873 (some inspections of DateTime member variables cause creation, can break asserts) +--INI-- +date.timezone=GMT +--FILE-- +format(DateTime::ISO8601); +$b = new DateTime($str, new DateTimeZone('UTC')); + +echo "\n"; +echo "a->timezone_type: " . $a->timezone_type . "\n"; +echo "b->timezone_type: " . $b->timezone_type . "\n"; + +echo "\na: " . print_r($a, true) . "\n"; +echo "\nstr: $str\n"; +echo "b: " . print_r($b, true) . "\n"; + +echo "a->timezone_type: " . $a->timezone_type . "\n"; +echo "b->timezone_type: " . $b->timezone_type . "\n"; + +$eq = ($a == $b); +echo "\na == b: $eq\n"; +?> +--EXPECTF-- +a->timezone_type: 3 +b->timezone_type: 1 + +a: DateTime Object +( + [timezone_type] => 3 + [date] => 2010-01-01 08:45:00 + [timezone] => UTC +) + + +str: 2010-01-01T08:45:00+0000 +b: DateTime Object +( + [timezone_type] => 1 + [date] => 2010-01-01 08:45:00 + [timezone] => +00:00 +) + +a->timezone_type: 3 +b->timezone_type: 1 + +a == b: 1