From dba88c133bbe30d8fb2187dd830dfd301fa079fd Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Mon, 22 Jul 2013 21:19:08 +0100 Subject: [PATCH 1/2] Fix #60873: Add read_property handler for DateTime object --- ext/date/php_date.c | 96 ++++++++++++++++++++++-------------- ext/date/tests/bug60873.phpt | 48 ++++++++++++++++++ 2 files changed, 106 insertions(+), 38 deletions(-) create mode 100644 ext/date/tests/bug60873.phpt diff --git a/ext/date/php_date.c b/ext/date/php_date.c index 0f8822a906006..34b04b3e45ec3 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,56 +2182,74 @@ 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 void date_object_update_property(php_date_obj *dateobj, HashTable *props, zval *member) { - HashTable *props; zval *zv; - php_date_obj *dateobj; + if (!member || !zend_binary_strcmp(Z_STRVAL_P(member), Z_STRLEN_P(member), "date", sizeof("date")-1)) { + 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); + } + if (dateobj->time->is_localtime) { + if (!member || !zend_binary_strcmp(Z_STRVAL_P(member), Z_STRLEN_P(member), "timezone_type", sizeof("timezone_type")-1)) { + MAKE_STD_ZVAL(zv); + ZVAL_LONG(zv, dateobj->time->zone_type); + zend_hash_update(props, "timezone_type", sizeof("timezone_type"), &zv, sizeof(zval), NULL); + } + if (!member || !zend_binary_strcmp(Z_STRVAL_P(member), Z_STRLEN_P(member), "timezone_type", sizeof("timezone_type")-1)) { + 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); + } + } +} +static zval *date_object_read_property(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC) +{ + php_date_obj *dateobj; + dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC); + date_object_update_property(dateobj, zend_std_get_properties(object TSRMLS_CC), member); - props = zend_std_get_properties(object TSRMLS_CC); - - if (!dateobj->time || GC_G(gc_active)) { - 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); + return (zend_get_std_object_handlers())->read_property(object, member, type, key TSRMLS_CC); +} - /* then we add the timezone name (or similar) */ - 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); +static HashTable *date_object_get_properties(zval *object TSRMLS_DC) +{ + HashTable *props; + php_date_obj *dateobj; - 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; + dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC); - snprintf(tmpstr, sizeof("+05:00"), "%c%02d:%02d", - utc_offset > 0 ? '-' : '+', - abs(utc_offset / 60), - abs((utc_offset % 60))); + props = zend_std_get_properties(object TSRMLS_CC); - 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); + if (!dateobj->time || GC_G(gc_active)) { + return props; } + date_object_update_property(dateobj, props, NULL); + return props; } diff --git a/ext/date/tests/bug60873.phpt b/ext/date/tests/bug60873.phpt new file mode 100644 index 0000000000000..b9e6896f3b73c --- /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 + [timezone] => UTC + [date] => 2010-01-01 08:45:00 +) + + +str: 2010-01-01T08:45:00+0000 +b: DateTime Object +( + [timezone_type] => 1 + [timezone] => +00:00 + [date] => 2010-01-01 08:45:00 +) + +a->timezone_type: 3 +b->timezone_type: 1 + +a == b: 1 \ No newline at end of file From 10d3a62285d6a2225cd319ff513deadde8fbac05 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Thu, 25 Jul 2013 15:17:50 +0100 Subject: [PATCH 2/2] Improve code for reading DateTime property --- ext/date/php_date.c | 88 +++++++++++++++++++++--------------- ext/date/tests/bug60873.phpt | 6 +-- 2 files changed, 54 insertions(+), 40 deletions(-) diff --git a/ext/date/php_date.c b/ext/date/php_date.c index 34b04b3e45ec3..a27b79429b06f 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -2183,54 +2183,64 @@ static HashTable *date_object_get_gc_timezone(zval *object, zval ***table, int * } -static void date_object_update_property(php_date_obj *dateobj, HashTable *props, zval *member) +static inline zval *date_object_update_property_date(php_date_obj *dateobj, HashTable *props) { zval *zv; + 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; +} - if (!member || !zend_binary_strcmp(Z_STRVAL_P(member), Z_STRLEN_P(member), "date", sizeof("date")-1)) { - 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); - } - if (dateobj->time->is_localtime) { - if (!member || !zend_binary_strcmp(Z_STRVAL_P(member), Z_STRLEN_P(member), "timezone_type", sizeof("timezone_type")-1)) { - MAKE_STD_ZVAL(zv); - ZVAL_LONG(zv, dateobj->time->zone_type); - zend_hash_update(props, "timezone_type", sizeof("timezone_type"), &zv, sizeof(zval), NULL); - } - if (!member || !zend_binary_strcmp(Z_STRVAL_P(member), Z_STRLEN_P(member), "timezone_type", sizeof("timezone_type")-1)) { - 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; +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))); + 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; + ZVAL_STRING(zv, tmpstr, 0); } - zend_hash_update(props, "timezone", 9, &zv, sizeof(zval), NULL); - } + 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 *dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC); - dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC); - date_object_update_property(dateobj, zend_std_get_properties(object TSRMLS_CC), member); + 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); } @@ -2248,7 +2258,11 @@ static HashTable *date_object_get_properties(zval *object TSRMLS_DC) return props; } - date_object_update_property(dateobj, props, NULL); + date_object_update_property_date(dateobj, props); + if (dateobj->time->is_localtime) { + 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 index b9e6896f3b73c..5ffc56b6cf6fd 100644 --- a/ext/date/tests/bug60873.phpt +++ b/ext/date/tests/bug60873.phpt @@ -29,8 +29,8 @@ b->timezone_type: 1 a: DateTime Object ( [timezone_type] => 3 - [timezone] => UTC [date] => 2010-01-01 08:45:00 + [timezone] => UTC ) @@ -38,11 +38,11 @@ str: 2010-01-01T08:45:00+0000 b: DateTime Object ( [timezone_type] => 1 - [timezone] => +00:00 [date] => 2010-01-01 08:45:00 + [timezone] => +00:00 ) a->timezone_type: 3 b->timezone_type: 1 -a == b: 1 \ No newline at end of file +a == b: 1