diff options
author | Christoph M. Becker <cmbecker69@gmx.de> | 2019-04-30 16:10:04 +0200 |
---|---|---|
committer | Christoph M. Becker <cmbecker69@gmx.de> | 2019-06-11 08:42:32 +0200 |
commit | f3ff72e54b2f6c2fa1ac924ad95455a5309099d5 (patch) | |
tree | 6717ebfa30359b2d99f256b41b4e1635d1c6fb4a | |
parent | 199eb2b110aa57c423bada077f6c9e71c5d17daf (diff) | |
download | php-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-- | NEWS | 1 | ||||
-rw-r--r-- | ext/standard/string.c | 21 | ||||
-rw-r--r-- | ext/standard/tests/strings/setlocale-win32.phpt | 25 |
3 files changed, 47 insertions, 0 deletions
@@ -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=== |