核心機制對比
| 方式 | 存儲位置 | 生命週期 | 容量 | 安全性 | 適用場景 |
| Session | 服務端 (文件/Redis/DB) | 瀏覽器關閉/過期 | 無硬性限制 | 高 (ID 在 Cookie) | 用戶登入態、購物車、權限 |
| Cookie | 客戶端瀏覽器 | 設置過期時間 | 4KB/域 | 低 (可被竊取/篡改) | 記住我、偏好設定、追蹤 |
| 表單隱藏域 | 頁面 HTML | 單次請求 | 無限制 | 低 (可見/可改) | 多步表單、CSRF Token |
| URL 參數 (GET) | 地址欄 | 單次請求 | ~2KB (瀏覽器限制) | 低 (可見/記錄在日誌) | 分頁、搜索、分享鏈接 |
| 資料庫/快取 | 服務端持久化 | 業務定義 | 大 | 高 | 跨設備、長期、大數據 |
| JWT Token | 客戶端 (Header) | 設置過期 | ~8KB (Header 限制) | 簽名驗證、無狀態 | API 鑑權、單點登入、微服務 |
實戰代碼範例
1. Session (推薦:用戶狀態)
<?php
// page_a.php - 設置
session_start();
$_SESSION['user'] = ['id' => 1, 'name' => '張三'];
header('Location: page_b.php');
// page_b.php - 讀取
session_start();
if (isset($_SESSION['user'])) {
echo "歡迎,{$_SESSION['user']['name']}";
}
// 跨標籤/窗口共享:默認同瀏覽器進程共享 Cookie
// 若需新窗口獨立:session_name('UNIQUE_NAME') 区分
2. Cookie (推薦:持久化偏好)
<?php
// 設置 (需在輸出前)
setcookie('pref_theme', 'dark', [
'expires' => time() + 86400 * 30, // 30天
'path' => '/',
'domain' => '', // 當前域
'secure' => true, // 僅 HTTPS
'httponly' => true, // 防 JS 讀取
'samesite' => 'Lax', // CSRF 保護
]);
// 讀取
$theme = $_COOKIE['pref_theme'] ?? 'light';
3. 表單隱藏域 (多步向導)
<!-- step1.php -->
<form action="step2.php" method="post">
<input type="hidden" name="step1_data" value="<?= htmlspecialchars(json_encode($data)) ?>">
<input type="submit" value="下一步">
</form>
<!-- step2.php -->
<?php
$data = json_decode($_POST['step1_data'], true);
4. URL 參數 (分享/SEO)
<?php
// 生成帶參數鏈接
$url = 'detail.php?' . http_build_query([
'id' => 123,
'source' => 'newsletter',
'utm_campaign' => 'summer_sale',
]);
echo "<a href='$url'>查看詳情</a>";
// 接收
$id = (int)($_GET['id'] ?? 0);
現代最佳實踐:API 無狀態鑑權 (JWT)
<?php
// 登入成功簽發 Token
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
$payload = [
'iss' => 'myapp',
'aud' => 'api',
'iat' => time(),
'exp' => time() + 3600,
'uid' => 123,
'roles' => ['user'],
];
$jwt = JWT::encode($payload, $privateKey, 'RS256'); // 非對稱加密更安全
// 返回給客戶端:Authorization: Bearer $jwt
// 中間件驗證
$token = explode(' ', $request->header('Authorization'))[1] ?? '';
try {
$decoded = JWT::decode($token, new Key($publicKey, 'RS256'));
$request->userId = $decoded->uid;
} catch (\Exception $e) {
return response()->json(['code' => 401, 'msg' => 'Token 無效'])->send();
}
安全鐵律
- ✅ 敏感數據 (ID、權限、金額) 僅存 Session/DB,絕不放 Cookie/URL/隱藏域
- ✅ Cookie 設置
HttpOnly、Secure、SameSite
- ✅ Session ID 定期輪換
session_regenerate_id(true) (登入/權限變更後)
- ✅ 所有用戶輸入經驗證/過濾後再使用
- ✅ HTTPS 全站強制執行
避坑指南
- Session 丟失
- 檢查
session.save_path 寫入權限、session.cookie_domain 匹配、session.gc_maxlifetime 足夠大、集群環境未共享存儲
- Cookie 不生效
- 設置代碼在輸出之後、域名/路徑不匹配、瀏覽器隱私模式阻擋、
SameSite=Strict 導致跨站不攜帶
- 中文亂碼
- URL 參數用
urlencode()/urldecode(),Cookie 值用 json_encode() 序列化