Ubuntu 中 PHP Session 過期時間無法自訂的問題

Written by Simon Asika on

file

有自己在 Ubuntu 或 Debian 系統上開發 PHP 的人應該會發現,自己寫的會員登入 Remember Me 好像都無法作用。明明 Session 與 Cookie 時間都設的非常長了,卻還是會自動過期。

這是因為 Debian 會覆蓋 PHP 本身的 session.gc_maxlifetime 造成的。如果我們今天採用原生的 Session 處理機制,預設會把 session 資料存在 /var/lib/php5 裡面。

但在 Debian 中,PHP 的 session.gc_probability 被設成 0,意味著 Session 垃圾回收永遠不會進行,取而代之的是 Debian 自行設定的 Cronjob 來清除過期 Sessions,它的位置在: /etc/cron.d/php5

# /etc/cron.d/php5: crontab fragment for php5
#  This purges session files older than X, where X is defined in seconds
#  as the largest value of session.gc_maxlifetime from all your php.ini
#  files, or 24 minutes if not defined.  See /usr/lib/php5/maxlifetime

# Look for and purge old sessions every 30 minutes
09,39 *     * * *     root   [ -x /usr/lib/php5/maxlifetime ] && [ -x /usr/lib/php5/sessionclean ] && [ -d /var/lib/php5 ] && /usr/lib/php5/sessionclean /var/lib/php5 $(/usr/lib/php5/maxlifetime)

由此可知,Debian 會每 30 分鐘清除一次 session(原生 php 的session過期時間是24分鐘),所以我們怎麼設定過期時間都是無效的。

解決方法

解決方法也不難,調整 php.ini 設定並把 cronjob 移除掉即可。不過我一向主張程式設計師不應該依賴環境設定,如果能夠由我們自己的程式在 Runtime 時覆蓋是最好的。

處理方式是重新打開 php 的 session 垃圾回收,並將 session 轉移到我們自己設定的目錄儲存,以避開 Debian 的自定清除。程式碼如下,加入在你的系統的啟動環境中即可:

// 把 session 的生命週期調到你想要的時間
ini_set('session.gc_maxlifetime', 864000);

// 打開垃圾回收,1 表示有 1% 的機會進行垃圾回收
ini_set('session.gc_probability', 1);
ini_set('session.gc_divisor', 100);

// 設定自己的 session path 以避開 Debian 的自動清除
session_save_path(PATH_ROOT . '/sessions');

// 都設定好之後再啟動 session
session_start();

另外,改用 Database 或其他非原生 php session 儲存方案也是方法之一。

參考資源

PHP sessions timeout too soon, no matter how you set session.gc_maxlifetime

Control Tools

WS-logo