简体   繁体   English

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

[英]Codeigniter 3 upgrade session lock causing issues

We've recently upgraded an old Codeigniter app from 2.1.0 to 3.1.9, and everything has gone smoothly. 我们最近已将旧的Codeigniter应用程序从2.1.0升级到3.1.9,一切进展顺利。 Except, that the new session locking is causing issues and I'm wondering the proper way to fix it. 除此之外,新的会话锁定会引起问题,我想知道修复它的正确方法。

The app uses AJAX heavily, however most of the AJAX calls don't write to the session and don't seem to break it. 该应用程序大量使用AJAX,但是大多数AJAX调用不会写入会话,并且似乎也不会中断会话。

Here is an example of the issue: there is a GUI with checkboxes, and when the input is changed (a checkbox is checked or unchecked) an AJAX call was made. 这是一个问题的示例:存在一个带有复选框的GUI,并且当更改输入(选中或取消选中复选框)时,将进行AJAX调用。 On the other end of that AJAX call which boxes were checked were written to session so that they would be remembered from visit to visit. 在该AJAX呼叫的另一端,将选中了复选框的会话写入会话,以便每次访问时都能记住它们。 However, if you checked/unchecked multiple boxes causing multiple AJAX calls to go out, you would end up getting logged out. 但是,如果您选中/取消选中多个框而导致多个AJAX呼叫中断,则最终将被注销。 Similar behavior has been discovered around the app, all where session writes are happening. 在所有正在执行会话写操作的应用程序周围都发现了类似的行为。

I've tried implementing session_write_close() as suggested by the Codeigniter documentation but that only half worked in some spots, and caused more issues in area where there were no issues before. 我尝试按照Codeigniter文档的建议实施session_write_close() ,但是只有一半在某些地方有效,并且在以前没有问题的区域中引起了更多问题。 The app has a few endpoints that do all the work and all work flows share, so fixing the endpoint where the session writes are happening with session_write_close() breaks other script calls when they continue to need the session. 该应用程序具有几个可以完成所有工作且所有工作流都共享的端点,因此使用session_write_close()修复会话写入发生的端点时,当它们继续需要会话时,会中断其他脚本调用。

The short term solution I've come up with is to debounce the AJAX calls (which helps but doesn't solve the problem by itself) and to disable inputs until the AJAX call has finished. 我想出的短期解决方案是对AJAX调用进行反跳(这有助于但不能单独解决问题),并禁用输入,直到AJAX调用完成。

Is there a better long term solution? 有更好的长期解决方案吗? Ultimately this app is being phased out, so spending a long time rewriting it isn't feasible. 最终,该应用已被淘汰,因此花很长时间重写它是不可行的。

The only long-term solution is to properly use session_write_close() . 唯一的长期解决方案是正确使用session_write_close()

As you undoubtedly understand, session data is locked so only one script at any time can write to the session's persistent datastore. 毫无疑问,会话数据已锁定,因此在任何时候只有一个脚本可以写入会话的持久性数据存储。 Session locking prevents hard to troubleshoot concurrency bugs and is more secure. 会话锁定可防止对并发错误进行故障排除,并且更加安全。

Without seeing your implementation it's really hard, er... impossible to offer any precise advice. 如果没有看到您的实现,这真的很难,呃……无法提供任何准确的建议。 Here are some things to consider that might help sort out the mess. 这里有一些需要考虑的事情可能有助于弄清混乱。

Either do ALL or NONE of the session writes in the AJAX response functions. 无论是做所有或会话没有在AJAX响应函数写。 (By "AJAX response function" I mean the PHP controller/method value of the AJAX url.) (通过“ AJAX响应功能”,我指的是AJAX网址的PHP controller/method值。)

With the ALL approach call session_write_close() in the "main" script before making any AJAX requests. 使用ALL方法,在发出任何AJAX请求之前,请在“主要”脚本中调用session_write_close() Keep in mind that $_SESSION is not affected by session_write_close() . 请记住, $_SESSION不受session_write_close()影响。 All $_SESSION items in the main script will remain accessible so you can reliably read the values. 脚本中的所有$_SESSION项都将保持可访问状态,因此您可以可靠地读取值。 However, changes made to $_SESSION will not be written because, as far as PHP is concerned, the session is closed. 但是,将不会写入对$_SESSION所做的更改 ,因为就PHP而言,该会话已关闭。 But that's only true for the script that calls session_write_close() . 但这仅适用于调用session_write_close()的脚本。

With the NONE approach you may still need to read session data. 使用NONE方法,您可能仍需要读取会话数据。 In that case it would be wise to have the AJAX response functions call session_write_close as soon as possible to minimize the time concurrent requests are blocked. 在那种情况下,最好让AJAX响应函数尽快调用session_write_close ,以最大程度地减少并发请求被阻塞的时间。 The call is more important for functions that require significant time to execute. 对于需要大量时间才能执行的功能,该调用更为重要。 If the script execution time is short then the explicit call to session_write_close() is not needed. 如果脚本执行时间很短,则不需要显式调用session_write_close() If at all possible, ie no need to read session data, then not loading the session class might result in cleaner code. 如果有可能,即无需读取会话数据,则不加载session类可能会导致代码更简洁。 It would definitely eliminate any chance of concurrent request blocking. 肯定会消除并发请求阻塞的任何机会。

Don't try to test session behavior by using multiple tabs to the same app on the same browser. 不要尝试通过在同一浏览器上使用多个选项卡来测试同一应用程序来测试会话行为。

Consider using $config['sess_time_to_update'] = 0; 考虑使用$config['sess_time_to_update'] = 0; and then explicitly call $this->sess_regenerate((bool) config_item('sess_regenerate_destroy')); 然后显式调用$this->sess_regenerate((bool) config_item('sess_regenerate_destroy')); when and where it makes sense that the session id needs to be changed, ie right after login; 需要更改会话ID的时间和地点,即登录后立即更改; right after a redirect to a "sensitive" page; 重定向到“敏感”页面后; etc. 等等

What follows next is offered with a large amount of trepidation. 接下来的内容带有大量的恐惧。 I've tested this using the "files" driver, but not extensively. 我已经使用“文件”驱动程序对此进行了测试,但是还没有进行广泛的测试。 So, buyer beware. 因此,买家要当心。

I found that it is possible to "re-start" a session by calling the PHP function session_start() after session_write_close() has been used. 我发现这是可能的“重新启动”会话通过调用PHP函数session_start()之后session_write_close()已被使用。 CodeIgniter will open and read the session datastore and rebuild the $_SESSION superglobal. CodeIgniter将打开并读取会话数据存储,并重建$_SESSION超全局变量。 It's now possible to change session data and it will be written when script execution ends - or with another call to session_write_close() . 现在可以更改会话数据,它将在脚本执行结束时写入-或通过另一个对session_write_close()调用来写入。

This makes sense because session_write_close() does not "do" anything to the CodeIgniter session object. 这是有道理的,因为session_write_close()不会对CodeIgniter session对象执行任何操作。 The class is still instantiated and configured. 该类仍被实例化和配置。 CodeIgniter's custom SessionHandlerInterface is used to open, read, and write session data after session_start() is called. CodeIgniter的自定义SessionHandlerInterface用于在调用session_start()之后打开,读取和写入会话数据。

Maybe this apparent functionality can be used to solve your problems. 也许这种明显的功能可以用来解决您的问题。 In case I wasn't clear earlier - use at your own risk! 如果我之前不清楚,请自担风险!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM