|
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.net
diff --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-2025 The PHP GroupAll rights reserved. |
Last updated: Sat Oct 25 14:00:01 2025 UTC |