From 0e9a12d8b16aee763d946f2271c8dae9dc49c4d0 Mon Sep 17 00:00:00 2001 From: Derick Rethans Date: Fri, 14 Mar 2008 16:19:52 +0000 Subject: [PATCH] - MFH: Allow datetime objects to be serialized and woken up. - MFH: Implemented __set_state(). --- NEWS | 1 + ext/date/php_date.c | 140 ++++++++++++++++++++++++++++++++++++++++++++ ext/date/php_date.h | 2 + 3 files changed, 143 insertions(+) diff --git a/NEWS b/NEWS index 27c5251c78..16e1e63ecb 100644 --- a/NEWS +++ b/NEWS @@ -39,6 +39,7 @@ PHP NEWS returned. . support for "first/last day of " style texts. . support for date/time strings returned by MS SQL. + . support for serialization and unserialization of DateTime objects. - Added functionality to SPL extension: . Added ability to store associative information with objects in SplObjectStorage. (Marcus) diff --git a/ext/date/php_date.c b/ext/date/php_date.c index ddb1cb85d8..27ba5aa164 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -205,6 +205,8 @@ const zend_function_entry date_functions[] = { const zend_function_entry date_funcs_date[] = { PHP_ME(DateTime, __construct, NULL, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC) + PHP_ME(DateTime, __wakeup, NULL, ZEND_ACC_PUBLIC) + PHP_ME(DateTime, __set_state, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) PHP_ME_MAPPING(createFromFormat, date_create_from_format, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) PHP_ME_MAPPING(getLastErrors, date_get_last_errors, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) PHP_ME_MAPPING(format, date_format, NULL, 0) @@ -272,6 +274,7 @@ typedef struct _php_timezone_obj php_timezone_obj; struct _php_date_obj { zend_object std; timelib_time *time; + HashTable *props; }; struct _php_timezone_obj { @@ -320,6 +323,7 @@ static zend_object_value date_object_new_date(zend_class_entry *class_type TSRML static zend_object_value date_object_new_timezone(zend_class_entry *class_type TSRMLS_DC); static zend_object_value date_object_clone_date(zval *this_ptr TSRMLS_DC); static int date_object_compare_date(zval *d1, zval *d2 TSRMLS_DC); +static HashTable *date_object_get_properties(zval *object TSRMLS_DC); static zend_object_value date_object_clone_timezone(zval *this_ptr TSRMLS_DC); /* This is need to ensure that session extension request shutdown occurs 1st, because it uses the date extension */ @@ -1524,6 +1528,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.get_properties = date_object_get_properties; #define REGISTER_DATE_CLASS_CONST_STRING(const_name, value) \ zend_declare_class_constant_stringl(date_ce_date, const_name, sizeof(const_name)-1, value, sizeof(value)-1 TSRMLS_CC); @@ -1633,6 +1638,59 @@ static int date_object_compare_date(zval *d1, zval *d2 TSRMLS_DC) return 1; } +static HashTable *date_object_get_properties(zval *object TSRMLS_DC) +{ + HashTable *props; + zval *zv; + php_date_obj *dateobj; + + + dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC); + + props = dateobj->std.properties; + + if (!dateobj->time) { + 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) + 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); + } + + return props; +} + static inline zend_object_value date_object_new_timezone_ex(zend_class_entry *class_type, php_timezone_obj **ptr TSRMLS_DC) { php_timezone_obj *intern; @@ -1886,6 +1944,88 @@ PHP_METHOD(DateTime, __construct) } /* }}} */ +static int php_date_initialize_from_hash(zval **return_value, php_date_obj **dateobj, HashTable *myht) +{ + zval **z_date = NULL; + zval **z_timezone = NULL; + zval **z_timezone_type = NULL; + zval *tmp_obj = NULL; + timelib_tzinfo *tzi; + php_timezone_obj *tzobj; + + if (zend_hash_find(myht, "date", 5, (void**) &z_date) == SUCCESS) { + convert_to_string(*z_date); + if (zend_hash_find(myht, "timezone_type", 14, (void**) &z_timezone_type) == SUCCESS) { + convert_to_long(*z_timezone_type); + if (zend_hash_find(myht, "timezone", 9, (void**) &z_timezone) == SUCCESS) { + convert_to_string(*z_timezone); + + switch (Z_LVAL_PP(z_timezone_type)) { + case TIMELIB_ZONETYPE_OFFSET: + case TIMELIB_ZONETYPE_ABBR: { + char *tmp = emalloc(Z_STRLEN_PP(z_date) + Z_STRLEN_PP(z_timezone) + 2); + snprintf(tmp, Z_STRLEN_PP(z_date) + Z_STRLEN_PP(z_timezone) + 2, "%s %s", Z_STRVAL_PP(z_date), Z_STRVAL_PP(z_timezone)); + date_initialize(*dateobj, tmp, Z_STRLEN_PP(z_date) + Z_STRLEN_PP(z_timezone) + 1, NULL, NULL, 0 TSRMLS_CC); + efree(tmp); + return 1; + } + + case TIMELIB_ZONETYPE_ID: + convert_to_string(*z_timezone); + + tzi = php_date_parse_tzfile(Z_STRVAL_PP(z_timezone), DATE_TIMEZONEDB TSRMLS_CC); + + tzobj = zend_object_store_get_object(date_instantiate(date_ce_timezone, tmp_obj TSRMLS_CC) TSRMLS_CC); + tzobj->type = TIMELIB_ZONETYPE_ID; + tzobj->tzi.tz = tzi; + tzobj->initialized = 1; + + date_initialize(*dateobj, Z_STRVAL_PP(z_date), Z_STRLEN_PP(z_date), NULL, tmp_obj, 0 TSRMLS_CC); + return 1; + } + } + } + } + return 0; +} + +/* {{{ proto DateTime::__set_state() +*/ +PHP_METHOD(DateTime, __set_state) +{ + zval *object = getThis(); + php_date_obj *dateobj; + zval *array; + HashTable *myht; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) == FAILURE) { + RETURN_FALSE; + } + + myht = HASH_OF(array); + + date_instantiate(date_ce_date, return_value TSRMLS_CC); + dateobj = (php_date_obj *) zend_object_store_get_object(return_value TSRMLS_CC); + php_date_initialize_from_hash(&return_value, &dateobj, myht); +} +/* }}} */ + +/* {{{ proto DateTime::__wakeup() +*/ +PHP_METHOD(DateTime, __wakeup) +{ + zval *object = getThis(); + php_date_obj *dateobj; + HashTable *myht; + + dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC); + + myht = Z_OBJPROP_P(object); + + php_date_initialize_from_hash(&return_value, &dateobj, myht); +} +/* }}} */ + /* Helper function used to add an associative array of warnings and errors to a zval */ void zval_from_error_container(zval *z, timelib_error_container *error) { diff --git a/ext/date/php_date.h b/ext/date/php_date.h index 5804f2a2c4..06924865f5 100644 --- a/ext/date/php_date.h +++ b/ext/date/php_date.h @@ -48,6 +48,8 @@ PHP_FUNCTION(getdate); /* Advanced Interface */ PHP_METHOD(DateTime, __construct); +PHP_METHOD(DateTime, __wakeup); +PHP_METHOD(DateTime, __set_state); PHP_FUNCTION(date_create); PHP_FUNCTION(date_create_from_format); PHP_FUNCTION(date_parse); -- 2.50.1