Cookie 是 Web 應用實現會話追蹤、用戶偏好記錄、單點登入的核心機制。PHP 通過 setcookie() 發送 Set-Cookie 響應頭,$_COOKIE 超全局變量自動解析請求頭。本文全面覆蓋 Cookie 生命周期管理、登錄態實現、安全屬性與最佳實踐。
Set-Cookie 頭發送Cookie 頭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',
]);
<?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 保護
]);
?>
<?php
// 單個讀取
$userToken = $_COOKIE['auth_token'] ?? null;
// 判斷是否存在
if (isset($_COOKIE['user_id'])) {
echo "歡迎回來,用戶 {$_COOKIE['user_id']}";
} else {
echo "訪客模式";
}
// 調試:查看所有 Cookie
print_r($_COOKIE);
?>
<?php
// 必須與設置時 path、domain、secure、httponly 完全一致
setcookie('auth_token', '', [
'expires' => time() - 3600, // 過去時間
'path' => '/',
'domain' => '.example.com',
'secure' => true,
'httponly' => true,
'samesite' => 'Lax',
]);
?>
避免明文存儲用戶 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 |
Strict:完全禁止跨站攜帶(含鏈接跳轉)Lax:允許鏈接跳轉、GET 表單攜帶,阻止 POST/iframe/圖片請求None:所有跨站請求攜帶,**必須配合 Secure=true**<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>
setcookie() 前不能有任何輸出(含 BOM、空白、echo)$_COOKIE 反映的是請求頭,剛設置的 Cookie 需下次請求才可讀取.example.com 覆蓋 www 和所有子域;設置 example.com 現代瀏覽器同樣覆蓋子域Cookie 是無狀態 HTTP 的狀態延伸。專業 PHP 開發者需掌握:
setcookie() 完整參數控制(特別是選項陣列語法)Domain=.example.com 機制配合 Session(服務端存儲)與 JWT(無狀態 Token),構建分層會話管理體系,是現代 PHP 應用認證授權的標準架構。