本文介绍了Codeigniter 3升级会话锁定导致问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

We've recently upgraded an old Codeigniter app from 2.1.0 to 3.1.9, and everything has gone smoothly. Except, that the new session locking is causing issues and I'm wondering the proper way to fix it.

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

The app uses AJAX heavily, however most of the AJAX calls don't write to the session and don't seem to break it.

这里是问题的一个示例:存在一个带有复选框的GUI,并且当更改输入(选中或取消选中复选框)时,会进行AJAX调用.在该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. 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. However, if you checked/unchecked multiple boxes causing multiple AJAX calls to go out, you would end up getting logged out. Similar behavior has been discovered around the app, all where session writes are happening.

我已经尝试按照 Codeigniter文档,但是只有一半在某些位置有效,并且在以前没有问题的区域中引起了更多问题.该应用程序具有几个可以完成所有工作且所有工作流都共享的端点,因此使用 session_write_close()修复正在进行会话写操作的端点时,当它们继续需要会话时,会中断其他脚本调用.

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. 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.

我想出的短期解决方案是对AJAX调用进行去抖动(这本身可以帮助但不能解决问题),并禁用输入,直到AJAX调用完成为止.

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.

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

Is there a better long term solution? Ultimately this app is being phased out, so spending a long time rewriting it isn't feasible.

推荐答案

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

The only long-term solution is to properly use 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.

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

Either do ALL or NONE of the session writes in the AJAX response functions. (By "AJAX response function" I mean the PHP controller/method value of the AJAX url.)

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

With the ALL approach call session_write_close() in the "main" script before making any AJAX requests. Keep in mind that $_SESSION is not affected by session_write_close(). All $_SESSION items in the main script will remain accessible so you can reliably read the values. However, changes made to $_SESSION will not be written because, as far as PHP is concerned, the session is closed. But that's only true for the script that calls session_write_close().

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

With the NONE approach you may still need to read session data. 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. 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. If at all possible, i.e. no need to read session data, then not loading the session class might result in cleaner code. 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.

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

Consider using $config['sess_time_to_update'] = 0; and then explicitly call $this->sess_regenerate((bool) config_item('sess_regenerate_destroy')); when and where it makes sense that the session id needs to be changed, i.e. right after login; 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.

我发现使用 session_write_close()后可以通过调用PHP函数 session_start()来重新启动"会话.CodeIgniter将打开并读取会话数据存储,并重新构建 $ _ SESSION 超全局变量.现在可以更改会话数据,并且将在脚本执行结束时写入会话数据-或调用另一个 session_write_close().

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. CodeIgniter will open and read the session datastore and rebuild the $_SESSION superglobal. 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()不会对CodeIgniter session 对象执行任何操作.该类仍被实例化和配置.在调用 session_start()之后,CodeIgniter的自定义 SessionHandlerInterface 用于打开,读取和写入会话数据.

This makes sense because session_write_close() does not "do" anything to the CodeIgniter session object. 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.

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

Maybe this apparent functionality can be used to solve your problems. In case I wasn't clear earlier - use at your own risk!

这篇关于Codeigniter 3升级会话锁定导致问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

11-03 11:12