Skip to content

Commit f3ff72e

Browse files
committed
Fix #77937: preg_match failed
On some recent Windows systems, ext\pcre\tests\locales.phpt fails, because 'pt_PT' is accepted by `setlocale()`, but not properly supported by the ctype functions, which are used internally by PCRE2 to build the localized character tables. Since there appears to be no way to properly check whether a given locale is fully supported, but we want to minimize BC impact, we filter out typical Unix locale names, except for a few cases which have already been properly supported on Windows. This way code like setlocale(LC_ALL, 'de_DE.UTF-8', 'de_DE', 'German_Germany.1252'); should work like on older Windows systems. It should be noted that the locale names causing trouble are not (yet) documented as valid names anyway, see <https://docs.microsoft.com/en-us/cpp/c-runtime-library/locale-names-languages-and-country-region-strings?view=vs-2019>.
1 parent 199eb2b commit f3ff72e

File tree

3 files changed

+47
-0
lines changed

3 files changed

+47
-0
lines changed

NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ PHP NEWS
2727
- Standard:
2828
. Fixed bug #77135 (Extract with EXTR_SKIP should skip $this).
2929
(Craig Duncan, Dmitry)
30+
. Fixed bug ##77937 (preg_match failed). (cmb, Anatol)
3031

3132
- Zip:
3233
. Fixed bug #76345 (zip.h not found). (Michael Maroszek)

ext/standard/string.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4513,7 +4513,28 @@ PHP_FUNCTION(setlocale)
45134513
}
45144514
}
45154515

4516+
# ifndef PHP_WIN32
45164517
retval = php_my_setlocale(cat, loc ? ZSTR_VAL(loc) : NULL);
4518+
# else
4519+
if (loc) {
4520+
/* BC: don't try /^[a-z]{2}_[A-Z]{2}($|\..*)/ except for /^u[ks]_U[KS]$/ */
4521+
char *locp = ZSTR_VAL(loc);
4522+
if (ZSTR_LEN(loc) >= 5 && locp[2] == '_'
4523+
&& locp[0] >= 'a' && locp[0] <= 'z' && locp[1] >= 'a' && locp[1] <= 'z'
4524+
&& locp[3] >= 'A' && locp[3] <= 'Z' && locp[4] >= 'A' && locp[4] <= 'Z'
4525+
&& (locp[5] == '\0' || locp[5] == '.')
4526+
&& !(locp[0] == 'u' && (locp[1] == 'k' || locp[1] == 's')
4527+
&& locp[3] == 'U' && (locp[4] == 'K' || locp[4] == 'S')
4528+
&& locp[5] == '\0')
4529+
) {
4530+
retval = NULL;
4531+
} else {
4532+
retval = php_my_setlocale(cat, ZSTR_VAL(loc));
4533+
}
4534+
} else {
4535+
retval = php_my_setlocale(cat, NULL);
4536+
}
4537+
# endif
45174538
zend_update_current_locale();
45184539
if (retval) {
45194540
if (loc) {
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
--TEST--
2+
Unix locale names are rejected on Windows, except for some special cases
3+
--SKIPIF--
4+
<?php
5+
if (substr(PHP_OS, 0, 3) != 'WIN') die('skip this test is for Windows platforms only');
6+
?>
7+
--FILE--
8+
<?php
9+
var_dump(setlocale(LC_ALL, 'de_DE'));
10+
var_dump(setlocale(LC_ALL, 'de_DE.UTF-8'));
11+
// the following are supposed to be accepted
12+
var_dump(setlocale(LC_ALL, 'uk_UK'));
13+
var_dump(setlocale(LC_ALL, 'uk_US'));
14+
var_dump(setlocale(LC_ALL, 'us_UK'));
15+
var_dump(setlocale(LC_ALL, 'us_US'));
16+
?>
17+
===DONE===
18+
--EXPECT--
19+
bool(false)
20+
bool(false)
21+
string(27) "English_United Kingdom.1252"
22+
string(26) "English_United States.1252"
23+
string(27) "English_United Kingdom.1252"
24+
string(26) "English_United States.1252"
25+
===DONE===

0 commit comments

Comments
 (0)