| 特性 | Cookie | Session |
|---|---|---|
| 儲存位置 | 客戶端瀏覽器 | 伺服器端(檔案/資料庫/Redis) |
| 安全性 | 可被竄改、側錄、XSS 竊取 | 用戶無法直接修改,相對安全 |
| 容量限制 | 單餅乾 4KB、域名約 20-50 個 | 伺服器磁碟/記憶體限制,幾乎無上限 |
| 傳輸開銷 | 每請求自動攜帶(含靜態資源) | 僅傳 Session ID(Cookie/URL),體積極小 |
| 跨域共享 | 需設定 Domain/Path | 需共用儲存介質(Redis/DB) |
session_start():啟動/恢復會話,讀取或建立 Session ID$_SESSION 超全域陣列) 123,
'username' => 'john',
'role' => 'admin',
'login_at' => time(),
];
// 3. 讀取
if (isset($_SESSION['user'])) {
echo "歡迎,{$_SESSION['user']['username']}";
}
// 4. 刪除單一鍵
unset($_SESSION['user']['role']);
// 5. 完全銷毀(登出)
session_unset(); // 清空 $_SESSION
session_destroy(); // 刪除伺服器端儲存檔案
// 建議同步刪除客戶端 Cookie
if (ini_get('session.use_cookies')) {
$params = session_get_cookie_params();
setcookie(session_name(), '', time() - 42000, $params['path'], $params['domain'], $params['secure'], $params['httponly']);
}
?>
prepare("SELECT id, username, password_hash FROM users WHERE username=?");
$stmt->execute([$username]);
$user = $stmt->fetch();
if ($user && password_verify($password, $user['password_hash'])) {
// 2. 登入成功:重新生成 Session ID(防 Session Fixation)
session_regenerate_id(true);
// 3. 寫入必要資訊
$_SESSION['user_id'] = $user['id'];
$_SESSION['username'] = $user['username'];
$_SESSION['last_activity'] = time();
header('Location: dashboard.php');
exit;
}
$error = '帳號或密碼錯誤';
}
// 顯示登入表單...
?>
1800) {
session_unset();
session_destroy();
header('Location: login.php?timeout=1');
exit;
}
$_SESSION['last_activity'] = time();
// 正常顯示內容...
?>
Session ID 會自動附加在 URL:?PHPSESSID=abc123。需啟用 session.use_trans_sid=1(php.ini)或手動傳遞。安全風險極高(URL 洩漏、快取、書籤),生產環境**強烈不建議**,應要求啟用 Cookie。
pdo = $pdo; }
public function open($savePath, $sessionName) { return true; }
public function close() { return true; }
public function read($id) {
$stmt = $this->pdo->prepare("SELECT data FROM sessions WHERE id=? AND expiry>?");
$stmt->execute([$id, time()]);
return $stmt->fetchColumn() ?: '';
}
public function write($id, $data) {
$expiry = time() + ini_get('session.gc_maxlifetime');
$stmt = $this->pdo->prepare("INSERT INTO sessions (id,data,expiry) VALUES (?,?,?) ON DUPLICATE KEY UPDATE data=?,expiry=?");
return $stmt->execute([$id, $data, $expiry, $data, $expiry]);
}
public function destroy($id) {
$this->pdo->prepare("DELETE FROM sessions WHERE id=?")->execute([$id]);
return true;
}
public function gc($maxlifetime) {
$this->pdo->prepare("DELETE FROM sessions WHERE expiry")->execute([time()]);
return true;
}
}
// 註冊
$handler = new DbSessionHandler($pdo);
session_set_save_handler($handler, true);
session_start();
?>
name"; } } session_start(); $user = new User(); $user->id = 1; $user->name = 'Alice'; $_SESSION['user_obj'] = $user; // 自動 serialize() // 下一請求自動 unserialize() // 需確保類別定義已載入(autoload),否則會變成 __PHP_Incomplete_Class // 解決:spl_autoload_register 或 session 開始前 require 類別檔 ?>
Secure、HttpOnly、SameSite=Strictsession_regenerate_id(true) 防 Session Fixationlast_activity,配合 session.gc_maxlifetimeuser_id、role,敏感資料查 DBsession.gc_probability/gc_divisor 控制 GC 頻率Session 是 PHP 有狀態開發的基石。掌握啟動時機、生命週期控制、儲存驅動切換、安全防護四大核心,即可從簡單登入延伸至分散式系統的 Session 共享架構。現代專案建議直接使用框架封裝(Laravel session()、Symfony SessionInterface),專注業務邏輯。