萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 網路程式設計 >> PHP 程式設計

PHP Cookie 完整指南:設置、讀取、刪除、登錄態管理與安全加固

Cookie 是 Web 應用實現會話追蹤、用戶偏好記錄、單點登入的核心機制。PHP 通過 setcookie() 發送 Set-Cookie 響應頭,$_COOKIE 超全局變量自動解析請求頭。本文全面覆蓋 Cookie 生命周期管理、登錄態實現、安全屬性與最佳實踐。

Cookie 基礎機制

  • 服務器通過 Set-Cookie 頭發送
  • 瀏覽器自動存儲,後續請求自動攜帶 Cookie 頭
  • 屬於域名+路徑作用域,受同源策略限制
  • 大小限制約 4KB,數量限制每域名 ~50-180 個

setcookie() 參數詳解

setcookie(
    string $name,
    string $value = "",
    int $expires_or_options = 0,
    string $path = "",
    string $domain = "",
    bool $secure = false,
    bool $httponly = false
): bool

// PHP 7.3+ 選項陣列語法(推薦)
setcookie($name, $value, [
    'expires' => time() + 86400,
    'path' => '/',
    'domain' => '.example.com',
    'secure' => true,
    'httponly' => true,
    'samesite' => 'Lax',
]);

核心操作範例

1. 設置 Cookie

<?php
// 會話級(瀏覽器關閉失效)
setcookie('lang', 'zh-CN');

// 持久化 1 小時
setcookie('theme', 'dark', time() + 3600, '/');

// 完整參數:跨子域、僅 HTTPS、防 XSS
setcookie('auth_token', $token, [
    'expires' => time() + 86400 * 30, // 30 天
    'path' => '/',
    'domain' => '.example.com',       // 共享給所有子域名
    'secure' => true,                 // 僅 HTTPS
    'httponly' => true,               // 禁止 JS 讀取
    'samesite' => 'Lax',              // CSRF 保護
]);
?>

2. 讀取 Cookie

<?php
// 單個讀取
$userToken = $_COOKIE['auth_token'] ?? null;

// 判斷是否存在
if (isset($_COOKIE['user_id'])) {
    echo "歡迎回來,用戶 {$_COOKIE['user_id']}";
} else {
    echo "訪客模式";
}

// 調試:查看所有 Cookie
print_r($_COOKIE);
?>

3. 刪除 Cookie

<?php
// 必須與設置時 path、domain、secure、httponly 完全一致
setcookie('auth_token', '', [
    'expires' => time() - 3600, // 過去時間
    'path' => '/',
    'domain' => '.example.com',
    'secure' => true,
    'httponly' => true,
    'samesite' => 'Lax',
]);
?>

登錄態管理實戰:加密 Cookie 方案

避免明文存儲用戶 ID,使用加密簽名 Cookie:

<?php
// 依賴:composer require defuse/php-encryption
use Defuse\Crypto\Crypto;
use Defuse\Crypto\Key;

$key = Key::loadFromAsciiSafeString($env['COOKIE_ENCRYPTION_KEY']); // 32 字節 Base64

function setAuthCookie(int $userId, array $claims = []): void {
    global $key;
    $payload = json_encode(array_merge(['uid' => $userId, 'iat' => time()], $claims));
    $encrypted = Crypto::encrypt($payload, $key);
    setcookie('auth', $encrypted, [
        'expires' => time() + 86400 * 14,
        'path' => '/',
        'domain' => '.example.com',
        'secure' => true,
        'httponly' => true,
        'samesite' => 'Lax',
    ]);
}

function getAuthUserId(): ?int {
    global $key;
    $cookie = $_COOKIE['auth'] ?? null;
    if (!$cookie) return null;
    try {
        $payload = Crypto::decrypt($cookie, $key);
        $data = json_decode($payload, true);
        // 可選:檢查過期時間
        if (isset($data['exp']) && $data['exp'] < time()) return null;
        return $data['uid'] ?? null;
    } catch (Exception $e) {
        return null; // 解密失敗 = 無效/被篡改
    }
}
?>

安全屬性深度解析

| 屬性 | 作用 | 建議設置 | |------|------|----------| | HttpOnly | 禁止 JavaScript document.cookie 讀取 | **true**(除非必須 JS 讀取) | | Secure | 僅 HTTPS 傳輸 | **true**(生產環境強制) | | SameSite | 控制跨站請求攜帶 | Lax(平衡體驗/安全),關鍵操作 Strict | | Domain | 作用域名範圍 | 最小權限,需跨子域才加前導點 | | Path | 作用路徑範圍 | / 或具體路徑 /api |

SameSite 詳細行為

  • Strict:完全禁止跨站攜帶(含鏈接跳轉)
  • Lax:允許鏈接跳轉、GET 表單攜帶,阻止 POST/iframe/圖片請求
  • None:所有跨站請求攜帶,**必須配合 Secure=true**

JavaScript 端操作(非 HttpOnly 時)

<script>
const Cookie = {
    get(name) {
        const m = document.cookie.match(new RegExp('(^|; )' + name + '=([^;]+)'));
        return m ? decodeURIComponent(m[2]) : null;
    },
    set(name, value, days = 30) {
        const exp = new Date(Date.now() + days * 864e5).toUTCString();
        document.cookie = `${name}=${encodeURIComponent(value)};expires=${exp};path=/;SameSite=Lax`;
    },
    remove(name) {
        this.set(name, '', -1);
    }
};

// 使用
Cookie.set('pref_lang', 'en', 365);
console.log(Cookie.get('pref_lang'));
</script>

常見坑點與避坑

  1. 輸出前調用:setcookie() 前不能有任何輸出(含 BOM、空白、echo)
  2. 當前請求不生效:$_COOKIE 反映的是請求頭,剛設置的 Cookie 需下次請求才可讀取
  3. 刪除參數必須一致:path/domain/secure/httponly 與設置時完全一致
  4. 域名匹配規則:設置 .example.com 覆蓋 www 和所有子域;設置 example.com 現代瀏覽器同樣覆蓋子域
  5. 編碼問題:值自動 urlencode/urldecode,勿雙重編碼
  6. 大小限制:單 Cookie 4KB,總數限制,勿濫用存儲大數據

總結

Cookie 是無狀態 HTTP 的狀態延伸。專業 PHP 開發者需掌握:

  • setcookie() 完整參數控制(特別是選項陣列語法)
  • 登錄態加密存儲而非明文 ID
  • HttpOnly + Secure + SameSite=Lax 鐵三角防護
  • 跨子域共享的 Domain=.example.com 機制
  • 刪除時參數精確匹配

配合 Session(服務端存儲)與 JWT(無狀態 Token),構建分層會話管理體系,是現代 PHP 應用認證授權的標準架構。

copyright © 萬盛學電腦網 all rights reserved