From 8ffcaac13c974eefee1b21225b02a61d4e144f25 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Mon, 28 Feb 2022 12:37:49 +0100 Subject: [PATCH] Fix #5: ion\Timestamp crashes with string timezones --- ion.c | 23 +++++++++++++++++++---- ion.stub.php | 4 ++-- ion_arginfo.h | 4 ++-- tests/Timestamp/stringTZ.phpt | 31 +++++++++++++++++++++++++++++++ 4 files changed, 54 insertions(+), 8 deletions(-) create mode 100644 tests/Timestamp/stringTZ.phpt diff --git a/ion.c b/ion.c index cffeee5..aefdeeb 100644 --- a/ion.c +++ b/ion.c @@ -410,14 +410,15 @@ static ZEND_METHOD(ion_Timestamp, __construct) zend_long precision; zend_object *precision_obj = NULL, *format_obj = NULL; - zend_string *fmt = NULL, *dt = NULL; - zval *tz = NULL; + zend_string *fmt = NULL, *dt = NULL, *tz = NULL; + zend_object *tz_obj = NULL; + zval z_tz_tmp, *z_tz_ptr = NULL; ZEND_PARSE_PARAMETERS_START(1, 4) Z_PARAM_OBJ_OF_CLASS_OR_LONG(precision_obj, ce_Timestamp_Precision, precision) Z_PARAM_OPTIONAL Z_PARAM_OBJ_OF_CLASS_OR_STR_OR_NULL(format_obj, ce_Timestamp_Format, fmt) Z_PARAM_STR_OR_NULL(dt) - Z_PARAM_ZVAL(tz) + Z_PARAM_OBJ_OF_CLASS_OR_STR_OR_NULL(tz_obj, php_date_get_timezone_ce(), tz) ZEND_PARSE_PARAMETERS_END(); if (precision_obj) { @@ -426,7 +427,21 @@ static ZEND_METHOD(ion_Timestamp, __construct) if (format_obj) { fmt = Z_STR_P(zend_enum_fetch_case_value(format_obj)); } - php_ion_timestamp_ctor(obj, precision, fmt, dt, tz); + if (tz_obj) { + ZVAL_OBJ(z_tz_ptr = &z_tz_tmp, tz_obj); + } else if (tz) { + // there's no public API, so call timezone_open + zend_function *tz_open = zend_fetch_function_str(ZEND_STRL("timezone_open")); + if (tz_open) { + zval z_arg; + ZVAL_STR(&z_arg, tz); + zend_call_known_function(tz_open, NULL, NULL, z_tz_ptr = &z_tz_tmp, 1, &z_arg, NULL); + } + } + php_ion_timestamp_ctor(obj, precision, fmt, dt, z_tz_ptr); + if (tz && z_tz_ptr) { + zval_ptr_dtor(z_tz_ptr); + } } static ZEND_METHOD(ion_Timestamp, __toString) { diff --git a/ion.stub.php b/ion.stub.php index 06eef69..37bb8e0 100644 --- a/ion.stub.php +++ b/ion.stub.php @@ -275,13 +275,13 @@ class Timestamp extends \DateTime { * @param Timestamp\Precision|int $precision The timestamp's precision. * @param Timestamp\Format|string|null $format The timestamp's format. * @param string|null $datetime The timestamp's value. - * @param \DateTimeZone|null $timezone The timestamp's timezone. + * @param \DateTimeZone|string|null $timezone The timestamp's timezone. */ public function __construct( Timestamp\Precision|int $precision, Timestamp\Format|string|null $format = null, ?string $datetime = null, - ?\DateTimeZone $timezone = null, + \DateTimeZone|string|null $timezone = null, ) {} public function __toString() : string {} diff --git a/ion_arginfo.h b/ion_arginfo.h index a06aedb..0af9a51 100644 --- a/ion_arginfo.h +++ b/ion_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 82f37b032b109ad08cffc965a75843e57210debf */ + * Stub hash: f45c86044a99ab4db187da808bdd5cdfdb7e5a26 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_ion_serialize, 0, 1, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, data, IS_MIXED, 0) @@ -82,7 +82,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ion_Timestamp___construct, 0, 0, 1) ZEND_ARG_OBJ_TYPE_MASK(0, precision, ion\\Timestamp\\Precision, MAY_BE_LONG, NULL) ZEND_ARG_OBJ_TYPE_MASK(0, format, ion\\Timestamp\\Format, MAY_BE_STRING|MAY_BE_NULL, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, datetime, IS_STRING, 1, "null") - ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, timezone, DateTimeZone, 1, "null") + ZEND_ARG_OBJ_TYPE_MASK(0, timezone, DateTimeZone, MAY_BE_STRING|MAY_BE_NULL, "null") ZEND_END_ARG_INFO() #define arginfo_class_ion_Timestamp___toString arginfo_class_ion_Symbol___toString diff --git a/tests/Timestamp/stringTZ.phpt b/tests/Timestamp/stringTZ.phpt new file mode 100644 index 0000000..a7f5c9b --- /dev/null +++ b/tests/Timestamp/stringTZ.phpt @@ -0,0 +1,31 @@ +--TEST-- +ion\Timestamp with TZ as string +--EXTENSIONS-- +ion +--INI-- +date.timezone=UTC +--FILE-- +TEST +getTimezone()); +echo $ts, "\n"; +echo $ts->setTimezone(new DateTimeZone(("America/Toronto"))), "\n"; +?> +DONE +--EXPECTF-- +TEST +object(DateTimeZone)#%d (2) { + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(13) "Europe/Madrid" +} +2022-02-28T11:40+01:00 +2022-02-28T05:40-05:00 +DONE -- 2.30.2