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

问题描述 投票:136回答:6

我想在php中扩展会话超时

我知道可以通过修改php.ini文件来实现。但我无法访问它。

那么有可能只用PHP代码吗?

php session session-timeout
6个回答
295
投票

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

如果放宽这个要求有一点是可以接受的,你可以放置一个下限而不是严格的持续时间限制,你可以轻松地这样做,而无需编写自定义逻辑。

轻松环境中的便利:方式和原因

如果您的会话使用cookie(它们可能是)实现,并且客户端不是恶意的,您可以通过调整某些参数来设置会话持续时间的上限。如果你使用PHP的PHP默认会话处理,设置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,并且其有效持续时间将是不确定的。这是因为服务器端的生命周期已过期的会话不会立即被垃圾收集,而只会被whenever the session GC kicks in收集。 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重新生成它们。


29
投票

如果您使用PHP的默认会话处理,在所有平台中可靠地更改会话持续时间的唯一方法是更改​​php.ini。这是因为在某些平台上,垃圾收集是通过每隔一定时间运行的脚本(一个cron脚本)实现的,该脚本直接从php.ini读取,因此任何尝试在运行时更改它,例如通过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 sessions timing out too quickly,OP在一个主机上遇到了问题,但是当切换到另一个主机时问题就停止了。

因此,鉴于您无法访问php.ini,如果您想以便携式方式进行操作,则无法使用默认会话处理。显然,延长cookie的生命周期对于您的主机来说已经足够了,但如果您想要一个即使切换主机也能可靠运行的解决方案,您必须使用不同的替代方案。

可用的替代方法包括:

  1. 在PHP中设置一个不同的会话(保存)处理程序,以便将会话保存在PHP: Custom Session Handlers (PHP manual)中指定的不同目录或数据库中,以便cron作业无法到达它,并且只进行PHP的内部垃圾收集。这个选项可能可以使用ini_set()来设置session.gc_maxlifetime但我更喜欢忽略我的gc()回调中的maxlifetime参数并自己决定最大生命周期。
  2. 完全忘记PHP内部会话处理并实现自己的会话管理。这种方法有两个主要缺点:你需要自己的全局会话变量,所以你失去了$_SESSION超全局的优势,它需要更多的代码,因此有更多的机会容易出现bug和安全漏洞。最重要的是,会话标识符应该使用加密安全的随机或伪随机数生成,以避免会话ID可预测性(导致可能的会话劫持),并且这对于移植PHP来说并不容易。它的主要优点是它可以在所有平台上一致地工作,并且您可以完全控制代码。这是采取的方法,例如通过phpBB论坛软件(至少版本1;我不确定更新的版本)。

documentation for 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)更复杂;基本上,您必须自己重新实现所有会话功能。我不会在这里详述。


3
投票

为使用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


3
投票

$_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()直接销毁会话而不是依赖于重定向可能是更好的选择。


1
投票

不。如果您无法访问php.ini,则无法保证更改会产生任何影响。

我怀疑你需要延长你的会话时间。 目前它有非常合理的超时,没有理由延长它。


0
投票

您可以使用ini_set()从PHP代码覆盖php.ini中的值。

© www.soinside.com 2019 - 2024. All rights reserved.