PHP Session 預設壽命約 24 分鐘(由 session.gc_maxlifetime=1440 決定),但實際過期機制涉及垃圾回收(GC)機率,行為常不如預期。本文系統整理 Session 過期的三種控制層級,並提供生產環境建議設定。
在程式碼中記錄「最後活動時間」,逾期即銷毀 Session。不依賴 PHP 內建 GC,完全可控。
<?php
session_start();
// 設定閒置逾期秒數(例:30 分鐘)
$idle_limit = 1800;
if (isset($_SESSION['last_activity']) && (time() - $_SESSION['last_activity'] > $idle_limit)) {
// 逾期:銷毀舊 session
session_unset();
session_destroy();
session_start(); // 重新開始新 session
}
// 更新最後活動時間
$_SESSION['last_activity'] = time();
// 登出時手動銷毀
// unset($_SESSION['last_activity']); session_destroy();
優點:精確控制、不受 GC 機率影響、可針對不同使用者/角色設定不同逾期。
缺點:需在每個入口點(或共用引入檔)執行。
; php.ini
session.gc_maxlifetime = 86400 ; 86400 秒 = 24 小時
session.gc_probability = 1
session.gc_divisor = 100 ; GC 機率 = 1/100 = 1%
關鍵提醒:
session.save_path,gc_maxlifetime 以最小值為準,會互相影響。將 Session 存入 Redis、Database,自行實作 gc($maxlifetime) 介面,精確刪除過期資料。
class RedisSessionHandler implements SessionHandlerInterface {
private $redis;
public function __construct() { $this->redis = new Redis(); $this->redis->connect('127.0.0.1'); }
public function open($savePath, $sessionName) { return true; }
public function close() { return true; }
public function read($id) { return $this->redis->get("session:$id") ?: ''; }
public function write($id, $data) { return $this->redis->setex("session:$id", 86400, $data); }
public function destroy($id) { return $this->redis->del("session:$id"); }
public function gc($maxlifetime) { return true; } // Redis 自動過期,無需掃描
}
session_set_save_handler(new RedisSessionHandler(), true);
session_start();
此法解決分散式部署共享 Session、精確過期、效能最佳三大問題,強烈推薦生產環境採用。
設為 1/1 會讓每請求都掃描 Session 目錄,嚴重拖慢效能,絕不建議。
session.save_path = "2;/tmp/php_sessions" ; 建立 2 層子目錄,分散檔案,提升檔案系統效能
# 每天凌晨 3 點清理超過 24 小時未存取的 session 檔
0 3 * * * find /var/lib/php/sessions -type f -cmin +1440 -delete
| 場景 | 建議方案 |
|---|---|
| 單機、流量中低、需求簡單 | 層級一(程式碼驗證)+ php.ini 調大 gc_maxlifetime |
| 多機負載平衡、需共享 Session | 層級三(Redis/Memcached Save Handler) |
| 嚴格合規、需審計登入紀錄 | 層級三 + 資料庫儲存 + 自訂 gc 邏輯 |