客服系統需求:人員長時間待機不操作,Session 不得過期強制登出。預設 PHP Session 24 分鐘 (1440 秒) 無活動即失效,關閉瀏覽器 Cookie 即銷毀。
; php.ini
session.use_cookies = 1
session.cookie_lifetime = 31536000 ; 1 年 (秒)
session.gc_maxlifetime = 31536000 ; 1 年 (秒)
; 重啟 Apache/PHP-FPM 生效
原理:cookie_lifetime 讓瀏覽器保留 Session ID Cookie 1 年;gc_maxlifetime 讓伺服器端 Session 檔案保留 1 年。GC (垃圾回收) 機率預設 1/1000,長期有效。
<?php
// 每支腳本最開頭 (或 bootstrap) 執行
session_start();
// 1. 設定伺服器端 Session 存活時間 (秒)
ini_set('session.gc_maxlifetime', 31536000); // 1 年
// 2. 設定 Cookie 存活時間,並覆蓋預設路徑 '/'
$lifetime = 31536000;
session_set_cookie_params($lifetime, '/'); // PHP 5.2+ 可用
// 3. 關鍵:手動重新發送 Cookie,更新 Expire 時間
// session_name() 取得 php.ini session.name (預設 PHPSESSID)
setcookie(session_name(), session_id(), time() + $lifetime, '/');
// 4. 可選:關閉瀏覽器關閉即銷毀 (session.cookie_lifetime=0 行為)
ini_set('session.cookie_lifetime', (string)$lifetime);
?>
預設 files handler 受限於單機、GC 不精確。實作 SessionHandlerInterface 存入 MySQL/Redis:
<?php
class DbSessionHandler implements SessionHandlerInterface
{
private $pdo;
public function __construct(PDO $pdo) { $this->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() + (int)ini_get('session.gc_maxlifetime');
$stmt = $this->pdo->prepare("
INSERT INTO sessions (id, data, expiry) VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE data = VALUES(data), expiry = VALUES(expiry)
");
return $stmt->execute([$id, $data, $expiry]);
}
public function destroy($id) {
return $this->pdo->prepare("DELETE FROM sessions WHERE id = ?")->execute([$id]);
}
public function gc($maxlifetime) {
return $this->pdo->prepare("DELETE FROM sessions WHERE expiry < ?")->execute([time()]);
}
}
// 註冊
$handler = new DbSessionHandler($pdo);
session_set_save_handler($handler, true); // true = 關閉舊 handler
session_start();
?>
資料表結構:
CREATE TABLE sessions (
id VARCHAR(128) PRIMARY KEY,
data TEXT NOT NULL,
expiry INT UNSIGNED NOT NULL,
INDEX idx_expiry (expiry)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
session_regenerate_id(true) 產生新 ID。session.cookie_secure = 1、session.cookie_httponly = 1、session.use_only_cookies = 1。ini_set + setcookie 覆蓋。