如果您使用 PHP 的默认会话处理,在所有平台上可靠地更改会话持续时间的唯一方法是更改 php.ini。这是因为在某些平台上,垃圾收集是通过一个每隔特定时间运行的脚本(一个 cron 脚本)来实现的,该脚本直接从 php.ini 读取,因此任何尝试在运行时更改它,例如通过ini_set(),是不可靠的,很可能不会工作。
例如,在 Debian Linux 系统中,PHP 的内部垃圾收集通过在配置中默认设置 session.gc_probability=0 来禁用,而是通过 /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 超全局的优势,并且它需要更多的代码,因此存在更多错误和安全漏洞的机会。最重要的是,会话标识符应该由密码安全的随机数或伪随机数生成,以避免会话 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)更复杂;基本上,您必须自己重新实现所有会话功能。此处不再赘述。