首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 用戶語言偵測與切換類 UserLang:支援 Cookie 持久化與 Accept-Language 回退

     編輯:PHP 綜合知識

功能需求

  • 優先讀取 Cookie 儲存的語言偏好。
  • 無 Cookie 時解析 HTTP_ACCEPT_LANGUAGE 標頭。
  • 支援手動切換語言並寫入 Cookie (預設 30 天)。
  • 輸出標準化語言代碼 (en, zh-CN, zh-TW) 供模板/翻譯系統使用。

核心類別 (UserLang.class.php)

<?php
class UserLang {
    private $name = 'userlang';
    private $expire = 2592000; // 30 天
    private $default = 'zh-CN';
    private $supported = ['en', 'zh-CN', 'zh-TW'];

    public function __construct(array $config = []) {
        $this->name = $config['name'] ?? $this->name;
        $this->expire = $config['expire'] ?? $this->expire;
        $this->default = $config['default'] ?? $this->default;
        $this->supported = $config['supported'] ?? $this->supported;
    }

    public function get() {
        // 1. Cookie
        if (isset($_COOKIE[$this->name])) {
            $lang = $_COOKIE[$this->name];
            if (in_array($lang, $this->supported)) return $lang;
        }
        // 2. Accept-Language
        $accept = $this->getAcceptLanguage();
        if ($accept) return $accept;
        // 3. Default
        return $this->default;
    }

    public function set($lang) {
        if (!in_array($lang, $this->supported)) return false;
        setcookie($this->name, $lang, time() + $this->expire, '/', '', false, true); // HttpOnly, Secure (需 HTTPS)
        return true;
    }

    private function getAcceptLanguage() {
        if (empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])) return null;
        $langs = [];
        foreach (explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']) as $part) {
            $part = trim($part);
            $q = 1.0;
            if (preg_match('/(.*);\s*q=([0-9.]+)/', $part, $m)) {
                $part = $m[1]; $q = (float)$m[2];
            }
            $code = strtolower(substr($part, 0, 2)); // 取語言代碼
            // 映射到支援列表 (簡單示例)
            $map = ['zh' => 'zh-CN', 'en' => 'en'];
            if (isset($map[$code]) && in_array($map[$code], $this->supported)) {
                $langs[$map[$code]] = $q;
            }
        }
        if (!$langs) return null;
        arsort($langs);
        return array_key_first($langs);
    }
}

使用範例

<?php
require 'UserLang.class.php';
$lang = new UserLang(['supported' => ['en','zh-CN','zh-TW','ja']]);

// 顯示語言切換連結
$current = $lang->get();
echo "當前語言: $current <br>";
foreach (['en','zh-CN','zh-TW','ja'] as $l) {
    echo "<a href='?lang=$l'>$l</a> ";
}

// 處理切換
if (isset($_GET['lang'])) {
    $lang->set($_GET['lang']);
    header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));
    exit;
}

// 載入對應翻譯檔
$trans = include "lang/{$current}.php";
echo $trans['welcome'];

Accept-Language 解析細節

標頭範例:zh-CN,zh;q=0.9,en;q=0.8,en-US;q=0.7

  • 按 , 分割,每段可含 ;q=權重 (預設 1.0)。
  • 取語言代碼前綴 (如 zh, en) 映射至支援列表。
  • 按權重排序,取最高者。

安全與最佳實踐

  • setcookie 設定 HttpOnly=true、Secure=true (僅 HTTPS)、SameSite=Lax。
  • 語言代碼嚴格白名單驗證,防止注入任意值導致 include 任意檔案 (LFI)。
  • 生產環境建議使用成熟 i18n 庫 (symfony/translation, gettext) 管理翻譯資源。

結語

UserLang 以 Cookie 優先、Accept-Language 回退、白名單驗證的策略,提供輕量級多語言偵測與切換能力。核心邏輯 <30 行,易於整合至任何 PHP 專案,為後續翻譯系統奠定基礎。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved