php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login | |
Patch glopes_date_5.4.patch for Date/time related Bug #53437Patch version 2013-03-05 11:20 UTC Return to Bug #53437 | Download this patchThis patch is obsolete Obsoleted by patches: Patch Revisions:Developer: ab@php.netdiff --git a/ext/date/php_date.c b/ext/date/php_date.c index fd6453f..ca84bf6 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -23,6 +23,7 @@ #include "php_main.h" #include "php_globals.h" #include "php_ini.h" +#include "ext/standard/base64.h" #include "ext/standard/info.h" #include "ext/standard/php_versioning.h" #include "ext/standard/php_math.h" @@ -472,6 +473,8 @@ const zend_function_entry date_funcs_interval[] = { const zend_function_entry date_funcs_period[] = { PHP_ME(DatePeriod, __construct, arginfo_date_period_construct, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC) + PHP_ME(DatePeriod, __wakeup, NULL, ZEND_ACC_PUBLIC) + PHP_ME(DatePeriod, __set_state, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) PHP_FE_END }; @@ -569,9 +572,16 @@ 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_period(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); +static zval *date_period_read_property(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC); +static zval **date_period_get_property_ptr_ptr(zval *object, zval *member, const zend_literal *key TSRMLS_DC); +static void date_period_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC); + +static int php_date_interval_serialize(zval *object, unsigned char **buffer, zend_uint *buf_len, zend_serialize_data *data TSRMLS_DC); +static int php_date_interval_unserialize(zval **object, zend_class_entry *ce, const unsigned char *buf, zend_uint buf_len, zend_unserialize_data *data TSRMLS_DC); /* {{{ Module struct */ zend_module_entry date_module_entry = { @@ -1966,6 +1976,8 @@ static void date_register_classes(TSRMLS_D) INIT_CLASS_ENTRY(ce_interval, "DateInterval", date_funcs_interval); ce_interval.create_object = date_object_new_interval; date_ce_interval = zend_register_internal_class_ex(&ce_interval, NULL, NULL TSRMLS_CC); + date_ce_interval->serialize = php_date_interval_serialize; + date_ce_interval->unserialize = php_date_interval_unserialize; memcpy(&date_object_handlers_interval, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); date_object_handlers_interval.clone_obj = date_object_clone_interval; date_object_handlers_interval.read_property = date_interval_read_property; @@ -1982,6 +1994,10 @@ static void date_register_classes(TSRMLS_D) zend_class_implements(date_ce_period TSRMLS_CC, 1, zend_ce_traversable); memcpy(&date_object_handlers_period, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); date_object_handlers_period.clone_obj = date_object_clone_period; + date_object_handlers_period.get_properties = date_object_get_properties_period; + date_object_handlers_period.read_property = date_period_read_property; + date_object_handlers_period.get_property_ptr_ptr = date_period_get_property_ptr_ptr; + date_object_handlers_period.write_property = date_period_write_property; #define REGISTER_PERIOD_CLASS_CONST_STRING(const_name, value) \ zend_declare_class_constant_long(date_ce_period, const_name, sizeof(const_name)-1, value TSRMLS_CC); @@ -2070,40 +2086,29 @@ 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_properties(zval *object TSRMLS_DC) +static void date_object_to_serializable_elements(timelib_time *time, HashTable *out_container) { - HashTable *props; zval *zv; - php_date_obj *dateobj; - - - dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC); - - props = zend_std_get_properties(object TSRMLS_CC); - - 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); + ZVAL_STRING(zv, date_format("Y-m-d H:i:s", 12, time, 1), 0); + zend_hash_update(out_container, "date", 5, &zv, sizeof(zval), NULL); /* then we add the timezone name (or similar) */ - if (dateobj->time->is_localtime) { + if (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); + ZVAL_LONG(zv, time->zone_type); + zend_hash_update(out_container, "timezone_type", 14, &zv, sizeof(zval), NULL); MAKE_STD_ZVAL(zv); - switch (dateobj->time->zone_type) { + switch (time->zone_type) { case TIMELIB_ZONETYPE_ID: - ZVAL_STRING(zv, dateobj->time->tz_info->name, 1); + ZVAL_STRING(zv, time->tz_info->name, 1); break; case TIMELIB_ZONETYPE_OFFSET: { char *tmpstr = emalloc(sizeof("UTC+05:00")); - timelib_sll utc_offset = dateobj->time->z; + timelib_sll utc_offset = time->z; snprintf(tmpstr, sizeof("+05:00"), "%c%02d:%02d", utc_offset > 0 ? '-' : '+', @@ -2114,12 +2119,29 @@ static HashTable *date_object_get_properties(zval *object TSRMLS_DC) } break; case TIMELIB_ZONETYPE_ABBR: - ZVAL_STRING(zv, dateobj->time->tz_abbr, 1); + ZVAL_STRING(zv, time->tz_abbr, 1); break; } - zend_hash_update(props, "timezone", 9, &zv, sizeof(zval), NULL); + zend_hash_update(out_container, "timezone", 9, &zv, sizeof(zval), NULL); } +} + +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); + + props = zend_std_get_properties(object TSRMLS_CC); + + if (!dateobj->time || GC_G(gc_active)) { + return props; + } + + date_object_to_serializable_elements(dateobj->time, props); + return props; } @@ -2225,11 +2247,10 @@ static HashTable *date_object_get_gc_interval(zval *object, zval ***table, int * static HashTable *date_object_get_properties_interval(zval *object TSRMLS_DC) { - HashTable *props; - zval *zv; - php_interval_obj *intervalobj; - - + HashTable *props; + php_interval_obj *intervalobj; + zval *zv; + intervalobj = (php_interval_obj *) zend_object_store_get_object(object TSRMLS_CC); props = zend_std_get_properties(object TSRMLS_CC); @@ -2241,7 +2262,7 @@ static HashTable *date_object_get_properties_interval(zval *object TSRMLS_DC) #define PHP_DATE_INTERVAL_ADD_PROPERTY(n,f) \ MAKE_STD_ZVAL(zv); \ ZVAL_LONG(zv, intervalobj->diff->f); \ - zend_hash_update(props, n, strlen(n) + 1, &zv, sizeof(zval), NULL); + zend_hash_update(props, n, sizeof(n), &zv, sizeof(zval), NULL); PHP_DATE_INTERVAL_ADD_PROPERTY("y", y); PHP_DATE_INTERVAL_ADD_PROPERTY("m", m); @@ -2258,6 +2279,8 @@ static HashTable *date_object_get_properties_interval(zval *object TSRMLS_DC) zend_hash_update(props, "days", 5, &zv, sizeof(zval), NULL); } +#undef PHP_DATE_INTERVAL_ADD_PROPERTY + return props; } @@ -2298,6 +2321,78 @@ static zend_object_value date_object_clone_period(zval *this_ptr TSRMLS_DC) return new_ov; } +static HashTable *date_object_get_properties_period(zval *object TSRMLS_DC) +{ + HashTable *props; + zval *zv; + php_period_obj *period_obj; + + + period_obj = zend_object_store_get_object(object TSRMLS_CC); + + props = zend_std_get_properties(object TSRMLS_CC); + + if (!period_obj->start || GC_G(gc_active)) { + return props; + } + + MAKE_STD_ZVAL(zv); + if (period_obj->start) { + php_date_obj *date_obj; + object_init_ex(zv, date_ce_date); + date_obj = zend_object_store_get_object(zv TSRMLS_CC); + date_obj->time = timelib_time_clone(period_obj->start); + } else { + ZVAL_NULL(zv); + } + zend_hash_update(props, "start", sizeof("start"), &zv, sizeof(zv), NULL); + + MAKE_STD_ZVAL(zv); + if (period_obj->current) { + php_date_obj *date_obj; + object_init_ex(zv, date_ce_date); + date_obj = zend_object_store_get_object(zv TSRMLS_CC); + date_obj->time = timelib_time_clone(period_obj->current); + } else { + ZVAL_NULL(zv); + } + zend_hash_update(props, "current", sizeof("current"), &zv, sizeof(zv), NULL); + + MAKE_STD_ZVAL(zv); + if (period_obj->end) { + php_date_obj *date_obj; + object_init_ex(zv, date_ce_date); + date_obj = zend_object_store_get_object(zv TSRMLS_CC); + date_obj->time = timelib_time_clone(period_obj->end); + } else { + ZVAL_NULL(zv); + } + zend_hash_update(props, "end", sizeof("end"), &zv, sizeof(zv), NULL); + + MAKE_STD_ZVAL(zv); + if (period_obj->interval) { + php_interval_obj *interval_obj; + object_init_ex(zv, date_ce_interval); + interval_obj = zend_object_store_get_object(zv TSRMLS_CC); + interval_obj->diff = timelib_rel_time_clone(period_obj->interval); + interval_obj->initialized = 1; + } else { + ZVAL_NULL(zv); + } + zend_hash_update(props, "interval", sizeof("interval"), &zv, sizeof(zv), NULL); + + /* converted to larger type (int->long); must check when unserializing */ + MAKE_STD_ZVAL(zv); + ZVAL_LONG(zv, (long) period_obj->recurrences); + zend_hash_update(props, "recurrences", sizeof("recurrences"), &zv, sizeof(zv), NULL); + + MAKE_STD_ZVAL(zv); + ZVAL_BOOL(zv, period_obj->include_start_date); + zend_hash_update(props, "include_start_date", sizeof("include_start_date"), &zv, sizeof(zv), NULL); + + return props; +} + static void date_object_free_storage_date(void *object TSRMLS_DC) { php_date_obj *intern = (php_date_obj *)object; @@ -2512,7 +2607,7 @@ PHP_METHOD(DateTime, __construct) } /* }}} */ -static int php_date_initialize_from_hash(zval **return_value, php_date_obj **dateobj, HashTable *myht TSRMLS_DC) +static int php_date_initialize_from_hash(php_date_obj *dateobj, HashTable *myht TSRMLS_DC) { zval **z_date = NULL; zval **z_timezone = NULL; @@ -2533,7 +2628,7 @@ static int php_date_initialize_from_hash(zval **return_value, php_date_obj **dat 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)); - php_date_initialize(*dateobj, tmp, Z_STRLEN_PP(z_date) + Z_STRLEN_PP(z_timezone) + 1, NULL, NULL, 0 TSRMLS_CC); + php_date_initialize(dateobj, tmp, Z_STRLEN_PP(z_date) + Z_STRLEN_PP(z_timezone) + 1, NULL, NULL, 0 TSRMLS_CC); efree(tmp); return 1; } @@ -2549,7 +2644,7 @@ static int php_date_initialize_from_hash(zval **return_value, php_date_obj **dat tzobj->tzi.tz = tzi; tzobj->initialized = 1; - php_date_initialize(*dateobj, Z_STRVAL_PP(z_date), Z_STRLEN_PP(z_date), NULL, tmp_obj, 0 TSRMLS_CC); + php_date_initialize(dateobj, Z_STRVAL_PP(z_date), Z_STRLEN_PP(z_date), NULL, tmp_obj, 0 TSRMLS_CC); zval_ptr_dtor(&tmp_obj); return 1; } @@ -2575,7 +2670,7 @@ PHP_METHOD(DateTime, __set_state) php_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 TSRMLS_CC); + php_date_initialize_from_hash(dateobj, myht TSRMLS_CC); } /* }}} */ @@ -2591,7 +2686,7 @@ PHP_METHOD(DateTime, __wakeup) myht = Z_OBJPROP_P(object); - php_date_initialize_from_hash(&return_value, &dateobj, myht TSRMLS_CC); + php_date_initialize_from_hash(dateobj, myht TSRMLS_CC); } /* }}} */ @@ -3671,21 +3766,6 @@ PHP_METHOD(DateInterval, __set_state) } /* }}} */ -/* {{{ proto DateInterval::__wakeup() -*/ -PHP_METHOD(DateInterval, __wakeup) -{ - zval *object = getThis(); - php_interval_obj *intobj; - HashTable *myht; - - intobj = (php_interval_obj *) zend_object_store_get_object(object TSRMLS_CC); - - myht = Z_OBJPROP_P(object); - - php_date_interval_initialize_from_hash(&return_value, &intobj, myht TSRMLS_CC); -} -/* }}} */ /* {{{ proto DateInterval date_interval_create_from_date_string(string time) Uses the normal date parsers and sets up a DateInterval from the relative parts of the parsed string */ @@ -3712,6 +3792,187 @@ PHP_FUNCTION(date_interval_create_from_date_string) } /* }}} */ +#define PHP_DATE_INTERVAL_UNSER_RAW_SIZE 92 /* 6 * 8 + 4 * 4 + 8 + (4 + 8) + 2 * 4; not null-terminated */ + +static int php_date_interval_serialize(zval *object, unsigned char **buffer, zend_uint *buf_len, zend_serialize_data *data TSRMLS_DC) +{ + php_interval_obj *interval_obj; + timelib_rel_time *or_trl; + unsigned char tmp[PHP_DATE_INTERVAL_UNSER_RAW_SIZE], + *b64_res; + int cursor = 0, + b64_len = 0; + +#define PHP_SER_WRITE_I32(v) \ + { \ + uint32_t t = htonl((uint32_t) (v)); \ + memcpy(&tmp[cursor], (const void *) &t, sizeof(t)); \ + cursor += sizeof(t); \ + } + +#define PHP_SER_WRITE_I64(v) \ + PHP_SER_WRITE_I32(((uint64_t) (v)) >> 32) \ + PHP_SER_WRITE_I32(((uint64_t) (v)) & 0xFFFFFFFF) + + + interval_obj = zend_object_store_get_object(object TSRMLS_CC); + or_trl = interval_obj->diff; + + PHP_SER_WRITE_I64(or_trl->y); + PHP_SER_WRITE_I64(or_trl->m); + PHP_SER_WRITE_I64(or_trl->d); + PHP_SER_WRITE_I64(or_trl->h); + PHP_SER_WRITE_I64(or_trl->i); + PHP_SER_WRITE_I64(or_trl->s); + PHP_SER_WRITE_I32(or_trl->weekday); + PHP_SER_WRITE_I32(or_trl->weekday_behavior); + PHP_SER_WRITE_I32(or_trl->first_last_day_of); + PHP_SER_WRITE_I32(or_trl->invert); + PHP_SER_WRITE_I64(or_trl->days); + PHP_SER_WRITE_I32(or_trl->special.type); + PHP_SER_WRITE_I64(or_trl->special.amount); + PHP_SER_WRITE_I32(or_trl->have_weekday_relative); + PHP_SER_WRITE_I32(or_trl->have_special_relative); + +#undef PHP_SER_WRITE_I32 +#undef PHP_SER_WRITE_I64 + + assert(cursor == PHP_DATE_INTERVAL_UNSER_RAW_SIZE); + + /* base64 to make serialization data binary safe */ + b64_res = php_base64_encode(tmp, sizeof(tmp), &b64_len); + + if (b64_res == NULL) { + return FAILURE; + } + + *buffer = b64_res; + *buf_len = b64_len; + + return SUCCESS; +} + +static int php_date_interval_unserialize(zval **object, zend_class_entry *ce, const unsigned char *buf, zend_uint buf_len, zend_unserialize_data *data TSRMLS_DC) +{ + php_interval_obj *interval_obj; + timelib_rel_time *trl; + unsigned char *b64_unenc; + int b64_unenc_size, + cursor = 0; + + /* should be 124, but we prefer the stricter check on the unencoded size instead */ + if (ce != date_ce_interval || buf_len > 150) { + return FAILURE; + } + + b64_unenc = php_base64_decode_ex(buf, (int) buf_len, &b64_unenc_size, 1); + if (b64_unenc == NULL) { + return FAILURE; + } + if (b64_unenc_size != PHP_DATE_INTERVAL_UNSER_RAW_SIZE) { + efree(b64_unenc); + return FAILURE; + } + + if (*object == NULL) { + MAKE_STD_ZVAL(*object); + } + object_init_ex(*object, ce); + + interval_obj = zend_object_store_get_object(*object TSRMLS_CC); + trl = timelib_rel_time_ctor(); + interval_obj->diff = trl; + +/* copy to signed 32_t, preserving bit pattern (casting the result of ntohl and + * assigning to st would probably suffice, but it's technically implementation + * defined behavior) and then assign to the field. This is done to force sign- + * extension if an int has 64 bits and the field is signed. If the field is + * unsigned, it would have the side-effect of corrupting values >= 2^31, as in + * (uint32_t)0xFFFFFFFE -> (int32_t)-2 -> (uint64_t)FFFFFFFFFFFFFFFE, which is + * why it isn't used for those fields. */ +#define PHP_SER_READ_I32_SIGNED(v) \ + { \ + int32_t st; \ + *((uint32_t*) &st) = ntohl(*((uint32_t*) &b64_unenc[cursor])); \ + (v) = st; \ + cursor += sizeof(uint32_t); \ + } + +#define PHP_SER_READ_I32_UNSIGNED(v) \ + (v) = ntohl(*((uint32_t*) &b64_unenc[cursor])); \ + cursor += sizeof(uint32_t); \ + +#define PHP_SER_READ_I64(v) \ + *((uint64_t*) &(v)) = (((uint64_t) ntohl(*((uint32_t*) &b64_unenc[cursor]))) << 32) | \ + ((uint64_t) ntohl(*((uint32_t*) &b64_unenc[cursor + sizeof(uint32_t)]))); \ + cursor += sizeof(uint64_t); + + PHP_SER_READ_I64(trl->y); + PHP_SER_READ_I64(trl->m); + PHP_SER_READ_I64(trl->d); + PHP_SER_READ_I64(trl->h); + PHP_SER_READ_I64(trl->i); + PHP_SER_READ_I64(trl->s); + PHP_SER_READ_I32_SIGNED(trl->weekday); + PHP_SER_READ_I32_SIGNED(trl->weekday_behavior); + PHP_SER_READ_I32_SIGNED(trl->first_last_day_of); + PHP_SER_READ_I32_SIGNED(trl->invert); + PHP_SER_READ_I64(trl->days); + PHP_SER_READ_I32_UNSIGNED(trl->special.type); + PHP_SER_READ_I64(trl->special.amount); + PHP_SER_READ_I32_UNSIGNED(trl->have_weekday_relative); + PHP_SER_READ_I32_UNSIGNED(trl->have_special_relative); + +#undef PHP_SER_READ_I32 +#undef PHP_SER_READ_I64 + + efree(b64_unenc); + + assert(cursor == PHP_DATE_INTERVAL_UNSER_RAW_SIZE); + + /* in case they're somewhere tested with if (rtime->have_weekday_relative == 1)... */ + trl->invert = !!trl->invert; + trl->have_weekday_relative = !!trl->have_weekday_relative; + trl->have_special_relative = !!trl->have_special_relative; + + interval_obj->initialized = 1; + + return SUCCESS; +} + +/* {{{ proto DateInterval::__wakeup() +*/ +PHP_METHOD(DateInterval, __wakeup) +{ + zval *object = getThis(); + php_interval_obj *interval_obj; + timelib_rel_time *rtime; + + interval_obj = zend_object_store_get_object(object TSRMLS_CC); + rtime = interval_obj->diff; + + /* validate state of DateInterval object */ + if (rtime->weekday < -7 || rtime->weekday > 6) { + php_error(E_ERROR, "Invalid serialization data for DateInterval object (weekday)"); + } + if (rtime->weekday_behavior < 0 || rtime->weekday_behavior > 2) { + php_error(E_ERROR, "Invalid serialization data for DateInterval object (weekday_behavior)"); + } + if (rtime->have_special_relative && ( + rtime->special.type != TIMELIB_SPECIAL_WEEKDAY && + rtime->special.type != TIMELIB_SPECIAL_DAY_OF_WEEK_IN_MONTH && + rtime->special.type != TIMELIB_SPECIAL_LAST_DAY_OF_WEEK_IN_MONTH)) { + php_error(E_ERROR, "Invalid serialization data for DateInterval object (special.type)"); + } + if (rtime->special.amount > 12 || rtime->special.amount < -12) { + php_error(E_ERROR, "Invalid serialization data for DateInterval object (special.amount)"); + } + if (rtime->first_last_day_of < 0 || rtime->first_last_day_of > 2) { + php_error(E_ERROR, "Invalid serialization data for DateInterval object (first_last_day_of)"); + } +} +/* }}} */ + /* {{{ date_interval_format - */ static char *date_interval_format(char *format, int format_len, timelib_rel_time *t) { @@ -3818,6 +4079,43 @@ static int date_period_initialize(timelib_time **st, timelib_time **et, timelib_ return retval; } +/* {{{ date_period_read_property */ +static zval *date_period_read_property(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC) +{ + zval *zv; + if (type != BP_VAR_IS && type != BP_VAR_R) { + php_error_docref(NULL TSRMLS_CC, E_ERROR, "Retrieval of DatePeriod properties for modification is unsupported"); + } + + Z_OBJPROP_P(object); /* build properties hash table */ + + zv = std_object_handlers.read_property(object, member, type, key TSRMLS_CC); + if (Z_TYPE_P(zv) == IS_OBJECT && Z_OBJ_HANDLER_P(zv, clone_obj)) { + /* defensive copy */ + zend_object_value zov = Z_OBJ_HANDLER_P(zv, clone_obj)(zv TSRMLS_CC); + MAKE_STD_ZVAL(zv); + Z_TYPE_P(zv) = IS_OBJECT; + Z_OBJVAL_P(zv) = zov; + } + + return zv; +} +/* }}} */ + +/* {{{ date_period_get_property_ptr_ptr */ +static zval **date_period_get_property_ptr_ptr(zval *object, zval *member, const zend_literal *key TSRMLS_DC) +{ + return NULL; /* force fallback to read_property */ +} +/* }}} */ + +/* {{{ date_period_write_property */ +static void date_period_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC) +{ + php_error_docref(NULL TSRMLS_CC, E_ERROR, "Writing to DatePeriod properties is unsupported"); +} +/* }}} */ + /* {{{ proto DatePeriod::__construct(DateTime $start, DateInterval $interval, int recurrences|DateTime $end) Creates new DatePeriod object. */ @@ -3904,6 +4202,119 @@ PHP_METHOD(DatePeriod, __construct) } /* }}} */ +static int php_date_period_initialize_from_hash(php_period_obj *period_obj, HashTable *myht TSRMLS_DC) +{ + zval **ht_entry; + + /* this function does no rollback on error */ + + if (zend_hash_find(myht, "start", sizeof("start"), (void**) &ht_entry) == SUCCESS) { + if (Z_TYPE_PP(ht_entry) == IS_OBJECT && Z_OBJCE_PP(ht_entry) == date_ce_date) { + php_date_obj *date_obj; + date_obj = zend_object_store_get_object(*ht_entry TSRMLS_CC); + period_obj->start = timelib_time_clone(date_obj->time); + } else if (Z_TYPE_PP(ht_entry) != IS_NULL) { + return 0; + } + } else { + return 0; + } + + if (zend_hash_find(myht, "end", sizeof("end"), (void**) &ht_entry) == SUCCESS) { + if (Z_TYPE_PP(ht_entry) == IS_OBJECT && Z_OBJCE_PP(ht_entry) == date_ce_date) { + php_date_obj *date_obj; + date_obj = zend_object_store_get_object(*ht_entry TSRMLS_CC); + period_obj->end = timelib_time_clone(date_obj->time); + } else if (Z_TYPE_PP(ht_entry) != IS_NULL) { + return 0; + } + } else { + return 0; + } + + if (zend_hash_find(myht, "current", sizeof("current"), (void**) &ht_entry) == SUCCESS) { + if (Z_TYPE_PP(ht_entry) == IS_OBJECT && Z_OBJCE_PP(ht_entry) == date_ce_date) { + php_date_obj *date_obj; + date_obj = zend_object_store_get_object(*ht_entry TSRMLS_CC); + period_obj->current = timelib_time_clone(date_obj->time); + } else if (Z_TYPE_PP(ht_entry) != IS_NULL) { + return 0; + } + } else { + return 0; + } + + if (zend_hash_find(myht, "interval", sizeof("interval"), (void**) &ht_entry) == SUCCESS) { + if (Z_TYPE_PP(ht_entry) == IS_OBJECT && Z_OBJCE_PP(ht_entry) == date_ce_interval) { + php_interval_obj *interval_obj; + interval_obj = zend_object_store_get_object(*ht_entry TSRMLS_CC); + period_obj->interval = timelib_rel_time_clone(interval_obj->diff); + } else { /* interval is required */ + return 0; + } + } else { + return 0; + } + + if (zend_hash_find(myht, "recurrences", sizeof("recurrences"), (void**) &ht_entry) == SUCCESS && + Z_TYPE_PP(ht_entry) == IS_LONG && Z_LVAL_PP(ht_entry) >= 0 && Z_LVAL_PP(ht_entry) <= INT_MAX) { + period_obj->recurrences = Z_LVAL_PP(ht_entry); + } else { + return 0; + } + + if (zend_hash_find(myht, "include_start_date", sizeof("include_start_date"), (void**) &ht_entry) == SUCCESS && + Z_TYPE_PP(ht_entry) == IS_BOOL) { + period_obj->include_start_date = Z_BVAL_PP(ht_entry); + } else { + return 0; + } + + period_obj->initialized = 1; + + return 1; +} + +/* {{{ proto DatePeriod::__set_state() +*/ +PHP_METHOD(DatePeriod, __set_state) +{ + php_period_obj *period_obj; + zval *array; + HashTable *myht; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) == FAILURE) { + RETURN_FALSE; + } + + myht = Z_ARRVAL_P(array); + + object_init_ex(return_value, date_ce_period); + period_obj = zend_object_store_get_object(return_value TSRMLS_CC); + if (!php_date_period_initialize_from_hash(period_obj, myht TSRMLS_CC)) { + php_error(E_ERROR, "Invalid serialization data for DatePeriod object"); + } +} +/* }}} */ + +/* {{{ proto DatePeriod::__wakeup() +*/ +PHP_METHOD(DatePeriod, __wakeup) +{ + zval *object = getThis(); + php_period_obj *period_obj; + HashTable *myht; + + period_obj = zend_object_store_get_object(object TSRMLS_CC); + + myht = Z_OBJPROP_P(object); + + if (!php_date_period_initialize_from_hash(period_obj, myht TSRMLS_CC)) { + php_error(E_ERROR, "Invalid serialization data for DatePeriod object"); + } +} +/* }}} */ + static int check_id_allowed(char *id, long what) { if (what & PHP_DATE_TIMEZONE_GROUP_AFRICA && strncasecmp(id, "Africa/", 7) == 0) return 1; diff --git a/ext/date/php_date.h b/ext/date/php_date.h index f0b662b..806c27a 100644 --- a/ext/date/php_date.h +++ b/ext/date/php_date.h @@ -88,6 +88,8 @@ PHP_FUNCTION(date_interval_format); PHP_FUNCTION(date_interval_create_from_date_string); PHP_METHOD(DatePeriod, __construct); +PHP_METHOD(DatePeriod, __wakeup); +PHP_METHOD(DatePeriod, __set_state); /* Options and Configuration */ PHP_FUNCTION(date_default_timezone_set); |
Copyright © 2001-2024 The PHP Group All rights reserved. |
Last updated: Sun Nov 24 03:01:32 2024 UTC |