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

Oli*_*Oli 142 php session session-timeout

我想在php中扩展会话超时

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

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

Jon*_*Jon 302

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

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

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

如果您的会话与饼干(他们可能是)来实现,并且如果客户端是没有恶意的,你可以通过调整某些参数设置会话持续时间的上限.如果您使用的是带有饼干PHP的默认会话处理,设置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!
Run Code Online (Sandbox Code Playgroud)

这可以通过配置服务器来保持会话数据至少一小时不活动,并指示您的客户在相同的时间跨度后"忘记"他们的会话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;
Run Code Online (Sandbox Code Playgroud)

会话ID持久性

到目前为止,我们并没有完全关注每个会话id的确切值,只要要求数据应该存在,只要我们需要它们.请注意,在(不太可能)会话ID对您很重要的情况下,必须注意session_regenerate_id在需要时重新生成它们.


Ped*_*eno 32

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

例如,在Debian Linux系统中,垃圾收集是通过/etc/cron.d/php5完成的,它在XX:09和XX:39(即每半小时)运行,如果它找到的会话早于会话php.ini中指定的.gc_maxlifetime,然后该会话被删除而没有任何怜悯.这也解释了为什么在这个问题中:PHP会话超时太快,OP在一台主机上出现问题,但是当切换到另一台主机时问题就停止了.

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

可用的替代方法包括:

  1. 在PHP中设置一个不同的会话(保存)处理程序,将会话保存在不同的目录或数据库中,如PHP中所指定的:自定义会话处理程序(PHP手册),以便cron作业无法访问它,只有PHP的内部垃圾收集发生.这个选项可能可以session.gc_probability=0用来设置session.gc_maxlifetime,但我更喜欢忽略回调中的maxlifetime参数,ini_set('session.gc_maxlifetime', ...)并自己确定最大生命周期.

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

文档中gc()有一个(1)的例子.这个例子很长,但我会在这里重现它,并进行必要的相关修改以延长会话持续时间.请注意包含$_SESSION以增加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
Run Code Online (Sandbox Code Playgroud)

方法(2)更复杂; 基本上,您必须自己重新实现所有会话功能.我不会在这里详述.


小智 13

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

为了使您的设置生效,您必须使用不同的保存会话目录来添加域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');
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

经过多次研究和测试,这对于共享 cpanel/php7 服务器来说效果很好。非常感谢:NoiS