Commit 52b56eb2543 for php.net
commit 52b56eb2543c9acb9a6ef5169b5fcda098acb833
Author: Weilin Du <weilindu@php.net>
Date: Sat Jul 4 01:32:47 2026 +0800
ext/Intl: Fix IntlDateFormatter offset type validation (#22533)
IntlDateFormatter::parse()/datefmt_parse() and
IntlDateFormatter::localtime()/datefmt_localtime() now raise a TypeError
when the offset argument is not of type int instead of silently converting
the value.
diff --git a/NEWS b/NEWS
index caddbd71749..216f3b2b52b 100644
--- a/NEWS
+++ b/NEWS
@@ -132,6 +132,9 @@ PHP NEWS
locale_get_display_keyword_value() respectively. (Weilin Du)
. Fix incorrect argument positions for invalid start/end arguments in
transliterator_transliterate(). (Weilin Du)
+ . IntlDateFormatter::parse()/datefmt_parse() and
+ IntlDateFormatter::localtime()/datefmt_localtime() now raise TypeError
+ when the offset argument is not of type int. (Weilin Du)
. Fixed IntlTimeZone::getDisplayName() to synchronize object error state
for invalid display types. (Weilin Du)
. Fixed Locale::lookup() and locale_lookup() to return NULL instead of the
diff --git a/UPGRADING b/UPGRADING
index eb6d182c54a..a42d5ec355a 100644
--- a/UPGRADING
+++ b/UPGRADING
@@ -56,6 +56,10 @@ PHP 8.6 UPGRADE NOTES
. ResourceBundle::get() and resourcebundle_get() now report fallback-disabled
resource lookups with "without fallback to <locale>" instead of the
malformed "without fallback from to <locale>".
+ . IntlDateFormatter::parse()/datefmt_parse() and
+ IntlDateFormatter::localtime()/datefmt_localtime() now raise a TypeError
+ when the offset argument is not of type int instead of silently converting
+ the value.
- PCNTL:
. pcntl_alarm() now raises a ValueError if the seconds argument is
diff --git a/ext/intl/dateformat/dateformat_parse.cpp b/ext/intl/dateformat/dateformat_parse.cpp
index d818627439e..0537b42feec 100644
--- a/ext/intl/dateformat/dateformat_parse.cpp
+++ b/ext/intl/dateformat/dateformat_parse.cpp
@@ -147,9 +147,12 @@ U_CFUNC PHP_FUNCTION(datefmt_parse)
DATE_FORMAT_METHOD_FETCH_OBJECT;
if (z_parse_pos) {
- zval *z_parse_pos_tmp = z_parse_pos;
- ZVAL_DEREF(z_parse_pos_tmp);
- const zend_long long_parse_pos = zval_get_long(z_parse_pos_tmp);
+ bool failed;
+ const zend_long long_parse_pos = zval_try_get_long(z_parse_pos, &failed);
+ if (failed) {
+ zend_argument_type_error(hasThis() ? 2 : 3, "must be of type int, %s given", zend_zval_value_name(z_parse_pos));
+ RETURN_THROWS();
+ }
if (ZEND_LONG_INT_OVFL(long_parse_pos)) {
intl_error_set_code(NULL, U_ILLEGAL_ARGUMENT_ERROR);
intl_error_set_custom_msg(NULL, "String index is out of valid range.");
@@ -229,9 +232,12 @@ U_CFUNC PHP_FUNCTION(datefmt_localtime)
DATE_FORMAT_METHOD_FETCH_OBJECT;
if (z_parse_pos) {
- zval *z_parse_pos_tmp = z_parse_pos;
- ZVAL_DEREF(z_parse_pos_tmp);
- const zend_long long_parse_pos = zval_get_long(z_parse_pos_tmp);
+ bool failed;
+ const zend_long long_parse_pos = zval_try_get_long(z_parse_pos, &failed);
+ if (failed) {
+ zend_argument_type_error(hasThis() ? 2 : 3, "must be of type int, %s given", zend_zval_value_name(z_parse_pos));
+ RETURN_THROWS();
+ }
if (ZEND_LONG_INT_OVFL(long_parse_pos)) {
intl_error_set_code(NULL, U_ILLEGAL_ARGUMENT_ERROR);
intl_error_set_custom_msg(NULL, "String index is out of valid range.");
diff --git a/ext/intl/tests/datefmt_parse_localtime_offset_type_error.phpt b/ext/intl/tests/datefmt_parse_localtime_offset_type_error.phpt
new file mode 100644
index 00000000000..5c3d03cd4f6
--- /dev/null
+++ b/ext/intl/tests/datefmt_parse_localtime_offset_type_error.phpt
@@ -0,0 +1,44 @@
+--TEST--
+datefmt_parse() and datefmt_localtime() validate offset type
+--EXTENSIONS--
+intl
+--FILE--
+<?php
+
+$fmt = new IntlDateFormatter('en_GB');
+$fmt->setPattern('VV');
+
+$offset = 'offset';
+try {
+ $fmt->parse('America/Los_Angeles', $offset);
+} catch (TypeError $e) {
+ echo $e->getMessage(), PHP_EOL;
+}
+
+$offset = 'offset';
+try {
+ datefmt_parse($fmt, 'America/Los_Angeles', $offset);
+} catch (TypeError $e) {
+ echo $e->getMessage(), PHP_EOL;
+}
+
+$offset = 'offset';
+try {
+ $fmt->localtime('America/Los_Angeles', $offset);
+} catch (TypeError $e) {
+ echo $e->getMessage(), PHP_EOL;
+}
+
+$offset = 'offset';
+try {
+ datefmt_localtime($fmt, 'America/Los_Angeles', $offset);
+} catch (TypeError $e) {
+ echo $e->getMessage(), PHP_EOL;
+}
+
+?>
+--EXPECT--
+IntlDateFormatter::parse(): Argument #2 ($offset) must be of type int, string given
+datefmt_parse(): Argument #3 ($offset) must be of type int, string given
+IntlDateFormatter::localtime(): Argument #2 ($offset) must be of type int, string given
+datefmt_localtime(): Argument #3 ($offset) must be of type int, string given