1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

Fix GH-10152: Custom properties of Date's child classes are not serialised

This commit is contained in:
Derick Rethans
2023-01-25 17:40:28 +00:00
parent f732486c08
commit 85fbc6eaa6
14 changed files with 288 additions and 23 deletions

View File

@@ -2254,6 +2254,19 @@ static void date_object_free_storage_period(zend_object *object) /* {{{ */
zend_object_std_dtor(&intern->std);
} /* }}} */
static void add_common_properties(HashTable *myht, zend_object *zobj)
{
HashTable *common;
zend_string *name;
zval *prop;
common = zend_std_get_properties(zobj);
ZEND_HASH_MAP_FOREACH_STR_KEY_VAL_IND(common, name, prop) {
zend_hash_add(myht, name, prop);
} ZEND_HASH_FOREACH_END();
}
/* Advanced Interface */
PHPAPI zval *php_date_instantiate(zend_class_entry *pce, zval *object) /* {{{ */
{
@@ -2733,6 +2746,8 @@ PHP_METHOD(DateTime, __serialize)
array_init(return_value);
myht = Z_ARRVAL_P(return_value);
date_object_to_hash(dateobj, myht);
add_common_properties(myht, &dateobj->std);
}
/* }}} */
@@ -2751,9 +2766,36 @@ PHP_METHOD(DateTimeImmutable, __serialize)
array_init(return_value);
myht = Z_ARRVAL_P(return_value);
date_object_to_hash(dateobj, myht);
add_common_properties(myht, &dateobj->std);
}
/* }}} */
static bool date_time_is_internal_property(zend_string *name)
{
if (
zend_string_equals_literal(name, "date") ||
zend_string_equals_literal(name, "timezone_type") ||
zend_string_equals_literal(name, "timezone")
) {
return 1;
}
return 0;
}
static void restore_custom_datetime_properties(zval *object, HashTable *myht)
{
zend_string *prop_name;
zval *prop_val;
ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(myht, prop_name, prop_val) {
if (date_time_is_internal_property(prop_name)) {
continue;
}
add_property_zval_ex(object, ZSTR_VAL(prop_name), ZSTR_LEN(prop_name), prop_val);
} ZEND_HASH_FOREACH_END();
}
/* {{{ */
PHP_METHOD(DateTime, __unserialize)
{
@@ -2772,6 +2814,8 @@ PHP_METHOD(DateTime, __unserialize)
if (!php_date_initialize_from_hash(&dateobj, myht)) {
zend_throw_error(NULL, "Invalid serialization data for DateTime object");
}
restore_custom_datetime_properties(object, myht);
}
/* }}} */
@@ -2793,6 +2837,8 @@ PHP_METHOD(DateTimeImmutable, __unserialize)
if (!php_date_initialize_from_hash(&dateobj, myht)) {
zend_throw_error(NULL, "Invalid serialization data for DateTimeImmutable object");
}
restore_custom_datetime_properties(object, myht);
}
/* }}} */
@@ -3753,9 +3799,35 @@ PHP_METHOD(DateTimeZone, __serialize)
array_init(return_value);
myht = Z_ARRVAL_P(return_value);
date_timezone_object_to_hash(tzobj, myht);
add_common_properties(myht, &tzobj->std);
}
/* }}} */
static bool date_timezone_is_internal_property(zend_string *name)
{
if (
zend_string_equals_literal(name, "timezone_type") ||
zend_string_equals_literal(name, "timezone")
) {
return 1;
}
return 0;
}
static void restore_custom_datetimezone_properties(zval *object, HashTable *myht)
{
zend_string *prop_name;
zval *prop_val;
ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(myht, prop_name, prop_val) {
if (date_timezone_is_internal_property(prop_name)) {
continue;
}
add_property_zval_ex(object, ZSTR_VAL(prop_name), ZSTR_LEN(prop_name), prop_val);
} ZEND_HASH_FOREACH_END();
}
/* {{{ */
PHP_METHOD(DateTimeZone, __unserialize)
{
@@ -3774,6 +3846,8 @@ PHP_METHOD(DateTimeZone, __unserialize)
if (!php_date_timezone_initialize_from_hash(&object, &tzobj, myht)) {
zend_throw_error(NULL, "Invalid serialization data for DateTimeZone object");
}
restore_custom_datetimezone_properties(object, myht);
}
/* }}} */
@@ -4344,9 +4418,44 @@ PHP_METHOD(DateInterval, __serialize)
array_init(return_value);
myht = Z_ARRVAL_P(return_value);
date_interval_object_to_hash(intervalobj, myht);
add_common_properties(myht, &intervalobj->std);
}
/* }}} */
static bool date_interval_is_internal_property(zend_string *name)
{
if (
zend_string_equals_literal(name, "date_string") ||
zend_string_equals_literal(name, "from_string") ||
zend_string_equals_literal(name, "y") ||
zend_string_equals_literal(name, "m") ||
zend_string_equals_literal(name, "d") ||
zend_string_equals_literal(name, "h") ||
zend_string_equals_literal(name, "i") ||
zend_string_equals_literal(name, "s") ||
zend_string_equals_literal(name, "f") ||
zend_string_equals_literal(name, "invert") ||
zend_string_equals_literal(name, "days")
) {
return 1;
}
return 0;
}
static void restore_custom_dateinterval_properties(zval *object, HashTable *myht)
{
zend_string *prop_name;
zval *prop_val;
ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(myht, prop_name, prop_val) {
if (date_interval_is_internal_property(prop_name)) {
continue;
}
add_property_zval_ex(object, ZSTR_VAL(prop_name), ZSTR_LEN(prop_name), prop_val);
} ZEND_HASH_FOREACH_END();
}
/* {{{ */
PHP_METHOD(DateInterval, __unserialize)
@@ -4364,6 +4473,7 @@ PHP_METHOD(DateInterval, __unserialize)
myht = Z_ARRVAL_P(array);
php_date_interval_initialize_from_hash(&object, &intervalobj, myht);
restore_custom_dateinterval_properties(object, myht);
}
/* }}} */
@@ -5269,9 +5379,44 @@ PHP_METHOD(DatePeriod, __serialize)
array_init(return_value);
myht = Z_ARRVAL_P(return_value);
date_period_object_to_hash(period_obj, myht);
add_common_properties(myht, &period_obj->std);
}
/* }}} */
/* {{{ date_period_is_internal_property
* Common for date_period_read_property(), date_period_write_property(), and
* restore_custom_dateperiod_properties functions
*/
static bool date_period_is_internal_property(zend_string *name)
{
if (
zend_string_equals_literal(name, "start") ||
zend_string_equals_literal(name, "current") ||
zend_string_equals_literal(name, "end") ||
zend_string_equals_literal(name, "interval") ||
zend_string_equals_literal(name, "recurrences") ||
zend_string_equals_literal(name, "include_start_date") ||
zend_string_equals_literal(name, "include_end_date")
) {
return 1;
}
return 0;
}
/* }}} */
static void restore_custom_dateperiod_properties(zval *object, HashTable *myht)
{
zend_string *prop_name;
zval *prop_val;
ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(myht, prop_name, prop_val) {
if (date_period_is_internal_property(prop_name)) {
continue;
}
add_property_zval_ex(object, ZSTR_VAL(prop_name), ZSTR_LEN(prop_name), prop_val);
} ZEND_HASH_FOREACH_END();
}
/* {{{ */
PHP_METHOD(DatePeriod, __unserialize)
@@ -5291,6 +5436,7 @@ PHP_METHOD(DatePeriod, __unserialize)
if (!php_date_period_initialize_from_hash(period_obj, myht)) {
zend_throw_error(NULL, "Invalid serialization data for DatePeriod object");
}
restore_custom_dateperiod_properties(object, myht);
}
/* }}} */
@@ -5313,25 +5459,6 @@ PHP_METHOD(DatePeriod, __wakeup)
}
/* }}} */
/* {{{ date_period_is_internal_property
* Common for date_period_read_property() and date_period_write_property() functions
*/
static bool date_period_is_internal_property(zend_string *name)
{
if (zend_string_equals_literal(name, "recurrences")
|| zend_string_equals_literal(name, "include_start_date")
|| zend_string_equals_literal(name, "include_end_date")
|| zend_string_equals_literal(name, "start")
|| zend_string_equals_literal(name, "current")
|| zend_string_equals_literal(name, "end")
|| zend_string_equals_literal(name, "interval")
) {
return 1;
}
return 0;
}
/* }}} */
/* {{{ date_period_read_property */
static zval *date_period_read_property(zend_object *object, zend_string *name, int type, void **cache_slot, zval *rv)
{

View File

@@ -0,0 +1,23 @@
--TEST--
Inherited DateTimeImmutable serialisation with custom properties
--FILE--
<?php
date_default_timezone_set("Europe/London");
class MyDateTimeImmutable extends DateTimeImmutable
{
public function __construct(
string $datetime = "now",
?DateTimeZone $timezone = null,
public ?bool $myProperty = null,
) {
parent::__construct($datetime, $timezone);
}
}
$d = new MyDateTimeImmutable("2023-01-25 16:32:55", myProperty: true);
$e = unserialize(serialize($d));
var_dump($e->myProperty);
?>
--EXPECTF--
bool(true)

View File

@@ -0,0 +1,22 @@
--TEST--
Inherited DateTimeInterval serialisation with custom properties
--FILE--
<?php
date_default_timezone_set("Europe/London");
class MyDateInterval extends DateInterval
{
public function __construct(
string $duration,
public ?bool $myProperty = null,
) {
parent::__construct($duration);
}
}
$d = new MyDateInterval("P1W2D", myProperty: true);
$e = unserialize(serialize($d));
var_dump($e->myProperty);
?>
--EXPECTF--
bool(true)

View File

@@ -0,0 +1,25 @@
--TEST--
Inherited DateTimePeriod serialisation with custom properties
--FILE--
<?php
date_default_timezone_set("Europe/London");
class MyDatePeriod extends DatePeriod
{
public function __construct(
DateTimeInterface $start,
DateInterval $interval,
int $recurrences,
int $options = 0,
public ?bool $myProperty = null,
) {
parent::__construct($start, $interval, $recurrences, $options);
}
}
$d = new MyDatePeriod(new DateTimeImmutable(), new DateInterval("PT5S"), 5, myProperty: true);
$e = unserialize(serialize($d));
var_dump($e->myProperty);
?>
--EXPECTF--
bool(true)

View File

@@ -0,0 +1,22 @@
--TEST--
Inherited DateTimeZone serialisation with custom properties
--FILE--
<?php
date_default_timezone_set("Europe/London");
class MyDateTimeZone extends DateTimeZone
{
public function __construct(
string $timezone = "Europe/Kyiv",
public ?bool $myProperty = null,
) {
parent::__construct($timezone);
}
}
$d = new MyDateTimeZone("Europe/London", myProperty: true);
$e = unserialize(serialize($d));
var_dump($e->myProperty);
?>
--EXPECTF--
bool(true)

View File

@@ -0,0 +1,23 @@
--TEST--
Inherited DateTime serialisation with custom properties
--FILE--
<?php
date_default_timezone_set("Europe/London");
class MyDateTime extends DateTime
{
public function __construct(
string $datetime = "now",
?DateTimeZone $timezone = null,
public ?bool $myProperty = null,
) {
parent::__construct($datetime, $timezone);
}
}
$d = new MyDateTime("2023-01-25 16:32:55", myProperty: true);
$e = unserialize(serialize($d));
var_dump($e->myProperty);
?>
--EXPECTF--
bool(true)

View File

@@ -4,7 +4,7 @@ Bug #53437 DateInterval unserialize bad data, 32 bit
<?php if (PHP_INT_SIZE != 4) { die('skip 32 bit only'); } ?>
--FILE--
<?php
$s = 'O:12:"DateInterval":15:{s:1:"y";s:1:"2";s:1:"m";s:1:"0";s:1:"d";s:3:"bla";s:1:"h";s:1:"6";s:1:"i";s:1:"8";s:1:"s";s:1:"0";s:7:"weekday";i:10;s:16:"weekday_behavior";i:10;s:17:"first_last_day_of";i:0;s:6:"invert";i:0;s:4:"days";s:4:"aoeu";s:12:"special_type";i:0;s:14:"special_amount";s:21:"234523452345234532455";s:21:"have_weekday_relative";i:21474836489;s:21:"have_special_relative";s:3:"bla";}';
$s = 'O:12:"DateInterval":8:{s:1:"y";s:1:"2";s:1:"m";s:1:"0";s:1:"d";s:3:"bla";s:1:"h";s:1:"6";s:1:"i";s:1:"8";s:1:"s";s:1:"0";s:6:"invert";i:0;s:4:"days";s:4:"aoeu";}';
$di = unserialize($s);
var_dump($di);

View File

@@ -4,7 +4,7 @@ Bug #53437 (DateInterval unserialize bad data, 64 bit)
<?php if (PHP_INT_SIZE != 8) { die('skip true 64 bit only'); } ?>
--FILE--
<?php
$s = 'O:12:"DateInterval":15:{s:1:"y";s:1:"2";s:1:"m";s:1:"0";s:1:"d";s:3:"bla";s:1:"h";s:1:"6";s:1:"i";s:1:"8";s:1:"s";s:1:"0";s:7:"weekday";i:10;s:16:"weekday_behavior";i:10;s:17:"first_last_day_of";i:0;s:6:"invert";i:0;s:4:"days";s:4:"aoeu";s:12:"special_type";i:0;s:14:"special_amount";s:21:"234523452345234532455";s:21:"have_weekday_relative";i:21474836489;s:21:"have_special_relative";s:3:"bla";}';
$s = 'O:12:"DateInterval":8:{s:1:"y";s:1:"2";s:1:"m";s:1:"0";s:1:"d";s:3:"bla";s:1:"h";s:1:"6";s:1:"i";s:1:"8";s:1:"s";s:1:"0";s:6:"invert";i:0;s:4:"days";s:4:"aoeu";}';
$di = unserialize($s);
var_dump($di);

View File

@@ -4,7 +4,7 @@ Bug #53437 (DateInterval unserialize bad data, 64 bit)
<?php if (PHP_INT_SIZE != 8) { die('skip true 64 bit only'); } ?>
--FILE--
<?php
$s = 'O:12:"DateInterval":16:{s:1:"y";s:1:"2";s:1:"m";s:1:"0";s:1:"d";s:3:"bla";s:1:"h";s:1:"6";s:1:"i";s:1:"8";s:1:"s";s:1:"0";s:1:"f";d:0.123654;s:7:"weekday";i:10;s:16:"weekday_behavior";i:10;s:17:"first_last_day_of";i:0;s:6:"invert";i:0;s:4:"days";s:4:"aoeu";s:12:"special_type";i:0;s:14:"special_amount";s:21:"234523452345234532455";s:21:"have_weekday_relative";i:21474836489;s:21:"have_special_relative";s:3:"bla";}';
$s = 'O:12:"DateInterval":9:{s:1:"y";s:1:"2";s:1:"m";s:1:"0";s:1:"d";s:3:"bla";s:1:"h";s:1:"6";s:1:"i";s:1:"8";s:1:"s";s:1:"0";s:1:"f";d:0.123654;s:6:"invert";i:0;s:4:"days";s:4:"aoeu";}';
$di = unserialize($s);
var_dump($di);

View File

@@ -2,7 +2,7 @@
Bug #79015 (undefined-behavior in php_date.c)
--FILE--
<?php
$payload = 'O:12:"DateInterval":16:{s:1:"y";i:1;s:1:"m";i:0;s:1:"d";i:4;s:1:"h";i:0;s:1:"i";i:0;s:1:"s";i:0;s:1:"f";i:9999999999990;s:7:"weekday";i:0;s:16:"weekday_behavior";i:0;s:17:"first_last_day_of";i:0;s:6:"invert";i:0;s:4:"days";b:0;s:12:"special_type";i:0;s:14:"special_amount";i:0;s:21:"have_weekday_relative";i:0;s:21:"have_special_relative";i:0;}';
$payload = 'O:12:"DateInterval":9:{s:1:"y";i:1;s:1:"m";i:0;s:1:"d";i:4;s:1:"h";i:0;s:1:"i";i:0;s:1:"s";i:0;s:1:"f";i:9999999999990;s:6:"invert";i:0;s:4:"days";b:0;}';
var_dump(unserialize($payload));
?>
--EXPECTF--

View File

@@ -0,0 +1,23 @@
--TEST--
GH-10152: Custom properties of DateTimeImmutable child classes are not serialized
--FILE--
<?php
class MyDateTimeImmutable extends DateTimeImmutable {
public function __construct(
string $datetime = "now",
?DateTimeZone $timezone = null,
public ?bool $myProperty = null,
) {
parent::__construct($datetime, $timezone);
}
}
$datetime = new MyDateTimeImmutable('2022-12-22T11:26:00Z', myProperty: true);
$serialized = serialize($datetime);
$unserialized = unserialize($serialized);
var_dump($unserialized->myProperty);
?>
--EXPECT--
bool(true)