我想在php中扩展会话超时
我知道可以通过修改php.ini文件来实现。但我无法访问它。
那么有可能只用PHP代码吗?
会话超时是一个必须在代码中实现的概念,如果您需要严格保证;这是你绝对可以确定在X分钟不活动后没有会话能够存活的唯一方法。
如果放宽这个要求有一点是可以接受的,你可以放置一个下限而不是严格的持续时间限制,你可以轻松地这样做,而无需编写自定义逻辑。
如果您的会话使用cookie(它们可能是)实现,并且客户端不是恶意的,您可以通过调整某些参数来设置会话持续时间的上限。如果你使用PHP的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!
这可以通过配置服务器来保持会话数据至少一小时不活动,并指示您的客户在相同的时间跨度后“忘记”他们的会话ID。需要这两个步骤才能达到预期的效果。
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对您很重要的情况下,必须注意在需要时使用session_regenerate_id
重新生成它们。
如果您使用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的生命周期对于您的主机来说已经足够了,但如果您想要一个即使切换主机也能可靠运行的解决方案,您必须使用不同的替代方案。
可用的替代方法包括:
ini_set()
来设置session.gc_maxlifetime但我更喜欢忽略我的gc()
回调中的maxlifetime参数并自己决定最大生命周期。$_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)更复杂;基本上,您必须自己重新实现所有会话功能。我不会在这里详述。
为使用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中的值。