From f514f5a12ef0c34853b5370ef55d630b499f977d Mon Sep 17 00:00:00 2001 From: billz Date: Sat, 21 Jun 2025 01:19:17 -0700 Subject: [PATCH] Sanitize user input w/ $validLocales, add detectBrowserLocale() --- includes/locale.php | 148 +++++++++++++++++--------------------------- 1 file changed, 58 insertions(+), 90 deletions(-) diff --git a/includes/locale.php b/includes/locale.php index 9f83b5a6..17ab03e5 100755 --- a/includes/locale.php +++ b/includes/locale.php @@ -1,107 +1,43 @@ = 2) { - $lang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2); - switch ($lang) { - case "de": - $locale = "de_DE.UTF-8"; - break; - case "fr": - $locale = "fr_FR.UTF-8"; - break; - case "it": - $locale = "it_IT.UTF-8"; - break; - case "pt": - $locale = "pt_BR.UTF-8"; - break; - case "sv": - $locale = "sv_SE.UTF-8"; - break; - case "nl": - $locale = "nl_NL.UTF-8"; - break; - case "zh": - if ($_SERVER['HTTP_ACCEPT_LANGUAGE'] == 'zh_TW') { - $locale = "zh_TW.UTF-8"; - } else { - $locale = "zh_CN.UTF-8"; - } - break; - case "cs": - $locale = "cs_CZ.UTF-8"; - break; - case "ru": - $locale = "ru_RU.UTF-8"; - break; - case "es": - $locale = "es_MX.UTF-8"; - break; - case "fi": - $locale = "fi_FI.UTF-8"; - break; - case "da": - $locale = "da_DK.UTF-8"; - break; - case "tr": - $locale = "tr_TR.UTF-8"; - break; - case "id": - $locale = "id_ID.UTF-8"; - break; - case "ko": - $locale = "ko_KR.UTF-8"; - break; - case "ja": - $locale = "ja_JP.UTF-8"; - break; - case "vi": - $locale = "vi_VN.UTF-8"; - break; - case "el": - $locale = "el_GR.UTF-8"; - break; - case "pl": - $locale = "pl_PL.UTF-8"; - break; - case "sk": - $locale = "sk_SK.UTF-8"; - break; - default: - $locale = "en_GB.UTF-8"; - break; - } - $_SESSION['locale'] = $locale; +// Set locale from POST, if provided and valid +$validLocales = array_keys(getLocales()); +if (!empty($_POST['locale']) && in_array($_POST['locale'], $validLocales, true)) { + $_SESSION['locale'] = $_POST['locale']; } -// Note: the associated locale must be installed on the RPi -// Use: 'sudo raspi-configure' and select 'Localisation Options' - -// activate the locale setting -if (!empty($_SESSION['locale'])) { - putenv("LANG=" . $_SESSION['locale']); - setlocale(LC_ALL, $_SESSION['locale']); +// Set locale from browser detection, if not already set +if (empty($_SESSION['locale'])) { + $_SESSION['locale'] = detectBrowserLocale(); } + +// Enforce only valid locale values in session +if (!in_array($_SESSION['locale'], $validLocales, true)) { + $_SESSION['locale'] = 'en_GB.UTF-8'; +} + +// Apply locale settings +putenv("LANG=" . escapeshellarg($_SESSION['locale'])); +setlocale(LC_ALL, $_SESSION['locale']); bindtextdomain(LOCALE_DOMAIN, LOCALE_ROOT); bind_textdomain_codeset(LOCALE_DOMAIN, 'UTF-8'); - textdomain(LOCALE_DOMAIN); -function getLocales() +function getLocales(): array { - $arrLocales = array( + return [ 'en_GB.UTF-8' => 'English', 'cs_CZ.UTF-8' => 'Čeština', 'zh_TW.UTF-8' => '正體中文 (Chinese traditional)', @@ -125,6 +61,38 @@ function getLocales() 'sv_SE.UTF-8' => 'Svenska', 'tr_TR.UTF-8' => 'Türkçe', 'vi_VN.UTF-8' => 'Tiếng Việt (Vietnamese)' - ); - return $arrLocales; + ]; } + +function detectBrowserLocale(): string +{ + if (empty($_SERVER['HTTP_ACCEPT_LANGUAGE']) || strlen($_SERVER['HTTP_ACCEPT_LANGUAGE']) < 2) { + return 'en_GB.UTF-8'; + } + + $lang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2); + return match ($lang) { + 'de' => 'de_DE.UTF-8', + 'fr' => 'fr_FR.UTF-8', + 'it' => 'it_IT.UTF-8', + 'pt' => 'pt_BR.UTF-8', + 'sv' => 'sv_SE.UTF-8', + 'nl' => 'nl_NL.UTF-8', + 'zh' => ($_SERVER['HTTP_ACCEPT_LANGUAGE'] === 'zh_TW') ? 'zh_TW.UTF-8' : 'zh_CN.UTF-8', + 'cs' => 'cs_CZ.UTF-8', + 'ru' => 'ru_RU.UTF-8', + 'es' => 'es_MX.UTF-8', + 'fi' => 'fi_FI.UTF-8', + 'da' => 'da_DK.UTF-8', + 'tr' => 'tr_TR.UTF-8', + 'id' => 'id_ID.UTF-8', + 'ko' => 'ko_KR.UTF-8', + 'ja' => 'ja_JP.UTF-8', + 'vi' => 'vi_VN.UTF-8', + 'el' => 'el_GR.UTF-8', + 'pl' => 'pl_PL.UTF-8', + 'sk' => 'sk_SK.UTF-8', + default => 'en_GB.UTF-8', + }; +} +