Add DateTimeZone's __serialize and __unserialize methods

This commit is contained in:
Derick Rethans 2022-04-14 16:52:22 +01:00
parent 8b2ee5388c
commit 181623f9c0
6 changed files with 151 additions and 21 deletions

View file

@ -1969,10 +1969,20 @@ static void php_timezone_to_string(php_timezone_obj *tzobj, zval *zv)
} }
} }
void date_timezone_object_to_hash(php_timezone_obj *tzobj, HashTable *props)
{
zval zv;
ZVAL_LONG(&zv, tzobj->type);
zend_hash_str_update(props, "timezone_type", strlen("timezone_type"), &zv);
php_timezone_to_string(tzobj, &zv);
zend_hash_str_update(props, "timezone", strlen("timezone"), &zv);
}
static HashTable *date_object_get_properties_for_timezone(zend_object *object, zend_prop_purpose purpose) /* {{{ */ static HashTable *date_object_get_properties_for_timezone(zend_object *object, zend_prop_purpose purpose) /* {{{ */
{ {
HashTable *props; HashTable *props;
zval zv;
php_timezone_obj *tzobj; php_timezone_obj *tzobj;
switch (purpose) { switch (purpose) {
@ -1992,11 +2002,7 @@ static HashTable *date_object_get_properties_for_timezone(zend_object *object, z
return props; return props;
} }
ZVAL_LONG(&zv, tzobj->type); date_timezone_object_to_hash(tzobj, props);
zend_hash_str_update(props, "timezone_type", sizeof("timezone_type")-1, &zv);
php_timezone_to_string(tzobj, &zv);
zend_hash_str_update(props, "timezone", sizeof("timezone")-1, &zv);
return props; return props;
} /* }}} */ } /* }}} */
@ -3500,7 +3506,7 @@ PHP_FUNCTION(date_diff)
} }
/* }}} */ /* }}} */
static zend_result timezone_initialize(php_timezone_obj *tzobj, const char *tz, size_t tz_len) /* {{{ */ static bool timezone_initialize(php_timezone_obj *tzobj, const char *tz, size_t tz_len) /* {{{ */
{ {
timelib_time *dummy_t = ecalloc(1, sizeof(timelib_time)); timelib_time *dummy_t = ecalloc(1, sizeof(timelib_time));
int dst, not_found; int dst, not_found;
@ -3509,19 +3515,19 @@ static zend_result timezone_initialize(php_timezone_obj *tzobj, const char *tz,
if (strlen(tz) != tz_len) { if (strlen(tz) != tz_len) {
php_error_docref(NULL, E_WARNING, "Timezone must not contain null bytes"); php_error_docref(NULL, E_WARNING, "Timezone must not contain null bytes");
efree(dummy_t); efree(dummy_t);
return FAILURE; return false;
} }
dummy_t->z = timelib_parse_zone(&tz, &dst, dummy_t, &not_found, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper); dummy_t->z = timelib_parse_zone(&tz, &dst, dummy_t, &not_found, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper);
if (not_found) { if (not_found) {
php_error_docref(NULL, E_WARNING, "Unknown or bad timezone (%s)", orig_tz); php_error_docref(NULL, E_WARNING, "Unknown or bad timezone (%s)", orig_tz);
efree(dummy_t); efree(dummy_t);
return FAILURE; return false;
} else { } else {
set_timezone_from_timelib_time(tzobj, dummy_t); set_timezone_from_timelib_time(tzobj, dummy_t);
timelib_free(dummy_t->tz_abbr); timelib_free(dummy_t->tz_abbr);
efree(dummy_t); efree(dummy_t);
return SUCCESS; return true;
} }
} /* }}} */ } /* }}} */
@ -3536,7 +3542,7 @@ PHP_FUNCTION(timezone_open)
ZEND_PARSE_PARAMETERS_END(); ZEND_PARSE_PARAMETERS_END();
tzobj = Z_PHPTIMEZONE_P(php_date_instantiate(date_ce_timezone, return_value)); tzobj = Z_PHPTIMEZONE_P(php_date_instantiate(date_ce_timezone, return_value));
if (FAILURE == timezone_initialize(tzobj, ZSTR_VAL(tz), ZSTR_LEN(tz))) { if (!timezone_initialize(tzobj, ZSTR_VAL(tz), ZSTR_LEN(tz))) {
zval_ptr_dtor(return_value); zval_ptr_dtor(return_value);
RETURN_FALSE; RETURN_FALSE;
} }
@ -3561,25 +3567,25 @@ PHP_METHOD(DateTimeZone, __construct)
} }
/* }}} */ /* }}} */
static zend_result php_date_timezone_initialize_from_hash(zval **return_value, php_timezone_obj **tzobj, HashTable *myht) /* {{{ */ static bool php_date_timezone_initialize_from_hash(zval **return_value, php_timezone_obj **tzobj, HashTable *myht) /* {{{ */
{ {
zval *z_timezone_type; zval *z_timezone_type;
if ((z_timezone_type = zend_hash_str_find(myht, "timezone_type", sizeof("timezone_type") - 1)) == NULL) { if ((z_timezone_type = zend_hash_str_find(myht, "timezone_type", sizeof("timezone_type") - 1)) == NULL) {
return FAILURE; return false;
} }
zval *z_timezone; zval *z_timezone;
if ((z_timezone = zend_hash_str_find(myht, "timezone", sizeof("timezone") - 1)) == NULL) { if ((z_timezone = zend_hash_str_find(myht, "timezone", sizeof("timezone") - 1)) == NULL) {
return FAILURE; return false;
} }
if (Z_TYPE_P(z_timezone_type) != IS_LONG) { if (Z_TYPE_P(z_timezone_type) != IS_LONG) {
return FAILURE; return false;
} }
if (Z_TYPE_P(z_timezone) != IS_STRING) { if (Z_TYPE_P(z_timezone) != IS_STRING) {
return FAILURE; return false;
} }
return timezone_initialize(*tzobj, Z_STRVAL_P(z_timezone), Z_STRLEN_P(z_timezone)); return timezone_initialize(*tzobj, Z_STRVAL_P(z_timezone), Z_STRLEN_P(z_timezone));
} /* }}} */ } /* }}} */
@ -3599,7 +3605,7 @@ PHP_METHOD(DateTimeZone, __set_state)
php_date_instantiate(date_ce_timezone, return_value); php_date_instantiate(date_ce_timezone, return_value);
tzobj = Z_PHPTIMEZONE_P(return_value); tzobj = Z_PHPTIMEZONE_P(return_value);
if (php_date_timezone_initialize_from_hash(&return_value, &tzobj, myht) == FAILURE) { if (!php_date_timezone_initialize_from_hash(&return_value, &tzobj, myht)) {
zend_throw_error(NULL, "Timezone initialization failed"); zend_throw_error(NULL, "Timezone initialization failed");
zval_ptr_dtor(return_value); zval_ptr_dtor(return_value);
} }
@ -3619,12 +3625,51 @@ PHP_METHOD(DateTimeZone, __wakeup)
myht = Z_OBJPROP_P(object); myht = Z_OBJPROP_P(object);
if (php_date_timezone_initialize_from_hash(&return_value, &tzobj, myht) == FAILURE) { if (!php_date_timezone_initialize_from_hash(&return_value, &tzobj, myht)) {
zend_throw_error(NULL, "Timezone initialization failed"); zend_throw_error(NULL, "Timezone initialization failed");
} }
} }
/* }}} */ /* }}} */
/* {{{ */
PHP_METHOD(DateTimeZone, __serialize)
{
zval *object = ZEND_THIS;
php_timezone_obj *tzobj;
HashTable *myht;
ZEND_PARSE_PARAMETERS_NONE();
tzobj = Z_PHPTIMEZONE_P(object);
DATE_CHECK_INITIALIZED(tzobj->initialized, DateTimeZone);
array_init(return_value);
myht = Z_ARRVAL_P(return_value);
date_timezone_object_to_hash(tzobj, myht);
}
/* }}} */
/* {{{ */
PHP_METHOD(DateTimeZone, __unserialize)
{
zval *object = ZEND_THIS;
php_timezone_obj *tzobj;
zval *array;
HashTable *myht;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_ARRAY(array)
ZEND_PARSE_PARAMETERS_END();
tzobj = Z_PHPTIMEZONE_P(object);
myht = Z_ARRVAL_P(array);
if (!php_date_timezone_initialize_from_hash(&object, &tzobj, myht)) {
zend_throw_error(NULL, "Invalid serialization data for DateTimeZone object");
}
}
/* }}} */
/* {{{ Returns the name of the timezone. */ /* {{{ Returns the name of the timezone. */
PHP_FUNCTION(timezone_name_get) PHP_FUNCTION(timezone_name_get)
{ {

View file

@ -453,6 +453,10 @@ class DateTimeZone
*/ */
public static function listIdentifiers(int $timezoneGroup = DateTimeZone::ALL, ?string $countryCode = null): array {} public static function listIdentifiers(int $timezoneGroup = DateTimeZone::ALL, ?string $countryCode = null): array {}
public function __serialize(): array {}
public function __unserialize(array $data): void {}
/** @tentative-return-type */ /** @tentative-return-type */
public function __wakeup(): void {} public function __wakeup(): void {}

View file

@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead. /* This is a generated file, edit the .stub.php file instead.
* Stub hash: ea354510fbf64c42ee1cdd6fd786ab937516226c */ * Stub hash: a157de6bca4bcf5a9ddace9e81ef700f132b4dda */
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_strtotime, 0, 1, MAY_BE_LONG|MAY_BE_FALSE) ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_strtotime, 0, 1, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, datetime, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, datetime, IS_STRING, 0)
@ -431,6 +431,10 @@ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_DateTimeZone_lis
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, countryCode, IS_STRING, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, countryCode, IS_STRING, 1, "null")
ZEND_END_ARG_INFO() ZEND_END_ARG_INFO()
#define arginfo_class_DateTimeZone___serialize arginfo_timezone_abbreviations_list
#define arginfo_class_DateTimeZone___unserialize arginfo_class_DateTimeInterface___unserialize
#define arginfo_class_DateTimeZone___wakeup arginfo_class_DateTimeInterface___wakeup #define arginfo_class_DateTimeZone___wakeup arginfo_class_DateTimeInterface___wakeup
ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_OBJ_INFO_EX(arginfo_class_DateTimeZone___set_state, 0, 1, DateTimeZone, 0) ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_OBJ_INFO_EX(arginfo_class_DateTimeZone___set_state, 0, 1, DateTimeZone, 0)
@ -553,6 +557,8 @@ ZEND_METHOD(DateTimeImmutable, setTimestamp);
ZEND_METHOD(DateTimeImmutable, createFromMutable); ZEND_METHOD(DateTimeImmutable, createFromMutable);
ZEND_METHOD(DateTimeImmutable, createFromInterface); ZEND_METHOD(DateTimeImmutable, createFromInterface);
ZEND_METHOD(DateTimeZone, __construct); ZEND_METHOD(DateTimeZone, __construct);
ZEND_METHOD(DateTimeZone, __serialize);
ZEND_METHOD(DateTimeZone, __unserialize);
ZEND_METHOD(DateTimeZone, __wakeup); ZEND_METHOD(DateTimeZone, __wakeup);
ZEND_METHOD(DateTimeZone, __set_state); ZEND_METHOD(DateTimeZone, __set_state);
ZEND_METHOD(DateInterval, __construct); ZEND_METHOD(DateInterval, __construct);
@ -696,6 +702,8 @@ static const zend_function_entry class_DateTimeZone_methods[] = {
ZEND_ME_MAPPING(getLocation, timezone_location_get, arginfo_class_DateTimeZone_getLocation, ZEND_ACC_PUBLIC) ZEND_ME_MAPPING(getLocation, timezone_location_get, arginfo_class_DateTimeZone_getLocation, ZEND_ACC_PUBLIC)
ZEND_ME_MAPPING(listAbbreviations, timezone_abbreviations_list, arginfo_class_DateTimeZone_listAbbreviations, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) ZEND_ME_MAPPING(listAbbreviations, timezone_abbreviations_list, arginfo_class_DateTimeZone_listAbbreviations, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
ZEND_ME_MAPPING(listIdentifiers, timezone_identifiers_list, arginfo_class_DateTimeZone_listIdentifiers, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) ZEND_ME_MAPPING(listIdentifiers, timezone_identifiers_list, arginfo_class_DateTimeZone_listIdentifiers, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
ZEND_ME(DateTimeZone, __serialize, arginfo_class_DateTimeZone___serialize, ZEND_ACC_PUBLIC)
ZEND_ME(DateTimeZone, __unserialize, arginfo_class_DateTimeZone___unserialize, ZEND_ACC_PUBLIC)
ZEND_ME(DateTimeZone, __wakeup, arginfo_class_DateTimeZone___wakeup, ZEND_ACC_PUBLIC) ZEND_ME(DateTimeZone, __wakeup, arginfo_class_DateTimeZone___wakeup, ZEND_ACC_PUBLIC)
ZEND_ME(DateTimeZone, __set_state, arginfo_class_DateTimeZone___set_state, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) ZEND_ME(DateTimeZone, __set_state, arginfo_class_DateTimeZone___set_state, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
ZEND_FE_END ZEND_FE_END

View file

@ -0,0 +1,58 @@
--TEST--
Test DateTimeZone::__serialize and DateTime::__unserialize
--FILE--
<?php
$tz = new DateTimeZone("CEST");
var_dump($tz->__serialize());
$tz = new DateTimeZone("UTC");
$tz->__unserialize(
[
'timezone_type' => 3,
'timezone' => 'Europe/London',
]
);
var_dump($tz);
$tz->__unserialize(
[
'timezone_type' => 2,
'timezone' => 'CEST',
]
);
var_dump($tz);
$tz->__unserialize(
[
'timezone_type' => 1,
'timezone' => '+0130',
]
);
var_dump($tz);
?>
--EXPECTF--
array(2) {
["timezone_type"]=>
int(2)
["timezone"]=>
string(4) "CEST"
}
object(DateTimeZone)#%d (%d) {
["timezone_type"]=>
int(3)
["timezone"]=>
string(13) "Europe/London"
}
object(DateTimeZone)#%d (%d) {
["timezone_type"]=>
int(2)
["timezone"]=>
string(4) "CEST"
}
object(DateTimeZone)#%d (%d) {
["timezone_type"]=>
int(1)
["timezone"]=>
string(6) "+01:30"
}

View file

@ -0,0 +1,15 @@
--TEST--
Test unserialization of DateTimeZone with null byte
--FILE--
<?php
$serialized = 'O:12:"DateTimeZone":2:{s:13:"timezone_type";i:3;s:8:"timezone";s:17:"Ame' . "\0" .'rica/New_York";}';
try {
$tz = unserialize($serialized);
} catch (Throwable $e) {
echo $e->getMessage(), "\n";
}
?>
--EXPECTF--
Warning: DateTimeZone::__unserialize(): Timezone must not contain null bytes in %s on line %d
Invalid serialization data for DateTimeZone object

View file

@ -6,9 +6,9 @@ $data = unserialize('a:2:{i:0;O:12:"DateTimeZone":2:{s:13:"timezone_type";a:2:{i
var_dump($data); var_dump($data);
?> ?>
--EXPECTF-- --EXPECTF--
Fatal error: Uncaught Error: Timezone initialization failed in %s:%d Fatal error: Uncaught Error: Invalid serialization data for DateTimeZone object in %s:%d
Stack trace: Stack trace:
#0 [internal function]: DateTimeZone->__wakeup() #0 [internal function]: DateTimeZone->__unserialize(Array)
#1 %s(%d): unserialize('a:2:{i:0;O:12:"...') #1 %s(%d): unserialize('a:2:{i:0;O:12:"...')
#2 {main} #2 {main}
thrown in %s on line %d thrown in %s on line %d