[php-src] master: ext/Intl: Fix IntlDateFormatter offset type validation (#22533)

Weilin Du via GitHub <[email protected]>
Newsgroups gmane.comp.php.cvs.general
Message-ID <[email protected]>
Author: Weilin Du (LamentXU123)
Committer: GitHub (web-flow)
Pusher: LamentXU123
Date: 2026-07-04T01:32:47+08:00

Commit: https://github.com/php/php-src/commit/52b56eb2543c9acb9a6ef5169b5fcda098acb833
Raw diff: https://github.com/php/php-src/commit/52b56eb2543c9acb9a6ef5169b5fcda098acb833.diff

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.

Changed paths:
  A  ext/intl/tests/datefmt_parse_localtime_offset_type_error.phpt
  M  NEWS
  M  UPGRADING
  M  ext/intl/dateformat/dateformat_parse.cpp


Diff:

diff --git a/NEWS b/NEWS
index caddbd717490..216f3b2b52b9 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 eb6d182c54a7..a42d5ec355a6 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 d818627439e3..0537b42feec5 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 000000000000..5c3d03cd4f65
--- /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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.