如何在PHP中更改会话超时时间?
在PHP中更改会话超时的方法及原因:
会话超时是一个需要在代码中实现的概念,如果您希望严格保证,这是唯一的方法,您可以绝对确定,在X分钟的不活动后,没有会话会继续存在。
如果在宽松的环境中放宽这个要求,并且您对持续时间的严格限制进行一些限制,您可以轻松地进行调整,而无需编写自定义逻辑。
在宽松的环境中的便利性:如何以及为什么
如果您的会话是通过cookie实现的(这可能是您的情况),而且客户端不是恶意的,您可以通过调整某些参数来设置会话持续时间的上限。如果您正在使用PHP的默认会话处理与cookie一起使用,那么设置session.gc_maxlifetime以及session_set_cookie_params应该可以满足您的要求,如下所示:
// 服务器至少应保留会话数据1小时
ini_set('session.gc_maxlifetime', 3600);
// 每个客户端应该记住他们的会话ID正好1小时
session_set_cookie_params(3600);
session_start(); // 准备就绪!
这是通过配置服务器在一小时的不活动时间内保留会话数据,并指示客户端在相同的时间段后“忘记”他们的会话ID来工作的。要实现预期的结果,这两个步骤都是必需的。
如果您不告诉客户端在一小时后忘记他们的会话ID(或者如果客户端是恶意的并选择忽略您的指示),他们将继续使用相同的会话ID,其有效持续时间将是不确定的。这是因为在服务器端已过期的会话只有在会话垃圾回收(session GC)启动时才会被立即清除。
GC是一个可能很昂贵的过程,所以通常概率相当小,甚至为零(一个网站获得大量点击的情况下,可能会完全放弃概率GC,并安排在后台每隔X分钟发生一次)。在这两种情况下(假设客户端不合作),会话生存时间的最小值将是session.gc_maxlifetime,但上限将是不可预测的。
如果您不将session.gc_maxlifetime设置为相同的时间段,那么服务器可能会在此之前丢弃闲置会话数据;在这种情况下,仍记得他们的会话ID的客户端将呈现它,但服务器将找不到与该会话相关联的数据,实际上会表现得像会话刚开始一样。
关键环境中的确定性
通过使用自定义逻辑还可以完全控制事物,以在会话不活动时也放置上限;与上述的下限相结合,这将得到一个严格的设置。
通过将上限与其余会话数据一起保存来实现这一点:
session_start(); // 准备就绪!
$now = time();
if (isset($_SESSION['discard_after']) && $now > $_SESSION['discard_after']) {
// 这个会话已经过期,杀死它并开始一个全新的
session_unset();
session_destroy();
session_start();
}
// 无论是新的还是旧的,它应该再活1小时
$_SESSION['discard_after'] = $now + 3600;
会话ID的持久性
到目前为止,我们对每个会话ID的具体值一直不关心,只关心数据在我们需要的时间内存在。请注意,在(不太可能的)情况下,会话ID对您很重要,必须小心在需要时使用session_regenerate_id重新生成它们。
问题:如果每分钟调用一次,会增加它的限制吗?例如,10:00我调用它,所以它的限制将是11:00,在1分钟后,10:01,限制将是11:01吗?
如果你调用什么?
这些:ini_set('session.gc_maxlifetime', 3600); session_set_cookie_params(3600);
是的,但只有在你也调用session_start()(否则根本没有效果),并且只有在你总是在session_start()之前调用这两个函数(否则gc_maxlifetime有可能影响当前打开的所有会话,而session_set_cookie_params只能影响使用当前请求开始的新会话)。
如果我再次调用session_start(),它会重置我的$_SESSION中的所有内容吗?
如果你的意思是“有潜力影响所有会话”,那么是的,如果你在调用session_start()之前总是调用那两个函数的话(否则gc_maxlifetime有影响当前打开的所有会话的潜力,而session_set_cookie_params只能影响使用当前请求开始的新会话)。
如果我不使用cookie,我不需要写这个对吗?
如果您使用会话ID作为GET参数,那么您可能不需要设置cookie计时器,但是您需要运行GC或自定义逻辑(取决于其重要性),以便用户无法重复使用会话ID(甚至可能是意外的,因为它将在URL栏和历史记录中显示给用户)。
我认为这个答案特别好,因为它展示了关键和非关键的部分。我个人使用PHP会话主要用于非关键的东西,比如错误消息等,而使用基于数据库的会话和自己的cookie来进行真正关键的操作,这样,带有适当过滤器的删除命令就可以将所有旧会话清除。
stackoverflow上最好的答案之一!谢谢!很多人忽略了为什么,只是跳到了如何。这让我成为了一个更好的程序员,而不仅仅是一个更好的复制者。希望有更多像这样的答案。
如果您在共享服务器上,您可能还需要设置“session.save_path”才能使其正常工作。除了忽略该点之外,这是一个很好的答案。
如何在PHP中更改会话超时时间?
如果您使用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会话超时太快,OP在一个主机上遇到了问题,但在切换到另一个主机后问题消失了。
因此,鉴于您无法访问php.ini,如果要以可移植的方式进行更改,使用默认的会话处理方式是不可行的。显然,延长cookie的生存时间对您的主机来说已经足够了,但如果您想要一个可靠地适用于切换主机的解决方案,您必须使用不同的替代方法。
可用的替代方法包括:
1. 在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的生存时间。
以下是示例代码:
savePath = 'my_savepath'; // 忽略savepath并使用我们自己的路径以使其安全免受自动GC影响 $this->lifetime = 3600; // 最小会话持续时间为1小时 if (!is_dir($this->savePath)) { mkdir($this->savePath, 0777); } return true; } function close() { return true; } function read($id) { return (string)_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)) { // 使用我们自己的生存时间 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') ); // 以下防止使用对象作为保存处理程序时出现意外效果 register_shutdown_function('session_write_close'); session_set_cookie_params(3600); // 将会话cookie持续时间设置为1小时 session_start(); // 继续按键从$_SESSION设置和检索值
方法(2)更加复杂;基本上,您必须自己重新实现所有会话函数。我不会在这里详细介绍。
有人可以确认一下吗?
:在粗略阅读后,看起来是正确的。您还可以参考stackoverflow.com/questions/520237/...,但如果您无法访问php.ini,则您的实际选项受到严格限制。
此外,在Ubuntu 14上,看起来/usr/lib/php5/maxlifetime将不会计算低于24分钟的值。因此,您无法将会话超时时间设置得低于该值。
“完全忽略PHP内部会话处理并实现自己的会话管理。”天哪,这是危险的建议。这将不可避免地导致安全噩梦。
我还注意到“它需要更多的代码,因此有更多的错误和安全漏洞的机会”。这不是建议,我正在列举替代方案,但如果您有改进的建议,请告诉我。
session.gc_probability根据文档的说法默认为1 - php.net/manual/en/...