2009-08-06 24 views
33

session.gc_maxlifetimesession_cache_expire()之間的實際差額是多少?PHP中的會話超時:最佳實踐

假設我希望用戶會話在非活動15分鐘後(而不是15分鐘後首次打開)無效。這其中哪一個可以幫助我?

我也知道我可以做session_set_cookie_params(),它可以設置用戶的cookie在一段時間內過期。但是,服務器端的cookie過期和實際會話過期並不相同;這是否也會在Cookie過期時刪除會話?

我的另一個解決方案是簡單的 $_SESSION['last_time'] = time() 對每個請求,並將會話與當前時間進行比較,刪除基於該會話的會話。我希望有一個更「內置」的機制來處理這個問題。

謝謝。

+0

當我就這個問題我自己的一些研究後偶然發現,一個可以對[這個計算器提問]這個問題非常透徹的答案( http://stackoverflow.com/a/1270960/474526),特別是爲什麼更新'session.gc_maxlifetime'和'session.cookie_lifetime'都不是可靠的方法。 – 2012-11-09 20:42:19

回答

39

每次session_start被稱爲會話文件時間戳(如果存在的話)被更新,用於計算是否超過了session.gc_maxlifetime。

更重要的是,在超過session.gc_maxlifetime時間後,您不能依賴會話過期。

PHP在加載當前會話後通過使用session.gc_probabilitysession.gc_divisor計算到期會話的垃圾回收,它計算垃圾回收將運行的概率。默認情況下它的概率爲1%。

如果訪問者數量較少,那麼非活動用戶可能會訪問應該過期並被刪除的會話。如果這很重要,則需要在會話中存儲時間戳並計算用戶如何記錄不活動狀態。

這個例子取代session_start和強制超時:

function my_session_start($timeout = 1440) { 
    ini_set('session.gc_maxlifetime', $timeout); 
    session_start(); 

    if (isset($_SESSION['timeout_idle']) && $_SESSION['timeout_idle'] < time()) { 
     session_destroy(); 
     session_start(); 
     session_regenerate_id(); 
     $_SESSION = array(); 
    } 

    $_SESSION['timeout_idle'] = time() + $timeout; 
} 
5

session.gc_maxlifetime基於最後一次會話文件被修改。因此,每次修改會話文件或在單獨的頁面中調用session_start()時,gc_maxlifetime的倒數重新開始並且用戶保持「登錄狀態」。這是你正在尋找的價值。你可以在你的php文件中通過ini_set()修改它,或者如果你有權訪問它,編輯php.ini

session_cache_expire()只控制HTTP「Expires」頭。該標題控制下載的頁面內容在用戶的瀏覽器緩存中保留多久。

49

我花了一些時間尋找一個很好的答案在php.ini服務器設置如何使 會話過期。我發現了很多信息,但花了一段時間才弄清楚爲什麼 設置按照他們的方式工作。如果您和我一樣,這可能對您有所幫助:

會話在服務器上存儲爲Cookie(客戶端pc上的文件)或服務器端上的文件 。兩種方法都有優點和缺點。

對於存儲在服務器上的會話,使用三個變量。

session.gc_probability合 session.gc_divisor 的session.gc_maxlifetime

(session.gc_probability合/ session.gc_divisor)產生該 垃圾收集例程將運行的概率。當垃圾收集器運行時,它會檢查至少session.gc_maxlifetime 未被訪問的會話文件並刪除它們。

這是所有在論壇的帖子解釋得很好(這其中尤其是!) - 但 下面的問題就上來:

1)如何應用這種可能性?服務器什麼時候擲骰子?

一個:服務器期間 服務器上的任何活動會話滾動骰子每次在session_start()被調用。因此,這意味着你應該看到垃圾收集 大致運行一次,每100倍的session_start()被調用 如果你有session.gc_probability合= 1和session.gc_divisor = 100

2)會發生什麼的默認在低容量的服務器上?

答:當調用session_start()時,它首先刷新會話並使 會話值可供您使用。這會更新 服務器上會話文件的時間。它然後擲骰子,如果它贏了(100分之一的機會),它會調用垃圾收集器。垃圾收集器然後檢查所有會話標識文件,並查看是否存在有資格刪除的任何 。

所以這意味着如果你是服務器上唯一的人,你的會話 永遠不會無效,它會顯示好像改變設置沒有 的效果。比方說,你的session.gc_maxlifetime更改爲10和session.gc_probability合 爲100。這意味着有100%的機率將垃圾收集器將運行,並且 將清除出那些沒有在最後10秒被訪問的任何會話文件。

如果你在服務器上只有一個,你會不會被刪除。您需要 至少有1個其他正在運行的活動會話才能處於非活動狀態。

因此,基本上,在低容量服務器上或低容量時間 - 在垃圾回收器實際運行之前,它可能會比session.gc_maxlifetime更長, 會話實際上會被刪除。並且不知道這是如何工作的,它可能會對你完全隨機出現。

3)爲什麼他們使用的概率是多少?

答:性能。在更高容量的服務器上,您不希望垃圾收集器 在session_start()的每個請求上運行。它會不必要地減慢服務器 。因此,根據您的服務器卷,您可能需要增加 或降低垃圾收集器運行的可能性。

我希望這個事情捆綁在一起你。如果你和我一樣,並且你嘗試了 會話。gc_maxlifetime,它似乎並沒有工作(因爲你在開發服務器上嘗試了 ,以免打擾任何人),那麼這個帖子 希望能爲你節省一些頭部劃痕。

祝你好運!

+3

非常豐富的答案!應該在官方的PHP文檔中。謝謝! – 2013-09-19 20:28:21

+0

非常明確的答案...但我只想指出,即使您使用PHP的默認基於文件的會話,Cookie仍會發送到用戶的瀏覽器。這是一個會話cookie(傳統上它們在關閉標籤/窗口時會過期)並且只包含它們的會話標識符。 因此,會話「問題」可能不限於服務器設置。如果用戶的瀏覽器在標籤/窗口關閉之後「記住」這個cookie,他們可能會丟失他們本來希望保留的會話。同樣,你對這個cookie的設置的搞亂可能會影響他們保持會話的能力。 – simonhamp 2015-03-25 13:25:04

+0

from http://www.appnovation.com/blog/session-garbage-collection-php ...在Debian/Ubuntu發行版中,默認情況下PHP會禁用其會話垃圾收集機制。相反,它每半小時運行一次cron作業(請參閱腳本/etc/cron.d/php5)以清除/ var/lib/php5 /目錄中的會話文件。 – renergy 2015-04-21 09:55:43

1

要檢查當前值,該代碼會有所幫助:

$gc_maxlifetime = ini_get('session.gc_maxlifetime'); 
$gc_probability = ini_get('session.gc_probability'); 
$gc_divisor  = ini_get('session.gc_divisor');