簡體   English   中英

PHP 中的會話超時:最佳實踐

[英]Session timeouts in PHP: best practices

session.gc_maxlifetimesession_cache_expire()之間的實際區別是什么?

假設我希望用戶會話在 15 分鍾非活動(而不是首次打開后 15 分鍾)后無效。 其中哪一項會幫助我呢?

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

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

謝謝。

我花了一些時間尋找 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() 時,服務器都會擲骰子。 所以這意味着如果你有 session.gc_probability = 1 和 session.gc_divisor = 100 的默認值,你應該看到垃圾收集器大約每 100 次調用 session_start() 運行一次

2.) 在低容量服務器上會發生什么?

答:當 session_start() 被調用時,它首先刷新會話並使會話值對您可用。 這會更新服務器上會話文件的時間。 它然后擲骰子,如果它贏了(100 次機會中的 1 次),它會調用垃圾收集器。 垃圾收集器然后檢查所有會話 id 文件並查看是否有任何可以刪除的文件。

因此,這意味着如果您是服務器上唯一的人,您的會話將永遠不會處於非活動狀態,並且看起來好像更改設置沒有任何效果。 假設您將 session.gc_maxlifetime 更改為 10,將 session.gc_probability 更改為 100。這意味着垃圾收集器有 100% 的機會運行,並且會清除過去 10 秒內未訪問的所有會話文件。

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

所以基本上,在低容量服務器或低容量時間 - 在垃圾收集器實際運行和會話實際刪除之前,它可能比 session.gc_maxlifetime 長得多。 在不知道它是如何工作的情況下,它對您來說可能完全是隨機的。

3.) 為什么他們使用概率?

一場表演。 在更高容量的服務器上,您不希望垃圾收集器在 session_start() 的每個請求上運行。 它會不必要地減慢服務器的速度。 因此,根據您的服務器容量,您可能希望增加或減少垃圾收集器運行的概率。

我希望這能為你把事情聯系在一起。 如果您像我一樣嘗試了 session.gc_maxlifetime 並且它似乎不起作用(因為您在開發服務器上嘗試了它以免打擾任何人),那么這篇文章希望能讓您免於頭疼。

祝你好運!

每次調用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;
}

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

session_cache_expire()僅控制 HTTP “Expires”標頭。 此標頭控制下載的頁面內容在用戶瀏覽器緩存中停留的時間。

要檢查當前值,此代碼將很有幫助:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM