Codeigniter 3升级会话锁定导致问题

时间:2018-11-26 14:34:39

标签: php ajax codeigniter session

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

该应用程序大量使用AJAX,但是大多数AJAX调用不会写入会话,并且似乎也不会中断会话。

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

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

我想出的短期解决方案是对AJAX调用进行反跳(这有助于但不能单独解决问题),并禁用输入,直到AJAX调用完成。

是否有更好的长期解决方案?最终,该应用已被淘汰,因此花费大量时间重写它是不可行的。

1 个答案:

答案 0 :(得分:1)

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

毫无疑问,会话数据是锁定的,因此任何时候任何时候都只有一个脚本可以写入会话的持久性数据存储。会话锁定可防止对并发错误进行故障排除,并且更加安全。

没有看到您的实现,这真的很难,呃……无法提供任何精确的建议。这里有一些需要考虑的事情可能有助于弄清混乱。

会话的 ALL NONE 都将在AJAX响应函数中写入。 (通过“ AJAX响应功能”,我指的是AJAX网址的PHP controller/method值。)

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

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

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

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

接下来会发生很多令人恐惧的事情。我已经使用“文件”驱动程序对此进行了测试,但是还没有进行广泛的测试。因此,买家要当心。

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

这是有道理的,因为session_write_close()不会对CodeIgniter session对象执行任何操作。该类仍被实例化和配置。 CodeIgniter的自定义SessionHandlerInterface用于在调用session_start()之后打开,读取和写入会话数据。

也许这种明显的功能可以用来解决您的问题。如果我之前不清楚,请自担风险!