根据我的经验,它一直与php.ini 文件有关。在您的情况下,session.gc_maxlifetime 的主值和本地值相矛盾。 (gc 代表垃圾收集)它们不必相互同意,因为本地值用于运行脚本。这只是意味着您的系统上有两个 php.ini 文件,位于不同的位置,并且本地 php.ini 文件覆盖了主 php.ini 文件设置。但是,我会非常怀疑您服务器上调用session_start() 的任何文件,这些文件使用主php.ini 文件,或在脚本本身中调用ini_set(...)。其工作方式是,无论该值设置为什么,它仅在需要进行垃圾收集时才有意义。垃圾收集由session_start() 完成,但您也可以通过其他方式触发垃圾收集,例如SessionHandler::gc 或cronjob,如本文后面所述。调用时,它会检查服务器上存储会话信息的文件的最后修改时间。如果从那时起经过的秒数大于当前的session.gc_maxlifetime 值,它将破坏会话。请注意,这是最后一次修改时间,而不是最后一次访问时间,因此您需要经常更改会话数据,以防止在未更改时将其删除。您还应该知道,这里有一个名为 session.lazy_write 的设置,如果启用并且默认启用,不会更新会话文件的最后修改时间,如果会话数据没有改变。因此,如果您想最大程度地减少会话因某种未知原因而被提前销毁的可能性,或者在会话上存储时间戳,以便数据始终在变化,并且您知道会话上次使用的时间(如果旧),则您需要禁用此功能,您可以手动拨打session_destroy()。要开始另一个会话,您可以使用session_write_close() 提交,然后调用session_start()。或者,使用session_regenerate_id(true) 一次性完成所有 3 个操作。
接下来,如果您使用您的预期设置初始化与session_start() 的会话,并继续使用每个请求的预期设置调用session_start(),那太棒了。但是,一旦您的服务器上的任何文件调用 session_start() 并使用不同的 session.gc_maxlifetime 值,无论是在您的情况下使用主 php.ini 值,还是调用 ini_set(...) 并忽略主值的脚本,它都会检查该文件的最后修改时间针对不同的值并破坏您的会话,尽管您的预期设置 - 假设它被选为必须进行垃圾收集的 100 个请求之一。
另一个需要关注的是session.cookie_lifetime。此处的值 0 会将 cookie 转换为浏览器会话 cookie。这意味着如果用户关闭他们的浏览器,那么会话 cookie 将被浏览器删除。您的主值使用 0。但您的本地值使用 31557600(一年中的平均秒数)。所以你在这里应该没问题。但是,如果您的服务器上的任何脚本覆盖此值,请睁大眼睛,使用值 0,或使用主 php.ini 文件。
您还应该注意默认的 1% 垃圾收集 CHANCE 会话将按照 session.gc_probability 和 session.gc_divisor 的定义被销毁,它们分别默认为 1 和 100。垃圾收集在调用start_session() 时完成,当且仅当请求“随机”被选为管理垃圾收集的请求。这意味着即使会话经过定义的秒数使其过期,start_session() STILL 即使对于这个过期的会话也不会进行垃圾收集。相反,由于浏览器跟踪其时间戳过期的 cookie,大多数用户会注意到他们的会话完全按计划过期。但是在调用start_session() 时,根据垃圾收集更改进行PHP 垃圾收集之前,不会强制执行会话。如果您希望会话在过期时被清除干净并开始一个新会话,您应该使用session_regenerate_id(true)。这里的true 意味着丢弃与前一个会话相关联的$_SESSION 数据,并向它们扔一个不同的会话ID,就好像它们的会话已过期一样。
您还应该知道,某些系统(例如基于 debian 的系统)有一个 cronjob,它每 30 分钟运行一次,以根据主 php.ini 配置信息进行垃圾收集。
请参阅 Christopher Kramer 的评论:http://php.net/manual/en/session.configuration.php
我无法验证上述关于 debian 系统的信息是否属实,但我之前考虑过 garbage collecting 使用 cronjob 来加速用户的请求,因此没有一个用户因为维护而不得不等待他们的请求通过cronjob 可以处理的。
这里的解决方案:
这里的一种解决方案是调整主 php.ini 值,如果您可以访问它,然后搜索您的服务器以查找可能调用 ini_set 的任何 PHP 文件,以查看是否有任何与您的设置冲突的文件以确保它们不会导致意外行为。
另一种解决方案是通过以下方式限制脚本可能遇到的此类冲突:(1.) 将 session.name 重命名为 PHPSESSID 以外的名称。和/或 (2.) 更改 session.save_path 路径。这些中的任何一个都足以避免脚本冲突。
临时修复可能是将您的session.gc_probability 更改为0,这样会话垃圾收集永远不会发生。或者通过使用像 session.gc_probability=1 和 session.gc_divisor=100000 这样的东西来减少机会。然后设置一个cronjob来调用SessionHandler::gc
有关更多会话配置信息,请参阅 http://php.net/manual/en/session.configuration.php。
最后,我想向您指出这篇文章,它提出了防止会话劫持的良好做法,其中大部分是我在整理这篇文章时引用的文章:https://stackoverflow.com/a/1270960/466314
请注意,它使用了一种会话方法,可确保会话按时到期,而不是稍后(尽管浏览器已经通过 cookie 垃圾收集做得很好)。它还对会话进行更改,跟踪会话上次使用的时间,因此会话数据始终在更改以避免session.lazy_write 的问题。
我的建议到此结束。如果您可以缩小问题范围,请尝试搜索 stackoverflow 或提出新问题。