Fix #5: ion\Timestamp crashes with string timezones
authorMichael Wallner <mike@php.net>
Mon, 28 Feb 2022 11:37:49 +0000 (12:37 +0100)
committerMichael Wallner <mike@php.net>
Mon, 28 Feb 2022 11:37:49 +0000 (12:37 +0100)
ion.c
ion.stub.php
ion_arginfo.h
tests/Timestamp/stringTZ.phpt [new file with mode: 0644]

diff --git a/ion.c b/ion.c
index cffeee5ec81febd08cd34a7cbe40f85a4cef0aaa..aefdeebf8cf7c472761e031074294aebad387e71 100644 (file)
--- 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)
 {
index 06eef69130538f46da3bdeb2f92fc8d172b0e4ff..37bb8e09b8e0806ac5afa7ee5bd3f86c0e3e4557 100644 (file)
@@ -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 {}
index a06aedb7d77ee253a204e949395cbe3cbbe57bf0..0af9a5172b69f307715e74aea3544ab3d78be6ed 100644 (file)
@@ -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 (file)
index 0000000..a7f5c9b
--- /dev/null
@@ -0,0 +1,31 @@
+--TEST--
+ion\Timestamp with TZ as string
+--EXTENSIONS--
+ion
+--INI--
+date.timezone=UTC
+--FILE--
+TEST
+<?php
+$ts = new ion\Timestamp(
+       precision: ion\Timestamp\Precision::MinTZ,
+       format: \ion\Timestamp\Format::Min,
+       datetime: "2022-02-28T11:40",
+       timezone: "Europe/Madrid",
+);
+var_dump($ts->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