Session 是 PHP 維持使用者狀態的核心機制,正確配置 php.ini 中的 Session 參數對安全性、效能、擴展性至關重要。本文系統整理所有 Session 相關指令,附帶最佳實踐建議。
session.save_handler = files
; 預設以檔案儲存。生產環境可改為 redis、memcached、database 等:
; session.save_handler = redis
; session.save_path = "tcp://127.0.0.1:6379?auth=password"
; Windows 範例
session.save_path = "C:/php/tmp/session"
; Linux 範例
session.save_path = "/var/lib/php/session"
; 進階:多層子目錄分散檔案 (提升大量 Session 效能)
; session.save_path = "2;600;/var/lib/php/session"
; N=2 表示建立 2 層子目錄 (16x16=256 目錄);MODE=600 權限
關鍵動作:
mkdir -p /var/lib/php/session 或 C:\php\tmp\sessionchown www-data:www-data /var/lib/php/session && chmod 700 /var/lib/php/session⚠️ 若未設定或目錄不可寫,session_start() 會報錯:Failed to initialize storage module。
| 參數 | 建議值 | 說明 |
|---|---|---|
session.use_cookies | 1 | 啟用 Cookie 傳遞 Session ID (必要) |
session.use_only_cookies | 1 | 強制僅用 Cookie,防止 URL 重寫攻擊 (Session Fixation) |
session.cookie_httponly | 1 | 禁止 JavaScript 存取 Cookie (防 XSS 竊取 Session ID) |
session.cookie_secure | 1 (僅 HTTPS) | 僅在 HTTPS 傳輸 Cookie (生產環境必開) |
session.cookie_samesite | Lax 或 Strict | 防 CSRF:Lax 允許連結導航,Strict 完全阻擋跨站 |
session.name | 自訂 (如 MYAPP_SESS) | 避免預設 PHPSESSID 洩露技術棧資訊 |
| 參數 | 預設 | 建議 | 說明 |
|---|---|---|---|
session.gc_maxlifetime | 1440 (24分) | 3600 (1小時) 或業務需求 | Session 資料最大存活秒數,超過視為垃圾 |
session.cookie_lifetime | 0 | 0 (瀏覽器關閉失效) 或固定秒數 | Cookie 過期時間,0 為 Session Cookie |
session.gc_probability | 1 | 1 | 垃圾回收機率分子 |
session.gc_divisor | 1000 | 1000 | 垃圾回收機率分母 (機率 = 1/1000 = 0.1%) |
垃圾回收機制:每次 session_start() 有 gc_probability/gc_divisor 機率觸發掃描 save_path,刪除修改時間超過 gc_maxlifetime 的檔案。
⚠️ 若使用 save_path = "N;MODE;/path" 子目錄模式,**自動 GC 會失效**,需自行排程 (cron) 清理:
# 每小時清理超過 1 小時的 session 檔
0 * * * * find /var/lib/php/session -type f -cmin +60 -delete
| 參數 | 建議 | 說明 |
|---|---|---|
session.auto_start | 0 | 關閉自動啟動,由程式碼 session_start() 控制,利於效能與彈性 |
session.serialize_handler | php | 序列化處理器:php (預設)、php_binary、igbinary (需擴充、效能更好) |
session.referer_check | 留空或特定域名 | 驗證 HTTP Referer,防偽造請求 (非萬全) |
session.cache_limiter | nocache | nocache/private/public,控制 HTTP 快取行為 |
session.cache_expire | 180 | 快取過期分鐘數 (配合 cache_limiter) |
session.use_trans_sid | 0 | 關閉 URL 透明 Session ID (安全考量) |
session.sid_length | 26 | Session ID 長度 (PHP 7.1+),建議 32-48 增加熵 |
session.sid_bits_per_character | 5 | 每字元位元數:4,5,6 (6 為 a-zA-Z0-9,- 最緊湊) |
同一伺服器運行多個 PHP 應用時,必須隔離 Session 儲存路徑,否則會互相干擾甚至安全風險:
; 應用 A (httpd-vhosts.conf 或 .user.ini)
php_value session.save_path "/var/lib/php/session/app_a"
php_value session.name "APP_A_SESS"
; 應用 B
php_value session.save_path "/var/lib/php/session/app_b"
php_value session.name "APP_B_SESS"
| 現象 | 原因 | 解決 |
|---|---|---|
| session_start() 警告 "open(/tmp/sess_...) failed: Permission denied" | save_path 目錄權限不足 | chown/chmod 給 PHP 執行身分 |
| Session 資料隨機遺失 | GC 機率過高、多應用共用 save_path、磁碟滿 | 調整 gc_probability/divisor;隔離 save_path;監控磁碟 |
| 跨子域名 Session 不共享 | cookie_domain 未設定 | session.cookie_domain = ".example.com" (前綴點號) |
| HTTPS 網站 Session 無法維持 | cookie_secure=1 但開發環境用 HTTP | 開發環境設 0,或使用 mkcert 建立本地 HTTPS |
| Session ID 過長導致 URL 超過限制 | use_trans_sid=1 且 sid_length 過大 | 關閉 use_trans_sid;縮短 sid_length |
[Session]
session.save_handler = files
session.save_path = "/var/lib/php/session"
session.use_cookies = 1
session.use_only_cookies = 1
session.cookie_httponly = 1
session.cookie_secure = 1
session.cookie_samesite = Lax
session.name = MYAPP_SESS
session.auto_start = 0
session.cookie_lifetime = 0
session.cookie_path = /
session.cookie_domain = .example.com
session.serialize_handler = php
session.gc_probability = 1
session.gc_divisor = 1000
session.gc_maxlifetime = 3600
session.referer_check = https://example.com
session.cache_limiter = nocache
session.cache_expire = 180
session.use_trans_sid = 0
session.sid_length = 48
session.sid_bits_per_character = 6
<?php
// 1. 盡早啟動 (輸出前)
session_start();
// 2. 設定自訂儲存處理器 (資料庫/Redis) - 實作 SessionHandlerInterface
// ini_set('session.save_handler', 'user');
// session_set_save_handler($handler, true);
// 3. 安全:重新產生 ID 防 Session Fixation
if (!isset($_SESSION['initiated'])) {
session_regenerate_id(true);
$_SESSION['initiated'] = true;
}
// 4. 存取資料
$_SESSION['user_id'] = 12345;
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
// 5. 銷毀登出
session_unset();
session_destroy();
// 並刪除 Cookie
setcookie(session_name(), '', time() - 3600, '/', '.example.com', true, true);
?>
Session 配置看似繁瑣,但每個參數都關乎安全與效能。建議:開發環境完整啟用錯誤報告觀察行為,生產環境套用上述範本並定期審查日誌。掌握這些細節,能避免 90% 的 Session 相關疑難雜症。