Skip to content

Commit 4efca40

Browse files
committed
ext/intl: Fix Locale::lookup() fallback on invalid language tags (#22306)
Locale::lookup() and locale_lookup() should not return the fallback locale when canonicalizing a language tag fails. Returning the fallback hid the intl error raised by lookup_loc_range() for invalid language tags. Return NULL in that error case instead, while preserving the exception path when intl.use_exceptions is enabled. Closes #22306
1 parent 35fde02 commit 4efca40

3 files changed

Lines changed: 51 additions & 4 deletions

File tree

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ PHP NEWS
4848
for invalid display types. (Weilin Du)
4949
. Fixed Spoofchecker restriction-level APIs to only be exposed with ICU 53
5050
and later. (Graham Campbell)
51+
. Fixed Locale::lookup() and locale_lookup() to return NULL instead of the
52+
fallback locale when a language tag cannot be canonicalized. (Weilin Du)
5153

5254
- mysqli:
5355
. Fix stmt->query leak in mysqli_execute_query() validation errors.

ext/intl/locale/locale_methods.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1435,14 +1435,15 @@ static zend_string* lookup_loc_range(const char* loc_range, HashTable* hash_arr,
14351435
zend_argument_type_error(2, "must only contain string values");
14361436
LOOKUP_CLEAN_RETURN(NULL);
14371437
}
1438-
cur_arr[cur_arr_len*2] = estrndup(Z_STRVAL_P(ele_value), Z_STRLEN_P(ele_value));
1439-
result = strToMatch(Z_STRVAL_P(ele_value), cur_arr[cur_arr_len*2]);
1438+
i = cur_arr_len*2;
1439+
cur_arr[i] = estrndup(Z_STRVAL_P(ele_value), Z_STRLEN_P(ele_value));
1440+
cur_arr_len++;
1441+
result = strToMatch(Z_STRVAL_P(ele_value), cur_arr[i]);
14401442
if(result == 0) {
14411443
intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "lookup_loc_range: unable to canonicalize lang_tag", 0);
14421444
LOOKUP_CLEAN_RETURN(NULL);
14431445
}
1444-
cur_arr[cur_arr_len*2+1] = Z_STRVAL_P(ele_value);
1445-
cur_arr_len++ ;
1446+
cur_arr[i+1] = Z_STRVAL_P(ele_value);
14461447
} ZEND_HASH_FOREACH_END(); /* end of for */
14471448

14481449
/* Canonicalize array elements */
@@ -1562,6 +1563,15 @@ PHP_FUNCTION(locale_lookup)
15621563
}
15631564

15641565
result_str = lookup_loc_range(loc_range, hash_arr, boolCanonical);
1566+
if (EG(exception)) {
1567+
RETURN_THROWS();
1568+
}
1569+
if (U_FAILURE(intl_error_get_code(NULL))) {
1570+
if (result_str) {
1571+
zend_string_release_ex(result_str, 0);
1572+
}
1573+
RETURN_NULL();
1574+
}
15651575
if(result_str == NULL || ZSTR_VAL(result_str)[0] == '\0') {
15661576
if( fallback_loc_str ) {
15671577
result_str = zend_string_copy(fallback_loc_str);
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
--TEST--
2+
Locale::lookup() returns null for invalid language tags
3+
--EXTENSIONS--
4+
intl
5+
--FILE--
6+
<?php
7+
8+
var_dump(Locale::lookup([''], 'de-DE', false, 'en-US'));
9+
var_dump(intl_get_error_message());
10+
11+
var_dump(locale_lookup([''], 'de-DE', false, 'en-US'));
12+
var_dump(intl_get_error_message());
13+
14+
ini_set('intl.use_exceptions', '1');
15+
16+
try {
17+
Locale::lookup([''], 'de-DE', false, 'en-US');
18+
} catch (IntlException $e) {
19+
echo $e->getMessage(), PHP_EOL;
20+
}
21+
22+
try {
23+
locale_lookup([''], 'de-DE', false, 'en-US');
24+
} catch (IntlException $e) {
25+
echo $e->getMessage(), PHP_EOL;
26+
}
27+
28+
?>
29+
--EXPECT--
30+
NULL
31+
string(75) "lookup_loc_range: unable to canonicalize lang_tag: U_ILLEGAL_ARGUMENT_ERROR"
32+
NULL
33+
string(75) "lookup_loc_range: unable to canonicalize lang_tag: U_ILLEGAL_ARGUMENT_ERROR"
34+
lookup_loc_range: unable to canonicalize lang_tag
35+
lookup_loc_range: unable to canonicalize lang_tag

0 commit comments

Comments
 (0)