我想在php中扩展会话超时
我知道可以通过修改php.ini文件来实现。 但我无法访问它。
那么只能用php代码才能做到吗?
答案 0 :(得分:289)
会话超时是一个必须在代码中实现的概念,如果你想要严格的保证;这是唯一的方式你可以绝对肯定在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,其有效持续时间将是非确定性。这是因为服务器端生命周期已过期的会话不会立即被垃圾收集,而只会被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对您很重要的情况下,必须注意在需要时使用session_regenerate_id
重新生成它们。
答案 1 :(得分:27)
如果使用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的生命周期对于您的主机来说已经足够了,但如果您想要一个即使切换主机也能可靠运行的解决方案,您还必须使用其他替代方案。
可用的替代方法包括:
在PHP中设置一个不同的会话(保存)处理程序,将会话保存在PHP: Custom Session Handlers (PHP manual)中指定的不同目录或数据库中,以便 cron 作业没有达到它,只有PHP的内部垃圾收集发生。此选项可能会使用ini_set()
设置 session.gc_maxlifetime ,但我更喜欢忽略gc()
回调中的 maxlifetime 参数并确定我自己的最长寿命。
完全忘记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)更复杂;基本上,您必须自己重新实现所有会话功能。我不会在这里详述。
答案 2 :(得分: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()
直接销毁会话而不是依赖于重定向可能是更好的选择。
答案 3 :(得分: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
答案 4 :(得分:1)
没有。 如果您无权访问php.ini,则无法保证更改会产生任何影响。
我怀疑你需要延长会话时间 目前它有非常合理的超时,没有理由延长它。
答案 5 :(得分:1)
仅用于共享托管服务器或在域上添加的通知=
为使设置生效,必须使用php_value session.save_path“ folderA / sessionsA”为添加的域设置不同的保存会话目录。
因此,请在根服务器上创建一个文件夹,而不要在public_html中创建一个文件夹,并且不要从外部进行公开访问。对于我的cpanel /服务器,该文件夹的权限为0700,工作正常。尝试一下...
php代码 =
#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);
ini_set('session.cache_expire', 57600);
ini_set('session.name', 'MyDomainA');
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
经过大量研究和测试,这对于共享的cpanel / php7服务器工作正常。非常感谢:NoiS
答案 6 :(得分:0)
您可以使用ini_set()
从PHP代码覆盖php.ini中的值。