PHP 預設將 Session 資料儲存在伺服器暫存目錄(session.save_path),但實務上常需自訂儲存位置、格式,甚至改用資料庫、Redis、Memcached。本文示範如何透過 session_set_save_handler() 註冊六個回呼函數,打造一個**檔案型自訂 Session Handler**,並說明各回呼的職責與關鍵細節。
session_save_path(),若包含 ;(如 N;/path 表示分層),需解析實際路徑。open、close、read、write、destroy、gc(垃圾回收)。session_set_save_handler() 註冊,再 session_start() 啟用。<?php
// 1. 解析真實儲存路徑
$sessionpath = session_save_path();
if (strpos($sessionpath, ';') !== false) {
$sessionpath = substr($sessionpath, strpos($sessionpath, ';') + 1);
}
// 2. 定義回呼函數(使用全域變數保存路徑與名稱)
function open($save_path, $session_name) {
global $sess_save_path, $sess_session_name;
$sess_save_path = $save_path;
$sess_session_name = $session_name;
return true;
}
function close() { return true; }
function read($id) {
global $sess_save_path;
$sess_file = "$sess_save_path/sess_$id";
if ($fp = @fopen($sess_file, 'r')) {
$data = fread($fp, filesize($sess_file));
fclose($fp);
return $data;
}
return ''; // 必須回傳空字串,不可回傳 false
}
function write($id, $sess_data) {
global $sess_save_path;
$sess_file = "$sess_save_path/sess_$id";
if ($fp = @fopen($sess_file, 'w')) {
$ret = fwrite($fp, $sess_data);
fclose($fp);
return $ret;
}
return false;
}
function destroy($id) {
global $sess_save_path;
$sess_file = "$sess_save_path/sess_$id";
return @unlink($sess_file);
}
function gc($maxlifetime) {
// 檔案型通常由系統 cron 清理,這裡直接回傳 true
return true;
}
// 3. 註冊並啟動
session_set_save_handler('open', 'close', 'read', 'write', 'destroy', 'gc');
session_start();
// 之後即可正常使用 $_SESSION
$_SESSION['user'] = 'demo';
?>
'',不可回傳 false 或 null,否則 PHP 會視為資料損毀並重新產生 Session ID。int),失敗回傳 false。session.gc_probability / session.gc_divisor 機率觸發;檔案型建議改用系統 cron 定期刪除過期 sess_* 檔案,效能更佳。redis 或資料庫支援原子操作的 Handler。SessionHandlerInterface 並傳遞物件實例給 session_set_save_handler(),程式碼更結構化。read/write 改為 Redis::get/set,並用 EXPIRE 實作 gc。openssl_encrypt)保護敏感 Session 資料。掌握自訂 Session Handler,即可靈活掌控 Session 儲存策略,滿足分散式部署、安全合規與效能優化等進階需求。