-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix GC issue when session lifetime is set to 0 #4744
Fix GC issue when session lifetime is set to 0 #4744
Conversation
I don't really know what this does, but the code does solve the bug. Any other maintainers familiar? Or @lf-uraku-yuki can you offer more explanation/documentation on what is happening here? |
Is there any scenario where someone would be setting this to |
The session expiration time is set to the same value in session.gc_maxlifetime in the current implementation. Therefore, session.gc_maxlifetime will be set to 0 even if you want to set the session expiration date to 0 (= While the browser is open). This side effect occurs with the gc method in each SessionHandler and destroys the existing session. |
Note that sessionHandler gc is called every time a session is started and is executed with the probability calculated from session.gc_divisor and session.gc_probability. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay I think I understand now. And to answer my own question: no, you would never intentionally set this to 0
while using the Session class. I'll leave the PR in case anyone else wants a look, but I'm good with it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As far as I remember setting 0
will work just fine on Debian and will stop PHP gc entirely. This PR can cause problems for some people since their apps will start using the default value which is 1440
.
We probably should mention this at least in the changelog.
Really hard to find info on this, but StackOverflow does seem to agree:
I think we need some more research before going with this. |
I'm not too keen on this fix as it leaves all stale sessions in the table forever (if $sessionExpiration is set to 0). What I did as a quick fix in my environment was to modify the garbage collection method in the DatabaseHandler class to clean out sessions with timestamps older than 2 days. public function gc($maxlifetime): bool
{
//deletes all sessions if $sessionExpiration is set to 0 (on browser close)
//https://github.com/codeigniter4/CodeIgniter4/issues/4169
//return ($this->db->table($this->table)->delete('timestamp < ' . (time() - $maxlifetime))) ? true : $this->fail();
//Instead, clean out stale sessions older than 2 days (ending sessions on browser close or 2 days whichever comes first)
return ($this->db->table($this->table)->delete('timestamp < UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 2 day))')) ? true : $this->fail();
} I think the ideal solution involves having two separate values for these settings. One that holds the client-side session expiration, and another for the server-side session expiration used during garbage collection (in place of my hard-coded 2 days in the above example). It would certainly be difficult to clearly explain to someone in the documentation or configuration file though. Thoughts? |
If I set |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this PR is okay.
But now there is a conflict. So I can't merge.
@lf-uraku-yuki Can you solve it?
@nmolinos
Why it leaves all stale sessions? if |
@lf-uraku-yuki |
Hi @kenjis, session.gc_maxlifetime would only be set to the PHP default in Session.php:307 if the configuration value wasn't set at all:
So leaving it at zero effectively sets gc_maxlifetime to zero as well. |
@nmolinos elseif ($this->sessionExpiration > 0)
{
ini_set('session.gc_maxlifetime', (string) $this->sessionExpiration);
} |
@kenjis Thanks for your patience...I see that now. You're absolutely right that fixes it. |
Are we sure this is safe across different OSes? See e.g. Michal's comment above. |
@kenjis Fix conflicts by weekend. |
@lf-uraku-yuki Thank you for your cooperation! |
Since this change would effectively cause sessions to be removed after 24 minutes of inactivity (for the PHP.ini default of 1440 in some cases -- when sessionExpiration is set to 0), this should definitely be made more apparent. Possibly adding a note to the configuration file where sessionExpiration is set, in addition the ChangeLog as mentioned by Michal. |
When you set Before:
After:
Session ConfigurationSee https://www.php.net/manual/en/session.configuration.php Server Sidesession.gc_maxlifetime default: 1440 session.gc_probability default: 1 session.gc_divisor default: 100 Client Sidesession.cookie_lifetime default: 0 |
I've confirmed Debian 10.11's behavior. ProcedureBuild docker environment and installs CI 4.1.4.
Check Debian version.
Update Home controller. <?php
namespace App\Controllers;
use Config\Services;
class Home extends BaseController
{
public function index()
{
//ini_set('session.gc_divisor', (string) 1);
$session = Services::session();
}
} Create session files.
Set <?php
namespace App\Controllers;
use Config\Services;
class Home extends BaseController
{
public function index()
{
ini_set('session.gc_divisor', (string) 1);
$session = Services::session();
}
} Set --- a/backend/app/Config/App.php
+++ b/backend/app/Config/App.php
@@ -174,7 +174,7 @@ class App extends BaseConfig
*
* @var int
*/
- public $sessionExpiration = 7200;
+ public $sessionExpiration = 0;
/**
* -------------------------------------------------------------------------- Run Home controller.
|
@MGatner @michalsn @nmolinos But when a user set So it is better to add a note that when you set |
It seems like everything is working. So I'm okay with the changes. Thank you for taking your time to investigate @kenjis ! |
Yes, stellar investigation! Puts my mind at ease. Is the comment you wrote above above appropriate for our User Guide? We would also need an entry in the Change Log it sounds like. |
The signature and committer email address do not match because the user specified at the time of commit was incorrect. I'm sorry . |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me! Whoever merges please squash.
@lf-uraku-yuki Thank your for your contribution! Next time, if possible, please use |
Description
Fixes #4169
If the session validity period is larger than 1, it operates as usual, and if it is 0, the setting value on the PHP side is used for GC timing.
Checklist: