From f54708b09946646559cf8d2b12f62ce3dd16a115 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Thu, 21 Mar 2024 19:44:02 +0000 Subject: [PATCH 1/3] ext/intl: IntlDateFormatter::parse adds new optional argument. New option to update its internal calendar. --- ext/intl/dateformat/dateformat.stub.php | 3 ++- ext/intl/dateformat/dateformat_arginfo.h | 3 ++- ext/intl/dateformat/dateformat_parse.c | 28 ++++++++++++++++-------- ext/intl/php_intl.stub.php | 7 ++++-- ext/intl/php_intl_arginfo.h | 3 ++- ext/intl/tests/gh13766.phpt | 19 ++++++++++++++++ 6 files changed, 49 insertions(+), 14 deletions(-) create mode 100644 ext/intl/tests/gh13766.phpt diff --git a/ext/intl/dateformat/dateformat.stub.php b/ext/intl/dateformat/dateformat.stub.php index 06f26b0658739..e4a93820e0eda 100644 --- a/ext/intl/dateformat/dateformat.stub.php +++ b/ext/intl/dateformat/dateformat.stub.php @@ -154,10 +154,11 @@ public static function formatObject($datetime, $format = null, ?string $locale = /** * @param int $offset + * @param bool $updateCalendar * @tentative-return-type * @alias datefmt_parse */ - public function parse(string $string, &$offset = null): int|float|false {} + public function parse(string $string, &$offset = null, bool $updateCalendar = false): int|float|false {} /** * @param int $offset diff --git a/ext/intl/dateformat/dateformat_arginfo.h b/ext/intl/dateformat/dateformat_arginfo.h index 4d16a26ef1673..52f1d13d80e5c 100644 --- a/ext/intl/dateformat/dateformat_arginfo.h +++ b/ext/intl/dateformat/dateformat_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 91f1dbe4843fd1d4dff7266e814a3c8f9aed882a */ + * Stub hash: b30993b32b0ce9e9034f59172820c72c7ea1f551 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_IntlDateFormatter___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, locale, IS_STRING, 1) @@ -73,6 +73,7 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_MASK_EX(arginfo_class_IntlDateFormatter_parse, 0, 1, MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, string, IS_STRING, 0) ZEND_ARG_INFO_WITH_DEFAULT_VALUE(1, offset, "null") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, updateCalendar, _IS_BOOL, 0, "false") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_MASK_EX(arginfo_class_IntlDateFormatter_localtime, 0, 1, MAY_BE_ARRAY|MAY_BE_FALSE) diff --git a/ext/intl/dateformat/dateformat_parse.c b/ext/intl/dateformat/dateformat_parse.c index 69aeff886d3b9..0dfa4d74e4f4c 100644 --- a/ext/intl/dateformat/dateformat_parse.c +++ b/ext/intl/dateformat/dateformat_parse.c @@ -31,7 +31,7 @@ * if set to 1 - store any error encountered in the parameter parse_error * if set to 0 - no need to store any error encountered in the parameter parse_error */ -static void internal_parse_to_timestamp(IntlDateFormatter_object *dfo, char* text_to_parse, size_t text_len, int32_t *parse_pos, zval *return_value) +static void internal_parse_to_timestamp(IntlDateFormatter_object *dfo, char* text_to_parse, size_t text_len, int32_t *parse_pos, bool update_calendar, zval *return_value) { double result = 0; UDate timestamp =0; @@ -42,13 +42,22 @@ static void internal_parse_to_timestamp(IntlDateFormatter_object *dfo, char* tex intl_convert_utf8_to_utf16(&text_utf16, &text_utf16_len, text_to_parse, text_len, &INTL_DATA_ERROR_CODE(dfo)); INTL_METHOD_CHECK_STATUS(dfo, "Error converting timezone to UTF-16" ); - timestamp = udat_parse( DATE_FORMAT_OBJECT(dfo), text_utf16, text_utf16_len, parse_pos, &INTL_DATA_ERROR_CODE(dfo)); - if( text_utf16 ){ - efree(text_utf16); + if (UNEXPECTED(update_calendar)) { + UCalendar *parsed_calendar = (UCalendar *)udat_getCalendar(DATE_FORMAT_OBJECT(dfo)); + udat_parseCalendar( DATE_FORMAT_OBJECT(dfo), parsed_calendar, text_utf16, text_utf16_len, parse_pos, &INTL_DATA_ERROR_CODE(dfo)); + if( text_utf16 ){ + efree(text_utf16); + } + INTL_METHOD_CHECK_STATUS( dfo, "Calendar parsing failed" ); + timestamp = ucal_getMillis( parsed_calendar, &INTL_DATA_ERROR_CODE(dfo)); + } else { + timestamp = udat_parse( DATE_FORMAT_OBJECT(dfo), text_utf16, text_utf16_len, parse_pos, &INTL_DATA_ERROR_CODE(dfo)); + if( text_utf16 ){ + efree(text_utf16); + } } INTL_METHOD_CHECK_STATUS( dfo, "Date parsing failed" ); - /* Since return is in sec. */ result = (double)timestamp / U_MILLIS_PER_SECOND; if (result > (double)LONG_MAX || result < (double)LONG_MIN) { @@ -122,13 +131,14 @@ PHP_FUNCTION(datefmt_parse) char* text_to_parse = NULL; size_t text_len =0; zval* z_parse_pos = NULL; - int32_t parse_pos = -1; + int32_t parse_pos = -1; + bool update_calendar = false; DATE_FORMAT_METHOD_INIT_VARS; /* Parse parameters. */ - if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "Os|z!", - &object, IntlDateFormatter_ce_ptr, &text_to_parse, &text_len, &z_parse_pos ) == FAILURE ){ + if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "Os|z!b", + &object, IntlDateFormatter_ce_ptr, &text_to_parse, &text_len, &z_parse_pos, &update_calendar ) == FAILURE ){ RETURN_THROWS(); } @@ -149,7 +159,7 @@ PHP_FUNCTION(datefmt_parse) RETURN_FALSE; } } - internal_parse_to_timestamp( dfo, text_to_parse, text_len, z_parse_pos?&parse_pos:NULL, return_value); + internal_parse_to_timestamp( dfo, text_to_parse, text_len, z_parse_pos?&parse_pos:NULL, update_calendar, return_value); if(z_parse_pos) { zval_ptr_dtor(z_parse_pos); ZVAL_LONG(z_parse_pos, parse_pos); diff --git a/ext/intl/php_intl.stub.php b/ext/intl/php_intl.stub.php index c03ee482123f2..3c23788b87e52 100644 --- a/ext/intl/php_intl.stub.php +++ b/ext/intl/php_intl.stub.php @@ -374,8 +374,11 @@ function datefmt_format(IntlDateFormatter $formatter, $datetime): string|false { */ function datefmt_format_object($datetime, $format = null, ?string $locale = null): string|false {} -/** @param int $offset */ -function datefmt_parse(IntlDateFormatter $formatter, string $string, &$offset = null): int|float|false {} +/** + * @param int $offset + * @param bool $updateCalendar + */ +function datefmt_parse(IntlDateFormatter $formatter, string $string, &$offset = null, bool $updateCalendar = false): int|float|false {} /** * @param int $offset diff --git a/ext/intl/php_intl_arginfo.h b/ext/intl/php_intl_arginfo.h index 8e632029bf0e1..d8506b7bd9e33 100644 --- a/ext/intl/php_intl_arginfo.h +++ b/ext/intl/php_intl_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: b45ef763d82e1ad9ab27336fd0ab95e2d2e79a90 */ + * Stub hash: 3184b18c1a3a623ea6e983c93b570232e4918430 */ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_intlcal_create_instance, 0, 0, IntlCalendar, 1) ZEND_ARG_INFO_WITH_DEFAULT_VALUE(0, timezone, "null") @@ -351,6 +351,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_datefmt_parse, 0, 2, MAY_BE_LONG ZEND_ARG_OBJ_INFO(0, formatter, IntlDateFormatter, 0) ZEND_ARG_TYPE_INFO(0, string, IS_STRING, 0) ZEND_ARG_INFO_WITH_DEFAULT_VALUE(1, offset, "null") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, updateCalendar, _IS_BOOL, 0, "false") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_datefmt_localtime, 0, 2, MAY_BE_ARRAY|MAY_BE_FALSE) diff --git a/ext/intl/tests/gh13766.phpt b/ext/intl/tests/gh13766.phpt new file mode 100644 index 0000000000000..6b7de5398cc3c --- /dev/null +++ b/ext/intl/tests/gh13766.phpt @@ -0,0 +1,19 @@ +--TEST-- +IntlDateFormatter::parse update its calendar +--EXTENSIONS-- +intl +--FILE-- +setTimeZone('Europe/Berlin'); +$oIntlDateFormatter->setPattern('VV'); + +var_dump($oIntlDateFormatter->parse('America/Los_Angeles', $offset1)); +var_dump($oIntlDateFormatter->getTimeZone()->getID()); +var_dump($oIntlDateFormatter->parse('America/Los_Angeles', $offset2, true)); +var_dump($oIntlDateFormatter->getTimeZone()->getID()); +--EXPECTF-- +int(%d) +string(13) "Europe/Berlin" +int(%d) +string(19) "America/Los_Angeles" From 286533e77084f97b7e296edb79dcbf99223cdc15 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Mon, 25 Mar 2024 18:43:07 +0000 Subject: [PATCH 2/3] alternative from feedback for comparison. --- ext/intl/dateformat/dateformat.stub.php | 9 ++++- ext/intl/dateformat/dateformat_arginfo.h | 7 +++- ext/intl/dateformat/dateformat_parse.c | 48 +++++++++++++++++++++--- ext/intl/php_intl.stub.php | 7 +--- ext/intl/php_intl_arginfo.h | 3 +- ext/intl/tests/gh13766.phpt | 2 +- 6 files changed, 59 insertions(+), 17 deletions(-) diff --git a/ext/intl/dateformat/dateformat.stub.php b/ext/intl/dateformat/dateformat.stub.php index e4a93820e0eda..4a9af0ebaedb8 100644 --- a/ext/intl/dateformat/dateformat.stub.php +++ b/ext/intl/dateformat/dateformat.stub.php @@ -154,11 +154,16 @@ public static function formatObject($datetime, $format = null, ?string $locale = /** * @param int $offset - * @param bool $updateCalendar * @tentative-return-type * @alias datefmt_parse */ - public function parse(string $string, &$offset = null, bool $updateCalendar = false): int|float|false {} + public function parse(string $string, &$offset = null): int|float|false {} + + /** + * @param int $offset + * @tentative-return-type + */ + public function parseToCalendar(string $string, &$offset = null): int|float|false {} /** * @param int $offset diff --git a/ext/intl/dateformat/dateformat_arginfo.h b/ext/intl/dateformat/dateformat_arginfo.h index 52f1d13d80e5c..1430c3c278387 100644 --- a/ext/intl/dateformat/dateformat_arginfo.h +++ b/ext/intl/dateformat/dateformat_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: b30993b32b0ce9e9034f59172820c72c7ea1f551 */ + * Stub hash: 9b2f5e8ef843f7415c0c52aff0c7b58b527a5154 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_IntlDateFormatter___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, locale, IS_STRING, 1) @@ -73,9 +73,10 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_MASK_EX(arginfo_class_IntlDateFormatter_parse, 0, 1, MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, string, IS_STRING, 0) ZEND_ARG_INFO_WITH_DEFAULT_VALUE(1, offset, "null") - ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, updateCalendar, _IS_BOOL, 0, "false") ZEND_END_ARG_INFO() +#define arginfo_class_IntlDateFormatter_parseToCalendar arginfo_class_IntlDateFormatter_parse + ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_MASK_EX(arginfo_class_IntlDateFormatter_localtime, 0, 1, MAY_BE_ARRAY|MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, string, IS_STRING, 0) ZEND_ARG_INFO_WITH_DEFAULT_VALUE(1, offset, "null") @@ -105,6 +106,7 @@ ZEND_FUNCTION(datefmt_is_lenient); ZEND_FUNCTION(datefmt_format); ZEND_FUNCTION(datefmt_format_object); ZEND_FUNCTION(datefmt_parse); +ZEND_METHOD(IntlDateFormatter, parseToCalendar); ZEND_FUNCTION(datefmt_localtime); ZEND_FUNCTION(datefmt_get_error_code); ZEND_FUNCTION(datefmt_get_error_message); @@ -128,6 +130,7 @@ static const zend_function_entry class_IntlDateFormatter_methods[] = { ZEND_RAW_FENTRY("format", zif_datefmt_format, arginfo_class_IntlDateFormatter_format, ZEND_ACC_PUBLIC, NULL, NULL) ZEND_RAW_FENTRY("formatObject", zif_datefmt_format_object, arginfo_class_IntlDateFormatter_formatObject, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC, NULL, NULL) ZEND_RAW_FENTRY("parse", zif_datefmt_parse, arginfo_class_IntlDateFormatter_parse, ZEND_ACC_PUBLIC, NULL, NULL) + ZEND_ME(IntlDateFormatter, parseToCalendar, arginfo_class_IntlDateFormatter_parseToCalendar, ZEND_ACC_PUBLIC) ZEND_RAW_FENTRY("localtime", zif_datefmt_localtime, arginfo_class_IntlDateFormatter_localtime, ZEND_ACC_PUBLIC, NULL, NULL) ZEND_RAW_FENTRY("getErrorCode", zif_datefmt_get_error_code, arginfo_class_IntlDateFormatter_getErrorCode, ZEND_ACC_PUBLIC, NULL, NULL) ZEND_RAW_FENTRY("getErrorMessage", zif_datefmt_get_error_message, arginfo_class_IntlDateFormatter_getErrorMessage, ZEND_ACC_PUBLIC, NULL, NULL) diff --git a/ext/intl/dateformat/dateformat_parse.c b/ext/intl/dateformat/dateformat_parse.c index 0dfa4d74e4f4c..58adb85676a60 100644 --- a/ext/intl/dateformat/dateformat_parse.c +++ b/ext/intl/dateformat/dateformat_parse.c @@ -131,14 +131,13 @@ PHP_FUNCTION(datefmt_parse) char* text_to_parse = NULL; size_t text_len =0; zval* z_parse_pos = NULL; - int32_t parse_pos = -1; - bool update_calendar = false; + int32_t parse_pos = -1; DATE_FORMAT_METHOD_INIT_VARS; /* Parse parameters. */ - if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "Os|z!b", - &object, IntlDateFormatter_ce_ptr, &text_to_parse, &text_len, &z_parse_pos, &update_calendar ) == FAILURE ){ + if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "Os|z!", + &object, IntlDateFormatter_ce_ptr, &text_to_parse, &text_len, &z_parse_pos ) == FAILURE ){ RETURN_THROWS(); } @@ -159,7 +158,7 @@ PHP_FUNCTION(datefmt_parse) RETURN_FALSE; } } - internal_parse_to_timestamp( dfo, text_to_parse, text_len, z_parse_pos?&parse_pos:NULL, update_calendar, return_value); + internal_parse_to_timestamp( dfo, text_to_parse, text_len, z_parse_pos?&parse_pos:NULL, false, return_value); if(z_parse_pos) { zval_ptr_dtor(z_parse_pos); ZVAL_LONG(z_parse_pos, parse_pos); @@ -167,6 +166,45 @@ PHP_FUNCTION(datefmt_parse) } /* }}} */ +PHP_METHOD(IntlDateFormatter, parseToCalendar) +{ + char* text_to_parse = NULL; + size_t text_len =0; + zval* z_parse_pos = NULL; + int32_t parse_pos = -1; + + DATE_FORMAT_METHOD_INIT_VARS; + + /* Parse parameters. */ + if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "Os|z!", + &object, IntlDateFormatter_ce_ptr, &text_to_parse, &text_len, &z_parse_pos ) == FAILURE ){ + RETURN_THROWS(); + } + + /* Fetch the object. */ + DATE_FORMAT_METHOD_FETCH_OBJECT; + + if (z_parse_pos) { + zend_long long_parse_pos; + ZVAL_DEREF(z_parse_pos); + long_parse_pos = zval_get_long(z_parse_pos); + 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.", 0); + RETURN_FALSE; + } + parse_pos = (int32_t)long_parse_pos; + if((size_t)parse_pos > text_len) { + RETURN_FALSE; + } + } + internal_parse_to_timestamp( dfo, text_to_parse, text_len, z_parse_pos?&parse_pos:NULL, true, return_value); + if(z_parse_pos) { + zval_ptr_dtor(z_parse_pos); + ZVAL_LONG(z_parse_pos, parse_pos); + } +} + /* {{{ Parse the string $value to a localtime array */ PHP_FUNCTION(datefmt_localtime) { diff --git a/ext/intl/php_intl.stub.php b/ext/intl/php_intl.stub.php index 3c23788b87e52..c03ee482123f2 100644 --- a/ext/intl/php_intl.stub.php +++ b/ext/intl/php_intl.stub.php @@ -374,11 +374,8 @@ function datefmt_format(IntlDateFormatter $formatter, $datetime): string|false { */ function datefmt_format_object($datetime, $format = null, ?string $locale = null): string|false {} -/** - * @param int $offset - * @param bool $updateCalendar - */ -function datefmt_parse(IntlDateFormatter $formatter, string $string, &$offset = null, bool $updateCalendar = false): int|float|false {} +/** @param int $offset */ +function datefmt_parse(IntlDateFormatter $formatter, string $string, &$offset = null): int|float|false {} /** * @param int $offset diff --git a/ext/intl/php_intl_arginfo.h b/ext/intl/php_intl_arginfo.h index d8506b7bd9e33..8e632029bf0e1 100644 --- a/ext/intl/php_intl_arginfo.h +++ b/ext/intl/php_intl_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 3184b18c1a3a623ea6e983c93b570232e4918430 */ + * Stub hash: b45ef763d82e1ad9ab27336fd0ab95e2d2e79a90 */ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_intlcal_create_instance, 0, 0, IntlCalendar, 1) ZEND_ARG_INFO_WITH_DEFAULT_VALUE(0, timezone, "null") @@ -351,7 +351,6 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_datefmt_parse, 0, 2, MAY_BE_LONG ZEND_ARG_OBJ_INFO(0, formatter, IntlDateFormatter, 0) ZEND_ARG_TYPE_INFO(0, string, IS_STRING, 0) ZEND_ARG_INFO_WITH_DEFAULT_VALUE(1, offset, "null") - ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, updateCalendar, _IS_BOOL, 0, "false") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_datefmt_localtime, 0, 2, MAY_BE_ARRAY|MAY_BE_FALSE) diff --git a/ext/intl/tests/gh13766.phpt b/ext/intl/tests/gh13766.phpt index 6b7de5398cc3c..358be93b033ae 100644 --- a/ext/intl/tests/gh13766.phpt +++ b/ext/intl/tests/gh13766.phpt @@ -10,7 +10,7 @@ $oIntlDateFormatter->setPattern('VV'); var_dump($oIntlDateFormatter->parse('America/Los_Angeles', $offset1)); var_dump($oIntlDateFormatter->getTimeZone()->getID()); -var_dump($oIntlDateFormatter->parse('America/Los_Angeles', $offset2, true)); +var_dump($oIntlDateFormatter->parseToCalendar('America/Los_Angeles', $offset2)); var_dump($oIntlDateFormatter->getTimeZone()->getID()); --EXPECTF-- int(%d) From ad4cfa94b541f4cf837ffe59aa27ac1cf58f77ca Mon Sep 17 00:00:00 2001 From: David Carlier Date: Thu, 25 Apr 2024 07:26:30 +0100 Subject: [PATCH 3/3] changes from feedback --- ext/intl/dateformat/dateformat.stub.php | 1 - ext/intl/dateformat/dateformat_arginfo.h | 7 +++- ext/intl/dateformat/dateformat_parse.c | 48 +++++++++++++----------- ext/intl/tests/gh13766.phpt | 16 ++++++++ 4 files changed, 48 insertions(+), 24 deletions(-) diff --git a/ext/intl/dateformat/dateformat.stub.php b/ext/intl/dateformat/dateformat.stub.php index 4a9af0ebaedb8..7582af2717fbe 100644 --- a/ext/intl/dateformat/dateformat.stub.php +++ b/ext/intl/dateformat/dateformat.stub.php @@ -161,7 +161,6 @@ public function parse(string $string, &$offset = null): int|float|false {} /** * @param int $offset - * @tentative-return-type */ public function parseToCalendar(string $string, &$offset = null): int|float|false {} diff --git a/ext/intl/dateformat/dateformat_arginfo.h b/ext/intl/dateformat/dateformat_arginfo.h index 1430c3c278387..df1de7d6895f4 100644 --- a/ext/intl/dateformat/dateformat_arginfo.h +++ b/ext/intl/dateformat/dateformat_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 9b2f5e8ef843f7415c0c52aff0c7b58b527a5154 */ + * Stub hash: 56b66b1b51220ddbff698ec4c9a6ae60f3e0bfb0 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_IntlDateFormatter___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, locale, IS_STRING, 1) @@ -75,7 +75,10 @@ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_MASK_EX(arginfo_class_IntlDateFormatte ZEND_ARG_INFO_WITH_DEFAULT_VALUE(1, offset, "null") ZEND_END_ARG_INFO() -#define arginfo_class_IntlDateFormatter_parseToCalendar arginfo_class_IntlDateFormatter_parse +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_IntlDateFormatter_parseToCalendar, 0, 1, MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_FALSE) + ZEND_ARG_TYPE_INFO(0, string, IS_STRING, 0) + ZEND_ARG_INFO_WITH_DEFAULT_VALUE(1, offset, "null") +ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_MASK_EX(arginfo_class_IntlDateFormatter_localtime, 0, 1, MAY_BE_ARRAY|MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, string, IS_STRING, 0) diff --git a/ext/intl/dateformat/dateformat_parse.c b/ext/intl/dateformat/dateformat_parse.c index 58adb85676a60..82b5a71bbee8f 100644 --- a/ext/intl/dateformat/dateformat_parse.c +++ b/ext/intl/dateformat/dateformat_parse.c @@ -43,16 +43,16 @@ static void internal_parse_to_timestamp(IntlDateFormatter_object *dfo, char* tex INTL_METHOD_CHECK_STATUS(dfo, "Error converting timezone to UTF-16" ); if (UNEXPECTED(update_calendar)) { - UCalendar *parsed_calendar = (UCalendar *)udat_getCalendar(DATE_FORMAT_OBJECT(dfo)); - udat_parseCalendar( DATE_FORMAT_OBJECT(dfo), parsed_calendar, text_utf16, text_utf16_len, parse_pos, &INTL_DATA_ERROR_CODE(dfo)); - if( text_utf16 ){ + UCalendar *parsed_calendar = (UCalendar *)udat_getCalendar(DATE_FORMAT_OBJECT(dfo)); + udat_parseCalendar(DATE_FORMAT_OBJECT(dfo), parsed_calendar, text_utf16, text_utf16_len, parse_pos, &INTL_DATA_ERROR_CODE(dfo)); + if (text_utf16) { efree(text_utf16); } INTL_METHOD_CHECK_STATUS( dfo, "Calendar parsing failed" ); timestamp = ucal_getMillis( parsed_calendar, &INTL_DATA_ERROR_CODE(dfo)); } else { - timestamp = udat_parse( DATE_FORMAT_OBJECT(dfo), text_utf16, text_utf16_len, parse_pos, &INTL_DATA_ERROR_CODE(dfo)); - if( text_utf16 ){ + timestamp = udat_parse(DATE_FORMAT_OBJECT(dfo), text_utf16, text_utf16_len, parse_pos, &INTL_DATA_ERROR_CODE(dfo)); + if (text_utf16) { efree(text_utf16); } } @@ -154,12 +154,12 @@ PHP_FUNCTION(datefmt_parse) RETURN_FALSE; } parse_pos = (int32_t)long_parse_pos; - if((size_t)parse_pos > text_len) { + if ((size_t)parse_pos > text_len) { RETURN_FALSE; } } - internal_parse_to_timestamp( dfo, text_to_parse, text_len, z_parse_pos?&parse_pos:NULL, false, return_value); - if(z_parse_pos) { + internal_parse_to_timestamp( dfo, text_to_parse, text_len, z_parse_pos ? &parse_pos : NULL, false, return_value); + if (z_parse_pos) { zval_ptr_dtor(z_parse_pos); ZVAL_LONG(z_parse_pos, parse_pos); } @@ -168,18 +168,19 @@ PHP_FUNCTION(datefmt_parse) PHP_METHOD(IntlDateFormatter, parseToCalendar) { - char* text_to_parse = NULL; - size_t text_len =0; - zval* z_parse_pos = NULL; - int32_t parse_pos = -1; + zend_string *text_to_parse = NULL; + zval* z_parse_pos = NULL; + int32_t parse_pos = -1; DATE_FORMAT_METHOD_INIT_VARS; - /* Parse parameters. */ - if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "Os|z!", - &object, IntlDateFormatter_ce_ptr, &text_to_parse, &text_len, &z_parse_pos ) == FAILURE ){ - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_STR(text_to_parse) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(z_parse_pos) + ZEND_PARSE_PARAMETERS_END(); + + object = ZEND_THIS; /* Fetch the object. */ DATE_FORMAT_METHOD_FETCH_OBJECT; @@ -187,19 +188,24 @@ PHP_METHOD(IntlDateFormatter, parseToCalendar) if (z_parse_pos) { zend_long long_parse_pos; ZVAL_DEREF(z_parse_pos); - long_parse_pos = zval_get_long(z_parse_pos); + bool failed = false; + long_parse_pos = zval_try_get_long(z_parse_pos, &failed); + if (failed) { + zend_argument_type_error(2, "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.", 0); RETURN_FALSE; } parse_pos = (int32_t)long_parse_pos; - if((size_t)parse_pos > text_len) { + if (parse_pos != -1 && (size_t)parse_pos > ZSTR_LEN(text_to_parse)) { RETURN_FALSE; } } - internal_parse_to_timestamp( dfo, text_to_parse, text_len, z_parse_pos?&parse_pos:NULL, true, return_value); - if(z_parse_pos) { + internal_parse_to_timestamp( dfo, ZSTR_VAL(text_to_parse), ZSTR_LEN(text_to_parse), z_parse_pos ? &parse_pos : NULL, true, return_value); + if (z_parse_pos) { zval_ptr_dtor(z_parse_pos); ZVAL_LONG(z_parse_pos, parse_pos); } diff --git a/ext/intl/tests/gh13766.phpt b/ext/intl/tests/gh13766.phpt index 358be93b033ae..b01b557e497a6 100644 --- a/ext/intl/tests/gh13766.phpt +++ b/ext/intl/tests/gh13766.phpt @@ -12,8 +12,24 @@ var_dump($oIntlDateFormatter->parse('America/Los_Angeles', $offset1)); var_dump($oIntlDateFormatter->getTimeZone()->getID()); var_dump($oIntlDateFormatter->parseToCalendar('America/Los_Angeles', $offset2)); var_dump($oIntlDateFormatter->getTimeZone()->getID()); +$offset3 = "offset"; + +try { + $oIntlDateFormatter->parseToCalendar('America/Los_Angeles', $offset3); +} catch (\TypeError $e) { + echo $e->getMessage() . PHP_EOL; +} +$offset3 = PHP_INT_MAX * 16; +try { + $oIntlDateFormatter->parseToCalendar('America/Los_Angeles', $offset3); +} catch (\ValueError $e) { + echo $e->getMessage(); +} --EXPECTF-- int(%d) string(13) "Europe/Berlin" int(%d) string(19) "America/Los_Angeles" +IntlDateFormatter::parseToCalendar(): Argument #2 ($offset) must be of type int, string given + +Deprecated: Implicit conversion from float 1.4757395258967641E+20 to int loses precision in %s on line %d