--- embedaddon/php/ext/date/php_date.c 2012/05/29 12:34:36 1.1.1.2 +++ embedaddon/php/ext/date/php_date.c 2013/07/22 01:31:38 1.1.1.3 @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2012 The PHP Group | + | Copyright (c) 1997-2013 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: php_date.c,v 1.1.1.2 2012/05/29 12:34:36 misho Exp $ */ +/* $Id: php_date.c,v 1.1.1.3 2013/07/22 01:31:38 misho Exp $ */ #include "php.h" #include "php_streams.h" @@ -39,6 +39,20 @@ static __inline __int64_t php_date_llabs( __int64_t i static inline long long php_date_llabs( long long i ) { return i >= 0 ? i : -i; } #endif +#ifdef PHP_WIN32 +#define DATE_I64_BUF_LEN 65 +# define DATE_I64A(i, s, len) _i64toa_s(i, s, len, 10) +# define DATE_A64I(i, s) i = _atoi64(s) +#else +#define DATE_I64_BUF_LEN 65 +# define DATE_I64A(i, s, len) \ + do { \ + int st = snprintf(s, len, "%lld", i); \ + s[st] = '\0'; \ + } while (0); +# define DATE_A64I(i, s) i = atoll(s) +#endif + /* {{{ arginfo */ ZEND_BEGIN_ARG_INFO_EX(arginfo_date, 0, 0, 1) ZEND_ARG_INFO(0, format) @@ -472,6 +486,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 }; @@ -495,9 +511,11 @@ int php_date_global_timezone_db_enabled; /* on 90'35; common sunrise declaration (sun body disappeared) */ #define DATE_SUNRISE_ZENITH "90.583333" +static PHP_INI_MH(OnUpdate_date_timezone); + /* {{{ INI Settings */ PHP_INI_BEGIN() - STD_PHP_INI_ENTRY("date.timezone", "", PHP_INI_ALL, OnUpdateString, default_timezone, zend_date_globals, date_globals) + STD_PHP_INI_ENTRY("date.timezone", "", PHP_INI_ALL, OnUpdate_date_timezone, default_timezone, zend_date_globals, date_globals) PHP_INI_ENTRY("date.default_latitude", DATE_DEFAULT_LATITUDE, PHP_INI_ALL, NULL) PHP_INI_ENTRY("date.default_longitude", DATE_DEFAULT_LONGITUDE, PHP_INI_ALL, NULL) PHP_INI_ENTRY("date.sunset_zenith", DATE_SUNSET_ZENITH, PHP_INI_ALL, NULL) @@ -563,11 +581,17 @@ static zend_object_value date_object_clone_interval(zv 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 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_gc_period(zval *object, zval ***table, int *n 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 void date_period_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC); /* {{{ Module struct */ zend_module_entry date_module_entry = { @@ -597,6 +621,7 @@ static PHP_GINIT_FUNCTION(date) date_globals->default_timezone = NULL; date_globals->timezone = NULL; date_globals->tzcache = NULL; + date_globals->timezone_valid = 0; } /* }}} */ @@ -842,25 +867,54 @@ timelib_tzinfo *php_date_parse_tzfile_wrapper(char *fo } /* }}} */ +/* Callback to check the date.timezone only when changed increases performance */ +/* {{{ static PHP_INI_MH(OnUpdate_date_timezone) */ +static PHP_INI_MH(OnUpdate_date_timezone) +{ + if (OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC) == FAILURE) { + return FAILURE; + } + + DATEG(timezone_valid) = 0; + if (stage == PHP_INI_STAGE_RUNTIME) { + if (!timelib_timezone_id_is_valid(DATEG(default_timezone), DATE_TIMEZONEDB)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, DATE_TZ_ERRMSG); + } else { + DATEG(timezone_valid) = 1; + } + } + + return SUCCESS; +} +/* }}} */ + /* {{{ Helper functions */ static char* guess_timezone(const timelib_tzdb *tzdb TSRMLS_DC) { /* Checking configure timezone */ - if (DATEG(timezone) && (strlen(DATEG(timezone)) > 0)) { + if (DATEG(timezone) && (strlen(DATEG(timezone))) > 0) { return DATEG(timezone); } /* Check config setting for default timezone */ if (!DATEG(default_timezone)) { /* Special case: ext/date wasn't initialized yet */ zval ztz; - - if (SUCCESS == zend_get_configuration_directive("date.timezone", sizeof("date.timezone"), &ztz) && - Z_TYPE(ztz) == IS_STRING && - Z_STRLEN(ztz) > 0 && - timelib_timezone_id_is_valid(Z_STRVAL(ztz), tzdb)) { + + if (SUCCESS == zend_get_configuration_directive("date.timezone", sizeof("date.timezone"), &ztz) + && Z_TYPE(ztz) == IS_STRING && Z_STRLEN(ztz) > 0 && timelib_timezone_id_is_valid(Z_STRVAL(ztz), tzdb)) { return Z_STRVAL(ztz); } - } else if (*DATEG(default_timezone) && timelib_timezone_id_is_valid(DATEG(default_timezone), tzdb)) { + } else if (*DATEG(default_timezone)) { + if (DATEG(timezone_valid) == 1) { + return DATEG(default_timezone); + } + + if (!timelib_timezone_id_is_valid(DATEG(default_timezone), tzdb)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid date.timezone value '%s', we selected the timezone 'UTC' for now.", DATEG(default_timezone)); + return "UTC"; + } + + DATEG(timezone_valid) = 1; return DATEG(default_timezone); } /* Fallback to UTC */ @@ -948,6 +1002,7 @@ static char *date_format(char *format, int format_len, timelib_time_offset *offset = NULL; timelib_sll isoweek, isoyear; int rfc_colon; + int weekYearSet = 0; if (!format_len) { return estrdup(""); @@ -974,7 +1029,6 @@ static char *date_format(char *format, int format_len, offset = timelib_get_time_zone_info(t->sse, t->tz_info); } } - timelib_isoweek_from_date(t->y, t->m, t->d, &isoweek, &isoyear); for (i = 0; i < format_len; i++) { rfc_colon = 0; @@ -990,8 +1044,12 @@ static char *date_format(char *format, int format_len, case 'z': length = slprintf(buffer, 32, "%d", (int) timelib_day_of_year(t->y, t->m, t->d)); break; /* week */ - case 'W': length = slprintf(buffer, 32, "%02d", (int) isoweek); break; /* iso weeknr */ - case 'o': length = slprintf(buffer, 32, "%d", (int) isoyear); break; /* iso year */ + case 'W': + if(!weekYearSet) { timelib_isoweek_from_date(t->y, t->m, t->d, &isoweek, &isoyear); weekYearSet = 1; } + length = slprintf(buffer, 32, "%02d", (int) isoweek); break; /* iso weeknr */ + case 'o': + if(!weekYearSet) { timelib_isoweek_from_date(t->y, t->m, t->d, &isoweek, &isoyear); weekYearSet = 1; } + length = slprintf(buffer, 32, "%d", (int) isoyear); break; /* iso year */ /* month */ case 'F': length = slprintf(buffer, 32, "%s", mon_full_names[t->m - 1]); break; @@ -1023,7 +1081,7 @@ static char *date_format(char *format, int format_len, case 'H': length = slprintf(buffer, 32, "%02d", (int) t->h); break; case 'i': length = slprintf(buffer, 32, "%02d", (int) t->i); break; case 's': length = slprintf(buffer, 32, "%02d", (int) t->s); break; - case 'u': length = slprintf(buffer, 32, "%06d", (int) floor(t->f * 1000000)); break; + case 'u': length = slprintf(buffer, 32, "%06d", (int) floor(t->f * 1000000 + 0.5)); break; /* timezone */ case 'I': length = slprintf(buffer, 32, "%d", localtime ? offset->is_dst : 0); break; @@ -1883,6 +1941,7 @@ static void date_register_classes(TSRMLS_D) 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; + date_object_handlers_date.get_gc = date_object_get_gc; #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); @@ -1933,6 +1992,7 @@ static void date_register_classes(TSRMLS_D) date_object_handlers_interval.write_property = date_interval_write_property; date_object_handlers_interval.get_properties = date_object_get_properties_interval; date_object_handlers_interval.get_property_ptr_ptr = NULL; + date_object_handlers_interval.get_gc = date_object_get_gc_interval; INIT_CLASS_ENTRY(ce_period, "DatePeriod", date_funcs_period); ce_period.create_object = date_object_new_period; @@ -1942,6 +2002,11 @@ 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.get_property_ptr_ptr = NULL; + date_object_handlers_period.get_gc = date_object_get_gc_period; + date_object_handlers_period.read_property = date_period_read_property; + 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); @@ -2005,7 +2070,11 @@ static int date_object_compare_date(zval *d1, zval *d2 instanceof_function(Z_OBJCE_P(d2), date_ce_date TSRMLS_CC)) { php_date_obj *o1 = zend_object_store_get_object(d1 TSRMLS_CC); php_date_obj *o2 = zend_object_store_get_object(d2 TSRMLS_CC); - + + if (!o1->time || !o2->time) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Trying to compare an incomplete DateTime object"); + return 1; + } if (!o1->time->sse_uptodate) { timelib_update_ts(o1->time, o1->time->tz_info); } @@ -2019,6 +2088,13 @@ static int date_object_compare_date(zval *d1, zval *d2 return 1; } +static HashTable *date_object_get_gc(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; @@ -2164,24 +2240,31 @@ static zend_object_value date_object_clone_interval(zv return new_ov; } +static HashTable *date_object_get_gc_interval(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_interval(zval *object TSRMLS_DC) { HashTable *props; zval *zv; php_interval_obj *intervalobj; - intervalobj = (php_interval_obj *) zend_object_store_get_object(object TSRMLS_CC); props = zend_std_get_properties(object TSRMLS_CC); - if (!intervalobj->initialized || GC_G(gc_active)) { + if (!intervalobj->initialized) { return props; } #define PHP_DATE_INTERVAL_ADD_PROPERTY(n,f) \ MAKE_STD_ZVAL(zv); \ - ZVAL_LONG(zv, intervalobj->diff->f); \ + ZVAL_LONG(zv, (long)intervalobj->diff->f); \ zend_hash_update(props, n, strlen(n) + 1, &zv, sizeof(zval), NULL); PHP_DATE_INTERVAL_ADD_PROPERTY("y", y); @@ -2190,6 +2273,9 @@ static HashTable *date_object_get_properties_interval( PHP_DATE_INTERVAL_ADD_PROPERTY("h", h); PHP_DATE_INTERVAL_ADD_PROPERTY("i", i); PHP_DATE_INTERVAL_ADD_PROPERTY("s", s); + PHP_DATE_INTERVAL_ADD_PROPERTY("weekday", weekday); + PHP_DATE_INTERVAL_ADD_PROPERTY("weekday_behavior", weekday_behavior); + PHP_DATE_INTERVAL_ADD_PROPERTY("first_last_day_of", first_last_day_of); PHP_DATE_INTERVAL_ADD_PROPERTY("invert", invert); if (intervalobj->diff->days != -99999) { PHP_DATE_INTERVAL_ADD_PROPERTY("days", days); @@ -2198,6 +2284,10 @@ static HashTable *date_object_get_properties_interval( ZVAL_FALSE(zv); zend_hash_update(props, "days", 5, &zv, sizeof(zval), NULL); } + PHP_DATE_INTERVAL_ADD_PROPERTY("special_type", special.type); + PHP_DATE_INTERVAL_ADD_PROPERTY("special_amount", special.amount); + PHP_DATE_INTERVAL_ADD_PROPERTY("have_weekday_relative", have_weekday_relative); + PHP_DATE_INTERVAL_ADD_PROPERTY("have_special_relative", have_special_relative); return props; } @@ -2299,6 +2389,7 @@ PHPAPI zval *php_date_instantiate(zend_class_entry *pc object_init_ex(object, pce); Z_SET_REFCOUNT_P(object, 1); Z_UNSET_ISREF_P(object); + return object; } @@ -2473,13 +2564,15 @@ static int php_date_initialize_from_hash(zval **return case TIMELIB_ZONETYPE_OFFSET: case TIMELIB_ZONETYPE_ABBR: { char *tmp = emalloc(Z_STRLEN_PP(z_date) + Z_STRLEN_PP(z_timezone) + 2); + int ret; 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); + ret = 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; + return 1 == ret; } - case TIMELIB_ZONETYPE_ID: + case TIMELIB_ZONETYPE_ID: { + int ret; convert_to_string(*z_timezone); tzi = php_date_parse_tzfile(Z_STRVAL_PP(z_timezone), DATE_TIMEZONEDB TSRMLS_CC); @@ -2490,9 +2583,10 @@ static int php_date_initialize_from_hash(zval **return 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); + ret = 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; + return 1 == ret; + } } } } @@ -2516,7 +2610,9 @@ 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); + if (!php_date_initialize_from_hash(&return_value, &dateobj, myht TSRMLS_CC)) { + php_error(E_ERROR, "Invalid serialization data for DateTime object"); + } } /* }}} */ @@ -2532,7 +2628,9 @@ PHP_METHOD(DateTime, __wakeup) myht = Z_OBJPROP_P(object); - php_date_initialize_from_hash(&return_value, &dateobj, myht TSRMLS_CC); + if (!php_date_initialize_from_hash(&return_value, &dateobj, myht TSRMLS_CC)) { + php_error(E_ERROR, "Invalid serialization data for DateTime object"); + } } /* }}} */ @@ -3430,10 +3528,19 @@ zval *date_interval_read_property(zval *object, zval * zval_copy_ctor(&tmp_member); convert_to_string(&tmp_member); member = &tmp_member; + key = NULL; } obj = (php_interval_obj *)zend_objects_get_address(object TSRMLS_CC); + if (!obj->initialized) { + retval = (zend_get_std_object_handlers())->read_property(object, member, type, key TSRMLS_CC); + if (member == &tmp_member) { + zval_dtor(member); + } + return retval; + } + #define GET_VALUE_FROM_STRUCT(n,m) \ if (strcmp(Z_STRVAL_P(member), m) == 0) { \ value = obj->diff->n; \ @@ -3482,9 +3589,19 @@ void date_interval_write_property(zval *object, zval * zval_copy_ctor(&tmp_member); convert_to_string(&tmp_member); member = &tmp_member; + key = NULL; } + obj = (php_interval_obj *)zend_objects_get_address(object TSRMLS_CC); + if (!obj->initialized) { + (zend_get_std_object_handlers())->write_property(object, member, value, key TSRMLS_CC); + if (member == &tmp_member) { + zval_dtor(member); + } + return; + } + #define SET_VALUE_FROM_STRUCT(n,m) \ if (strcmp(Z_STRVAL_P(member), m) == 0) { \ if (value->type != IS_LONG) { \ @@ -3544,30 +3661,48 @@ PHP_METHOD(DateInterval, __construct) } /* }}} */ -static long php_date_long_from_hash_element(HashTable *myht, char *element, size_t size) -{ - zval **z_arg = NULL; - if (zend_hash_find(myht, element, size + 1, (void**) &z_arg) == SUCCESS) { - convert_to_long(*z_arg); - return Z_LVAL_PP(z_arg); - } else { - return -1; - } -} - static int php_date_interval_initialize_from_hash(zval **return_value, php_interval_obj **intobj, HashTable *myht TSRMLS_DC) { (*intobj)->diff = timelib_rel_time_ctor(); - (*intobj)->diff->y = php_date_long_from_hash_element(myht, "y", 1); - (*intobj)->diff->m = php_date_long_from_hash_element(myht, "m", 1); - (*intobj)->diff->d = php_date_long_from_hash_element(myht, "d", 1); - (*intobj)->diff->h = php_date_long_from_hash_element(myht, "h", 1); - (*intobj)->diff->i = php_date_long_from_hash_element(myht, "i", 1); - (*intobj)->diff->s = php_date_long_from_hash_element(myht, "s", 1); - (*intobj)->diff->invert = php_date_long_from_hash_element(myht, "invert", 6); - (*intobj)->diff->days = php_date_long_from_hash_element(myht, "days", 4); +#define PHP_DATE_INTERVAL_READ_PROPERTY(element, member, itype, def) \ + do { \ + zval **z_arg = NULL; \ + if (zend_hash_find(myht, element, strlen(element) + 1, (void**) &z_arg) == SUCCESS) { \ + convert_to_long(*z_arg); \ + (*intobj)->diff->member = (itype)Z_LVAL_PP(z_arg); \ + } else { \ + (*intobj)->diff->member = (itype)def; \ + } \ + } while (0); + +#define PHP_DATE_INTERVAL_READ_PROPERTY_I64(element, member) \ + do { \ + zval **z_arg = NULL; \ + if (zend_hash_find(myht, element, strlen(element) + 1, (void**) &z_arg) == SUCCESS) { \ + convert_to_string(*z_arg); \ + DATE_A64I((*intobj)->diff->member, Z_STRVAL_PP(z_arg)); \ + } else { \ + (*intobj)->diff->member = -1LL; \ + } \ + } while (0); + + PHP_DATE_INTERVAL_READ_PROPERTY("y", y, timelib_sll, -1) + PHP_DATE_INTERVAL_READ_PROPERTY("m", m, timelib_sll, -1) + PHP_DATE_INTERVAL_READ_PROPERTY("d", d, timelib_sll, -1) + PHP_DATE_INTERVAL_READ_PROPERTY("h", h, timelib_sll, -1) + PHP_DATE_INTERVAL_READ_PROPERTY("i", i, timelib_sll, -1) + PHP_DATE_INTERVAL_READ_PROPERTY("s", s, timelib_sll, -1) + PHP_DATE_INTERVAL_READ_PROPERTY("weekday", weekday, int, -1) + PHP_DATE_INTERVAL_READ_PROPERTY("weekday_behavior", weekday_behavior, int, -1) + PHP_DATE_INTERVAL_READ_PROPERTY("first_last_day_of", first_last_day_of, int, -1) + PHP_DATE_INTERVAL_READ_PROPERTY("invert", invert, int, 0); + PHP_DATE_INTERVAL_READ_PROPERTY_I64("days", days); + PHP_DATE_INTERVAL_READ_PROPERTY("special_type", special.type, unsigned int, 0); + PHP_DATE_INTERVAL_READ_PROPERTY_I64("special_amount", special.amount); + PHP_DATE_INTERVAL_READ_PROPERTY("have_weekday_relative", have_weekday_relative, unsigned int, 0); + PHP_DATE_INTERVAL_READ_PROPERTY("have_special_relative", have_special_relative, unsigned int, 0); (*intobj)->initialized = 1; return 0; @@ -4171,6 +4306,229 @@ PHP_FUNCTION(date_sun_info) timelib_time_dtor(t2); } /* }}} */ + +static HashTable *date_object_get_gc_period(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_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 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"); + } +} +/* }}} */ + +/* {{{ 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_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"); +} +/* }}} */ + + /* * Local variables: * tab-width: 4