如何在PHP中更改会话超时?

2022-08-30 06:34:58

我想在php中延长会话超时

我知道可以通过修改php.ini文件来做到这一点。但是我无法访问它。

那么是否可以仅使用php代码来执行此操作?


答案 1

会话超时是一个概念,如果你想要严格的保证,必须在代码中实现;这是您可以绝对确定在X分钟不活动后没有会话存活的唯一方法

如果稍微放宽此要求是可以接受的,并且您可以设置下限而不是对持续时间进行严格的限制,则可以轻松执行此操作,而无需编写自定义逻辑。

轻松环境中的便利性:如何以及为何

如果您的会话是使用 Cookie 实现的(它们可能是),并且客户端不是恶意的,则可以通过调整某些参数来设置会话持续时间的上限。如果您将 PHP 的默认会话处理与 cookie 一起使用,则设置session.gc_maxlifetime以及session_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

  • 如果未设置为相同的时间跨度,则服务器可能会更早地丢弃空闲会话数据;在这种情况下,仍然记得其会话ID的客户端将显示它,但服务器不会找到与该会话关联的数据,有效地表现得好像会话刚刚启动一样。session.gc_maxlifetime

关键环境中的确定性

您可以通过使用自定义逻辑对会话不活动设置上限来使事情完全可控;再加上上面的下限,这会导致严格的设置。

为此,请将上限与会话数据的其余部分一起保存:

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


答案 2

如果使用 PHP 的默认会话处理,则在所有平台中可靠地更改会话持续时间的唯一方法是更改 php.ini。这是因为在某些平台中,垃圾回收是通过每隔一段时间运行的脚本(直接从php.ini读取的cron脚本)实现的,因此在运行时更改它的任何尝试,例如通过,都是不可靠的,很可能不起作用。ini_set()

例如,在 Debian Linux 系统中,PHP 的内部垃圾回收通过配置中的默认设置被禁用,而是通过 /etc/cron.d/php 完成,该垃圾回收在 XX:09 和 XX:39 运行(即每半小时一次)。此 cron 作业查找早于配置中指定的session.gc_maxlifetime会话,如果找到任何会话,则将其删除。因此,在这些系统中被忽略。这也解释了为什么在这个问题中:PHP会话超时太快,OP在一个主机中出现问题,但是当切换到另一个主机时问题停止了。session.gc_probability=0ini_set('session.gc_maxlifetime', ...)

因此,鉴于您无权访问php.ini,如果您想以可移植的方式执行此操作,则使用默认会话处理不是一种选择。显然,延长cookie生存期对于您的主机来说已经足够了,但是如果您想要一个即使切换主机也能可靠地工作的解决方案,则必须使用其他替代方案。

可用的替代方法包括:

  1. 在 PHP 中设置不同的会话(保存)处理程序,以将会话保存在不同的目录或数据库中,如 PHP:自定义会话处理程序(PHP 手册)中所指定,以便 cron 作业不会到达它,并且只进行 PHP 的内部垃圾回收。此选项可能可以用来设置session.gc_maxlifetime但我更喜欢忽略回调中的maxlifetime参数,并自行确定最大生存期。ini_set()gc()

  2. 完全忘记PHP内部会话处理,实现自己的会话管理。这种方法有两个主要缺点:您将需要自己的全局会话变量,因此您失去了超全局的优势,并且它需要更多的代码,因此有更多的机会出现错误和安全漏洞。最重要的是,会话标识符应该由加密安全的随机或伪随机数生成,以避免会话ID的可预测性(导致可能的会话劫持),而这在PHP移植上并不容易。主要优点是它将在所有平台上一致地工作,并且您可以完全控制代码。这是例如phpBB论坛软件(至少版本1;我不确定是否有更新的版本)。$_SESSION

session_set_save_handler() 的文档中有一个 (1) 的示例。该示例很长,但我会在此处重现它,并进行必要的相关修改以延长会话持续时间。请注意,包含 以增加 Cookie 生存期。session_set_cookie_params()

<?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)比较复杂;基本上,您必须自己重新实现所有会话功能。我不会在这里详细介绍。


推荐