首页 > 解决方案 > Codeigniter 3 升级会话锁定导致问题

问题描述

我们最近将旧的 Codeigniter 应用程序从 2.1.0 升级到 3.1.9,一切进展顺利。除了新的会话锁定导致问题,我想知道修复它的正确方法。

该应用程序大量使用 AJAX,但大多数 AJAX 调用不会写入会话并且似乎不会破坏它。

这是问题的一个示例:有一个带有复选框的 GUI,并且当输入更改时(选中或未选中复选框)进行了 AJAX 调用。在 AJAX 调用的另一端,哪些框被选中被写入会话,以便在访问时记住它们。但是,如果您选中/取消选中多个框导致多个 AJAX 调用退出,您最终会被注销。在应用程序周围发现了类似的行为,所有会话写入都在发生。

我已经尝试按照Codeigniter 文档session_write_close()的建议进行实施,但是在某些地方只有一半有效,并且在以前没有问题的区域引起了更多问题。该应用程序有几个端点可以完成所有工作并且所有工作流共享,因此当其他脚本调用继续需要会话时,修复会话写入发生的端点会中断其他脚本调用。session_write_close()

我提出的短期解决方案是消除 AJAX 调用的抖动(这有助于但不能自行解决问题)并在 AJAX 调用完成之前禁用输入。

有没有更好的长期解决方案?最终这个应用程序被淘汰了,所以花很长时间重写它是不可行的。

标签: phpajaxcodeignitersession

解决方案


唯一的长期解决方案是正确使用session_write_close().

正如您无疑理解的那样,会话数据被锁定,因此任何时候只有一个脚本可以写入会话的持久数据存储。会话锁定可以防止难以解决的并发错误并且更安全。

没有看到你的实现真的很难,呃......不可能提供任何准确的建议。这里有一些需要考虑的事情,可能有助于解决混乱。

在 AJAX 响应函数中执行ALLNONE会话写入。(“AJAX 响应函数”是指controller/methodAJAX url 的 PHP 值。)

在发出任何 AJAX 请求之前,在“主”脚本中调用ALL方法。session_write_close()请记住,$_SESSION不受session_write_close(). 脚本中的所有$_SESSION项目都将保持可访问性,因此您可以可靠地读取这些值。但是,不会写入对 的更改,因为就 PHP 而言,会话已关闭。但这仅适用于调用.$_SESSIONsession_write_close()

使用NONE方法,您可能仍需要读取会话数据。在这种情况下,明智的做法session_write_close是尽快调用 AJAX 响应函数,以尽量减少并发请求被阻塞的时间。对于需要大量执行时间的函数,调用更为重要。session_write_close()如果脚本执行时间很短,则不需要显式调用。如果可能的话,即不需要读取会话数据,那么不加载session类可能会导致代码更清晰。它肯定会消除并发请求阻塞的任何机会。

不要尝试通过在同一个浏览器上对同一个应用程序使用多个选项卡来测试会话行为。

考虑使用$config['sess_time_to_update'] = 0;,然后$this->sess_regenerate((bool) config_item('sess_regenerate_destroy'));在需要更改会话 ID 的时间和地点显式调用,即在登录后立即调用;在重定向到“敏感”页面之后;等等

接下来的内容充满了恐惧。我已经使用“文件”驱动程序对此进行了测试,但并不广泛。所以,买家要小心。

我发现可以通过在使用session_start() 后调用 PHP 函数来“重新启动”会话session_write_close()。CodeIgniter 将打开并读取会话数据存储并重建$_SESSION超全局。现在可以更改会话数据,它将在脚本执行结束时写入 - 或再次调用session_write_close().

这是有道理的,因为session_write_close()不会对 CodeIgnitersession对象“做”任何事情。该类仍被实例化和配置。CodeIgniter 的自定义SessionHandlerInterface用于在session_start()调用后打开、读取和写入会话数据。

也许这个明显的功能可以用来解决你的问题。如果我之前不清楚 - 使用风险自负!


推荐阅读