Session 是 Web 應用維持用戶狀態的核心機制。PHP 採用「文件存儲 + 機率性垃圾回收(GC)」的獨特設計,這與 Java、Node.js 等常駐進程模式截然不同。理解其運作原理,對於設定合理的過期時間、避免共享主機下的 Session 相互干擾、排查「明明設定 1 小時卻 24 分鐘就失效」等疑難雜症至關重要。
預設情況下,PHP 將 Session 資料序列化後寫入 /tmp 目錄(由 session.save_path 指定),檔案命名格式為 sess_<session_id>。例如:
sess_01aab840166fd1dc253e3b4a3f0b8381
檔案內容為序列化陣列:
username|s:9:"phpzixue.cn";admin|s:1:"0";
刪除該檔案即代表對應 Session 失效。
客戶端僅需保存 Session ID。兩種傳遞方式:
PHPSESSID(由 session.name 控制)index.php?PHPSESSID=01aab840166fd1dc253e3b4a3f0b8381由 session.use_cookies、session.use_only_cookies、session.use_trans_sid 控制策略。
session.gc_maxlifetime(預設 1440 秒 = 24 分鐘)定義 Session 資料的「最大生存時間」。但注意:這只是判定過期的門檻,而非精確失效時間。
每次 PHP 請求都有機率觸發 GC,機率 = session.gc_probability / session.gc_divisor。預設值:
session.gc_probability = 1 session.gc_divisor = 100 // 即 1% 機率
session.save_path 下所有 sess_* 檔案gc_maxlifetime$_SESSION,mtime 不變更,GC 會誤判為閒置而刪除定期更新 Session 內容以刷新 mtime:
<?php
if (!isset($_SESSION['last_access']) || (time() - $_SESSION['last_access']) > 60) {
$_SESSION['last_access'] = time();
}
?>
每 60 秒寫入一次,確保檔案 mtime 持續更新。
多站點共用同一 session.save_path(如預設 /tmp):
gc_maxlifetime = 7200(2 小時)導致站點 A 設定無效,且存在安全風險(其他站點可讀取 Session 檔案)。
session_save_path('/var/www/mysite/tmp/session');
確保目錄權限 700,僅當前用戶可讀寫。SessionHandlerInterface,配合 session_set_save_handler(),徹底解決檔案鎖競爭、跨機器共享、精確過期控制。session.save_path = "3;/tmp" 建立三級子目錄分散檔案,緩解單目錄性能瓶頸。| 場景 | 建議配置 |
|---|---|
| 高併發、需精確過期 | 改用 Redis + 自定義 Handler,配合 Lua 腳本原子檢查過期 |
| 單機、檔案存儲 | 獨立 save_path、提高 gc_probability(如 10/100)、定期 cron 清理 |
| 跨多台 Web Server | 必須使用共享存儲,檔案系統需支援鎖(NFS 有風險),首選 Redis/Memcached |
PHP Session 採用「機率性 GC + 檔案 mtime 判斷」的被動過期模型,gc_maxlifetime 只能保證最短生存時間。共享主機下務必隔離 save_path;高可靠場景建議遷移至資料庫/Redis 存儲並自行實現精確過期邏輯。理解這些細節,能讓你從「會用 Session」進階到「駕馭 Session」。