簡體   English   中英

如何在 PHP 中更改會話超時?

[英]How to change the session timeout in PHP?

我想在 php 中延長會話超時時間

我知道可以通過修改 php.ini 文件來做到這一點。 但我無權訪問它。

那么是否可以僅使用 php 代碼來完成?

如果你想要嚴格的保證,會話超時是一個必須在代碼中實現的概念; 這是您可以絕對確定在 X 分鍾不活動后沒有會話將繼續存在的唯一方法

如果稍微放寬這個要求是可以接受的,並且您可以設置下限而不是對持續時間的嚴格限制,那么您可以輕松做到這一點,而無需編寫自定義邏輯。

輕松環境中的便利:如何以及為什么

如果您的會話是使用 cookie(它們可能是)實現的,並且如果客戶端不是惡意的,您可以通過調整某些參數來設置會話持續時間的上限。 如果您使用 PHP 的默認會話處理 cookie,設置session.gc_maxlifetimesession_set_cookie_params應該像這樣為您工作:

// server should keep session data for AT LEAST 1 hour
ini_set('session.gc_maxlifetime', 3600);

// each client should remember their session id for EXACTLY 1 hour
session_set_cookie_params(3600);

session_start(); // ready to go!

這是通過配置服務器將會話數據保留至少一小時不活動並指示您的客戶端在同一時間跨度后他們應該“忘記”他們的會話 ID 來實現的。 這兩個步驟都是達到預期結果所必需的。

  • 如果您在一小時后不告訴客戶端忘記他們的會話 ID(或者如果客戶端是惡意的並選擇忽略您的指令),他們將繼續使用相同的會話 ID,其有效持續時間將是不確定的。 那是因為在服務器端已經過期的會話不會立即被垃圾收集,而只是在會話 GC 開始時才會被回收。

    GC 是一個潛在的昂貴過程,因此通常概率相當小甚至為零(獲得大量點擊的網站可能會完全放棄概率 GC 並安排它每 X 分鍾在后台發生一次)。 在這兩種情況下(假設非合作客戶端),有效會話生存期的下限都是session.gc_maxlifetime ,但上限是不可預測的。

  • 如果您沒有將session.gc_maxlifetime設置為相同的時間跨度,那么服務器可能會在此之前丟棄空閑會話數據; 在這種情況下,仍然記得其會話 ID 的客戶端將顯示它,但服務器將找不到與該會話相關的數據,有效地表現得好像會話剛剛開始一樣。

關鍵環境中的確定性

您可以通過使用自定義邏輯來設置會話不活動的上限,從而使事情完全可控; 加上上面的下限,這導致了嚴格的設置。

通過將上限與其余會話數據一起保存來執行此操作:

session_start(); // ready to go!

$now = time();
if (isset($_SESSION['discard_after']) && $now > $_SESSION['discard_after']) {
    // this session has worn out its welcome; kill it and start a brand new one
    session_unset();
    session_destroy();
    session_start();
}

// either new or old, it should live at most for another hour
$_SESSION['discard_after'] = $now + 3600;

會話 ID 持久化

到目前為止,我們根本沒有關心每個會話 id 的確切值,只關心數據應該在我們需要的時候存在的要求。 請注意,在(不太可能)會話 ID 對您很重要的情況下,必須注意在需要時使用session_regenerate_id重新生成它們。

如果您使用 PHP 的默認會話處理,在所有平台上可靠地更改會話持續時間的唯一方法是更改php.ini 這是因為在某些平台中,垃圾收集是通過每隔特定時間運行的腳本( cron腳本)實現的,該腳本直接從php.ini讀取,因此任何在運行時更改它的嘗試ini_set()例如通過ini_set()都是不可靠的並且很可能不起作用。

例如,在 Debian Linux 系統中,通過在配置中默認設置session.gc_probability=0來禁用 PHP 的內部垃圾收集,而是通過 /etc/cron.d/php 完成,它在 XX:09 和 XX 運行: 39(即每半小時一次)。 此 cron 作業查找早於配置中指定的session.gc_maxlifetime 的會話,如果找到,則將其刪除。 因此,在這些系統中, ini_set('session.gc_maxlifetime', ...)被忽略。 這也解釋了為什么在這個問題中: PHP 會話超時太快,OP 在一台主機上出現問題,但在切換到另一台主機時問題停止了。

因此,鑒於您無權訪問php.ini ,如果您想以可移植的方式執行此操作,則不能選擇使用默認會話處理。 顯然,延長 cookie 生命周期對於您的主機來說已經足夠了,但是如果您想要一個即使切換主機也能可靠運行的解決方案,則必須使用不同的替代方案。

可用的替代方法包括:

  1. 在 PHP 中設置不同的會話(保存)處理程序以將您的會話保存在不同的目錄或數據庫中,如PHP 中所述:自定義會話處理程序(PHP 手冊) ,以便cron作業不會到達它,只有 PHP 的發生內部垃圾收集。 此選項可能可以使用ini_set()來設置session.gc_maxlifetime但我更喜歡忽略gc()回調中的maxlifetime參數並自行確定最大生命周期。

  2. 完全忘記 PHP 內部會話處理並實現您自己的會話管理。 這種方法有兩個主要缺點:您將需要自己的全局會話變量,因此失去了$_SESSION超全局變量的優勢,並且它需要更多代碼,因此存在更多錯誤和安全漏洞的機會。 最重要的是,會話標識符應該從加密安全的隨機數或偽隨機數中生成,以避免會話 ID 的可預測性(導致可能的會話劫持),而 PHP 可移植性地做到這一點並不容易。 主要優點是它可以在所有平台上一致地工作,並且您可以完全控制代碼。 這就是phpBB論壇軟件(至少版本 1;我不確定更新的版本)所采用的方法。

session_set_save_handler()文檔中有 (1) 的示例。 該示例很長,但我將在此處重現它,並進行必要的相關修改以延長會話持續時間。 請注意包含session_set_cookie_params()以增加 cookie 的生命周期。

<?php
class FileSessionHandler
{

    private $savePath;
    private $lifetime;

    function open($savePath, $sessionName)
    {
        $this->savePath = 'my_savepath'; // Ignore savepath and use our own to keep it safe from automatic GC
        $this->lifetime = 3600; // 1 hour minimum session duration
        if (!is_dir($this->savePath)) {
            mkdir($this->savePath, 0777);
        }

        return true;
    }

    function close()
    {
        return true;
    }

    function read($id)
    {
        return (string)@file_get_contents("$this->savePath/sess_$id");
    }

    function write($id, $data)
    {
        return file_put_contents("$this->savePath/sess_$id", $data) === false ? false : true;
    }

    function destroy($id)
    {
        $file = "$this->savePath/sess_$id";
        if (file_exists($file)) {
            unlink($file);
        }

        return true;
    }

    function gc($maxlifetime)
    {
        foreach (glob("$this->savePath/sess_*") as $file) {
            if (filemtime($file) + $this->lifetime < time() && file_exists($file)) { // Use our own lifetime
                unlink($file);
            }
        }

        return true;
    }
}

$handler = new FileSessionHandler();
session_set_save_handler(
    array($handler, 'open'),
    array($handler, 'close'),
    array($handler, 'read'),
    array($handler, 'write'),
    array($handler, 'destroy'),
    array($handler, 'gc')
    );

// the following prevents unexpected effects when using objects as save handlers
register_shutdown_function('session_write_close');

session_set_cookie_params(3600); // Set session cookie duration to 1 hour
session_start();
// proceed to set and retrieve values by key from $_SESSION

方法(2)比較復雜; 基本上,您必須自己重新實現所有會話功能。 我不會在這里詳細介紹。

只是一個共享托管服務器的通知或添加到域=

要使您的設置php_value session.save_path folderA/sessionsA您必須使用php_value session.save_path folderA/sessionsA為添加的域設置不同的保存會話目錄。

所以創建一個文件夾到你的根服務器,不要進入public_html ,也不要從外部公開訪問。 對於我的 cpanel/服務器,文件夾權限0700工作正常。 試一下...

# Session timeout, 2628000 sec = 1 month, 604800 = 1 week, 57600 = 16 hours, 86400 = 1 day
ini_set('session.save_path', '/home/server/.folderA_sessionsA');
ini_set('session.gc_maxlifetime', 57600); 
ini_set('session.cookie_lifetime', 57600);
# session.cache_expire is in minutes unlike the other settings above         
ini_set('session.cache_expire', 960);
ini_set('session.name', 'MyDomainA');

session_start();之前session_start();

或者把它放在你的.htaccess文件中。

php_value session.save_path /home/server/.folderA_sessionsA
php_value session.gc_maxlifetime 57600
php_value session.cookie_lifetime 57600
php_value session.cache_expire 57600
php_value session.name MyDomainA

經過多次研究和測試,這適用於共享 cpanel/php7 服務器。 非常感謝: NoiS

為任何使用 Plesk 的人添加任何上述任何問題的評論,因為這讓我發瘋,從您的 PHP 腳本設置 session.gc_maxlifetime 將不起作用,因為 Plesk 有它自己的垃圾收集腳本從 cron 運行。

我使用了以下鏈接中發布的解決方案,將 cron 作業從每小時移動到每天以避免此問題,然后上面的最佳答案應該有效:

mv /etc/cron.hourly/plesk-php-cleanuper /etc/cron.daily/

https://websavers.ca/plesk-php-sessions-timing-earlier-expected

$_SESSION['login_time'] = time(); 進入上一個認證頁面。 並且在您想要檢查會話超時的每個其他頁面中剪下下面的內容。

if(time() - $_SESSION['login_time'] >= 1800){
    session_destroy(); // destroy session.
    header("Location: logout.php");
    die(); // See https://thedailywtf.com/articles/WellIntentioned-Destruction
    //redirect if the page is inactive for 30 minutes
}
else {        
   $_SESSION['login_time'] = time();
   // update 'login_time' to the last time a page containing this code was accessed.
}

編輯:這僅適用於您已經在其他帖子中使用過調整或禁用垃圾收集,並且想要手動檢查會話持續時間的情況。 不要忘記在重定向后添加die() ,因為某些腳本/機器人可能會忽略它。 此外,使用session_destroy()直接銷毀會話而不是依賴重定向可能是更好的選擇,同樣,在惡意客戶端或機器人的情況下。

不可以。如果您無權訪問 php.ini,則不能保證更改會產生任何效果。

我懷疑你需要延長你的會議時間。
目前它有相當合理的超時時間,沒有理由延長它。

您可以使用ini_set()從 PHP 代碼覆蓋 php.ini 中的值。

暫無
暫無

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

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