summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristoph M. Becker <cmbecker69@gmx.de>2019-04-30 16:10:04 +0200
committerChristoph M. Becker <cmbecker69@gmx.de>2019-06-11 08:42:32 +0200
commitf3ff72e54b2f6c2fa1ac924ad95455a5309099d5 (patch)
tree6717ebfa30359b2d99f256b41b4e1635d1c6fb4a
parent199eb2b110aa57c423bada077f6c9e71c5d17daf (diff)
downloadphp-git-f3ff72e54b2f6c2fa1ac924ad95455a5309099d5.tar.gz
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>.
-rw-r--r--NEWS1
-rw-r--r--ext/standard/string.c21
-rw-r--r--ext/standard/tests/strings/setlocale-win32.phpt25
3 files changed, 47 insertions, 0 deletions
diff --git a/NEWS b/NEWS
index 1b7e493d19..4da0c146fc 100644
--- a/NEWS
+++ b/NEWS
@@ -27,6 +27,7 @@ PHP NEWS
- Standard:
. Fixed bug #77135 (Extract with EXTR_SKIP should skip $this).
(Craig Duncan, Dmitry)
+ . Fixed bug ##77937 (preg_match failed). (cmb, Anatol)
- Zip:
. Fixed bug #76345 (zip.h not found). (Michael Maroszek)
diff --git a/ext/standard/string.c b/ext/standard/string.c
index ce90848561..2907c2253b 100644
--- a/ext/standard/string.c
+++ b/ext/standard/string.c
@@ -4513,7 +4513,28 @@ PHP_FUNCTION(setlocale)
}
}
+# ifndef PHP_WIN32
retval = php_my_setlocale(cat, loc ? ZSTR_VAL(loc) : NULL);
+# else
+ if (loc) {
+ /* BC: don't try /^[a-z]{2}_[A-Z]{2}($|\..*)/ except for /^u[ks]_U[KS]$/ */
+ char *locp = ZSTR_VAL(loc);
+ if (ZSTR_LEN(loc) >= 5 && locp[2] == '_'
+ && locp[0] >= 'a' && locp[0] <= 'z' && locp[1] >= 'a' && locp[1] <= 'z'
+ && locp[3] >= 'A' && locp[3] <= 'Z' && locp[4] >= 'A' && locp[4] <= 'Z'
+ && (locp[5] == '\0' || locp[5] == '.')
+ && !(locp[0] == 'u' && (locp[1] == 'k' || locp[1] == 's')
+ && locp[3] == 'U' && (locp[4] == 'K' || locp[4] == 'S')
+ && locp[5] == '\0')
+ ) {
+ retval = NULL;
+ } else {
+ retval = php_my_setlocale(cat, ZSTR_VAL(loc));
+ }
+ } else {
+ retval = php_my_setlocale(cat, NULL);
+ }
+# endif
zend_update_current_locale();
if (retval) {
if (loc) {
diff --git a/ext/standard/tests/strings/setlocale-win32.phpt b/ext/standard/tests/strings/setlocale-win32.phpt
new file mode 100644
index 0000000000..fcfbce3579
--- /dev/null
+++ b/ext/standard/tests/strings/setlocale-win32.phpt
@@ -0,0 +1,25 @@
+--TEST--
+Unix locale names are rejected on Windows, except for some special cases
+--SKIPIF--
+<?php
+if (substr(PHP_OS, 0, 3) != 'WIN') die('skip this test is for Windows platforms only');
+?>
+--FILE--
+<?php
+var_dump(setlocale(LC_ALL, 'de_DE'));
+var_dump(setlocale(LC_ALL, 'de_DE.UTF-8'));
+// the following are supposed to be accepted
+var_dump(setlocale(LC_ALL, 'uk_UK'));
+var_dump(setlocale(LC_ALL, 'uk_US'));
+var_dump(setlocale(LC_ALL, 'us_UK'));
+var_dump(setlocale(LC_ALL, 'us_US'));
+?>
+===DONE===
+--EXPECT--
+bool(false)
+bool(false)
+string(27) "English_United Kingdom.1252"
+string(26) "English_United States.1252"
+string(27) "English_United Kingdom.1252"
+string(26) "English_United States.1252"
+===DONE===