From 455bff5c1703a71dfe25c2d066c06e88eb4280a8 Mon Sep 17 00:00:00 2001 From: Naoto Kobayashi Date: Sun, 14 Nov 2021 00:58:36 +0900 Subject: [PATCH 1/6] Fix missing setlocale with php 8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When php version = 8, basename('§') does not bug even if LC_ALL is non-UTF-8 locale. This cause OC_Util::isSetLocaleWorking() to skip setlocale("C.UTF-8"). Fix it by using escapeshellcmd instead of basename. Signed-off-by: Naoto Kobayashi --- lib/private/legacy/OC_Util.php | 4 ++-- tests/lib/UtilTest.php | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/private/legacy/OC_Util.php b/lib/private/legacy/OC_Util.php index 35c81dd34e6e5..94fcb900898cf 100644 --- a/lib/private/legacy/OC_Util.php +++ b/lib/private/legacy/OC_Util.php @@ -1245,14 +1245,14 @@ public function isHtaccessWorking(\OCP\IConfig $config) { * @return bool */ public static function isSetLocaleWorking() { - if ('' === basename('§')) { + if ('' === escapeshellcmd('§')) { // Borrowed from \Patchwork\Utf8\Bootup::initLocale setlocale(LC_ALL, 'C.UTF-8', 'C'); setlocale(LC_CTYPE, 'en_US.UTF-8', 'fr_FR.UTF-8', 'es_ES.UTF-8', 'de_DE.UTF-8', 'ru_RU.UTF-8', 'pt_BR.UTF-8', 'it_IT.UTF-8', 'ja_JP.UTF-8', 'zh_CN.UTF-8', '0'); } // Check again - if ('' === basename('§')) { + if ('' === escapeshellcmd('§')) { return false; } return true; diff --git a/tests/lib/UtilTest.php b/tests/lib/UtilTest.php index 04d4858fb26d4..b9c791735bbfb 100644 --- a/tests/lib/UtilTest.php +++ b/tests/lib/UtilTest.php @@ -74,6 +74,14 @@ public function testEncodePath() { $this->assertEquals("/%C2%A7%23%40test%25%26%5E%C3%A4/-child", $result); } + public function testIsSetLocaleWorking() { + // OC_Util::isSetLocaleWorking() assumes escapeshellcmd('§') returns '' with non-UTF-8 locale. + $locale = setlocale(LC_CTYPE, 0); + setlocale(LC_CTYPE, 'C'); + $this->assertEquals('', escapeshellcmd('§')); + setlocale(LC_CTYPE, $locale); + } + public function testFileInfoLoaded() { $expected = function_exists('finfo_open'); $this->assertEquals($expected, \OC_Util::fileInfoLoaded()); From d2eb5aaa6ddbdd3fbbf6ba871f04398038eddcb2 Mon Sep 17 00:00:00 2001 From: Naoto Kobayashi Date: Sun, 14 Nov 2021 08:25:32 +0900 Subject: [PATCH 2/6] Check whether setlocale works only after setlocale Signed-off-by: Naoto Kobayashi --- lib/private/legacy/OC_Util.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/private/legacy/OC_Util.php b/lib/private/legacy/OC_Util.php index 94fcb900898cf..75c337f8baa96 100644 --- a/lib/private/legacy/OC_Util.php +++ b/lib/private/legacy/OC_Util.php @@ -1249,12 +1249,13 @@ public static function isSetLocaleWorking() { // Borrowed from \Patchwork\Utf8\Bootup::initLocale setlocale(LC_ALL, 'C.UTF-8', 'C'); setlocale(LC_CTYPE, 'en_US.UTF-8', 'fr_FR.UTF-8', 'es_ES.UTF-8', 'de_DE.UTF-8', 'ru_RU.UTF-8', 'pt_BR.UTF-8', 'it_IT.UTF-8', 'ja_JP.UTF-8', 'zh_CN.UTF-8', '0'); - } - // Check again - if ('' === escapeshellcmd('§')) { - return false; + // Check again + if ('' === escapeshellcmd('§')) { + return false; + } } + return true; } From 25f15f86a98c737f4847f6e861d809ffe104eedd Mon Sep 17 00:00:00 2001 From: Naoto Kobayashi Date: Mon, 15 Nov 2021 18:33:50 +0900 Subject: [PATCH 3/6] Add check whether escapeshellcmd behaves the same as basename Signed-off-by: Naoto Kobayashi --- tests/lib/UtilTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/lib/UtilTest.php b/tests/lib/UtilTest.php index b9c791735bbfb..65147ed52c9d3 100644 --- a/tests/lib/UtilTest.php +++ b/tests/lib/UtilTest.php @@ -79,6 +79,8 @@ public function testIsSetLocaleWorking() { $locale = setlocale(LC_CTYPE, 0); setlocale(LC_CTYPE, 'C'); $this->assertEquals('', escapeshellcmd('§')); + setlocale(LC_CTYPE, 'C.UTF-8'); + $this->assertEquals('§', escapeshellcmd('§')); setlocale(LC_CTYPE, $locale); } From e9b414fbe39eea609c5cfdfb0266527977495802 Mon Sep 17 00:00:00 2001 From: Naoto Kobayashi Date: Tue, 16 Nov 2021 00:40:52 +0900 Subject: [PATCH 4/6] OC_Util: Add fallbacks to check if current locale is UTF8 Using escapeshellcmd to get current locale causes error if the function is disabled. Add fallbacks to prevent the error. Signed-off-by: Naoto Kobayashi --- lib/private/legacy/OC_Util.php | 19 +++++++++++++++++-- tests/lib/UtilTest.php | 6 ++++-- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/lib/private/legacy/OC_Util.php b/lib/private/legacy/OC_Util.php index 75c337f8baa96..ff9a3bb1af79b 100644 --- a/lib/private/legacy/OC_Util.php +++ b/lib/private/legacy/OC_Util.php @@ -1238,6 +1238,21 @@ public function isHtaccessWorking(\OCP\IConfig $config) { return $content !== $testContent && $fallbackContent !== $testContent; } + /** + * Check if current locale is non-UTF8 + * + * @return bool + */ + private static function isNonUTF8Locale() { + if (function_exists("escapeshellcmd")) { + return ('' === escapeshellcmd('§')); + } else if (function_exists("escapeshellarg")) { + return ('\'\'' === escapeshellarg('§')); + } else { + return (0 === preg_match('/utf-?8/i', setlocale(LC_CTYPE, 0))); + } + } + /** * Check if the setlocal call does not work. This can happen if the right * local packages are not available on the server. @@ -1245,13 +1260,13 @@ public function isHtaccessWorking(\OCP\IConfig $config) { * @return bool */ public static function isSetLocaleWorking() { - if ('' === escapeshellcmd('§')) { + if (self::isNonUTF8Locale()) { // Borrowed from \Patchwork\Utf8\Bootup::initLocale setlocale(LC_ALL, 'C.UTF-8', 'C'); setlocale(LC_CTYPE, 'en_US.UTF-8', 'fr_FR.UTF-8', 'es_ES.UTF-8', 'de_DE.UTF-8', 'ru_RU.UTF-8', 'pt_BR.UTF-8', 'it_IT.UTF-8', 'ja_JP.UTF-8', 'zh_CN.UTF-8', '0'); // Check again - if ('' === escapeshellcmd('§')) { + if (self::isNonUTF8Locale()) { return false; } } diff --git a/tests/lib/UtilTest.php b/tests/lib/UtilTest.php index 65147ed52c9d3..bb328c5998d25 100644 --- a/tests/lib/UtilTest.php +++ b/tests/lib/UtilTest.php @@ -74,13 +74,15 @@ public function testEncodePath() { $this->assertEquals("/%C2%A7%23%40test%25%26%5E%C3%A4/-child", $result); } - public function testIsSetLocaleWorking() { - // OC_Util::isSetLocaleWorking() assumes escapeshellcmd('§') returns '' with non-UTF-8 locale. + public function testIsNonUTF8Locale() { + // OC_Util::isNonUTF8Locale() assumes escapeshellcmd('§') returns '' with non-UTF-8 locale. $locale = setlocale(LC_CTYPE, 0); setlocale(LC_CTYPE, 'C'); $this->assertEquals('', escapeshellcmd('§')); + $this->assertEquals('\'\'', escapeshellarg('§')); setlocale(LC_CTYPE, 'C.UTF-8'); $this->assertEquals('§', escapeshellcmd('§')); + $this->assertEquals('\'§\'', escapeshellarg('§')); setlocale(LC_CTYPE, $locale); } From c42c972ab0a79c2c19db569d352e54a2f1b7ea2d Mon Sep 17 00:00:00 2001 From: Naoto Kobayashi Date: Tue, 16 Nov 2021 00:46:21 +0900 Subject: [PATCH 5/6] OC_Util::isSetLocaleWorking: fix typo Signed-off-by: Naoto Kobayashi --- lib/private/legacy/OC_Util.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/private/legacy/OC_Util.php b/lib/private/legacy/OC_Util.php index ff9a3bb1af79b..757e220223c26 100644 --- a/lib/private/legacy/OC_Util.php +++ b/lib/private/legacy/OC_Util.php @@ -1254,7 +1254,7 @@ private static function isNonUTF8Locale() { } /** - * Check if the setlocal call does not work. This can happen if the right + * Check if the setlocale call does not work. This can happen if the right * local packages are not available on the server. * * @return bool From 6fc86943244e8acc88a0f742a5f406adb100ee1a Mon Sep 17 00:00:00 2001 From: Naoto Kobayashi Date: Tue, 16 Nov 2021 21:05:43 +0900 Subject: [PATCH 6/6] OC_Util::isNonUTF8Locale: fix lint error Signed-off-by: Naoto Kobayashi --- lib/private/legacy/OC_Util.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/private/legacy/OC_Util.php b/lib/private/legacy/OC_Util.php index 757e220223c26..078e3cf9a03f2 100644 --- a/lib/private/legacy/OC_Util.php +++ b/lib/private/legacy/OC_Util.php @@ -1244,12 +1244,12 @@ public function isHtaccessWorking(\OCP\IConfig $config) { * @return bool */ private static function isNonUTF8Locale() { - if (function_exists("escapeshellcmd")) { - return ('' === escapeshellcmd('§')); - } else if (function_exists("escapeshellarg")) { - return ('\'\'' === escapeshellarg('§')); + if (function_exists('escapeshellcmd')) { + return '' === escapeshellcmd('§'); + } elseif (function_exists('escapeshellarg')) { + return '\'\'' === escapeshellarg('§'); } else { - return (0 === preg_match('/utf-?8/i', setlocale(LC_CTYPE, 0))); + return 0 === preg_match('/utf-?8/i', setlocale(LC_CTYPE, 0)); } }