From f3ff72e54b2f6c2fa1ac924ad95455a5309099d5 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Tue, 30 Apr 2019 16:10:04 +0200 Subject: 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 . --- NEWS | 1 + ext/standard/string.c | 21 +++++++++++++++++++++ ext/standard/tests/strings/setlocale-win32.phpt | 25 +++++++++++++++++++++++++ 3 files changed, 47 insertions(+) create mode 100644 ext/standard/tests/strings/setlocale-win32.phpt 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-- + +--FILE-- + +===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=== -- cgit v1.2.1