I am using sessions in an attempt to implement persistent logins for my users in a web application. The back-end is php 7.2 and apache, provided through Namecheap shared hosting.
I am setting a session cookie on the client with a "cookie_lifetime" and "gc_maxlifetime" of 604,800 seconds (one week). The server calls session_start() with these parameters and checks a $_SESSION key called "user_id" to see if the session_start() call has started an existing session (if the key is defined, the user is "logged in"). It does this every time the page is loaded. Everything works fine until about 40 minutes of inactivity have gone by, then the next page refresh and attempt to call session_start() and access any $_SESSION keys returns undefined for everything, despite the session cookie still showing an "Expires" value several days in the future in DevTools.
My understanding was that "cookie_lifetime", "gc_maxlifetime", and the associated "Expires" header for setting the client-side cookie would preserve session information for at least as long as the time specified, but this interaction is demonstrating that regardless of what I put in those fields, the $_SESSION superglobal will not return anything meaningful beyond ~40 minutes of inactivity.
Am I not understanding this correctly, or is there perhaps something wrong from a server configuration standpoint that is beyond the scope of the client-server application code?
I didn't fully get to the bottom of why this was occurring. I did reach out to the Namecheap support staff, however, and they told me their sessions were not malfunctioning in the same way after ~40 minutes; they continued to see session values that had been set several hours previously when they tried to recreate the issue using the same code and configuration as I was using.
I dug into the server configuration and reviewed the output of a phpinfo() dump and determined that the Registered save handlers were set to files user. I can't find out what the user component of that reflects, and maybe that's where the issue lies, but I was able to resolve the issue by explicitly specifying the session.save_path parameter rather than relying on the default (which was no value in the phpinfo output).
The support staff had said that the default location was /home/[user]/tmp/ and their sessions were showing up there, but mine were not. After adding the explicit save_path to php.ini, my sessions began to appear there and the ~40 minute expiration stopped occurring.
I'll hold off on accepting this as the answer in case anyone else can provide more insight/understanding, but I wanted to at least chime in saying that I had found a solution to my problem. I'm not sure what was happening before, but I could not find my session files anywhere sensible in the directories of my shared host user account and I'm wondering if they were there at all. It's also very strange to me that it worked for the support staff but not for me or a friend that I had test it on his own computer.
I have one user reporting that they are being logged out at 6:45 pm est (around that time). My session expire time is 24 hours and they login about 8 hours earlier.
Just as a test I set sess_time_to_update to PHP_INT_MAX as their is a known bug that causes session logouts when it is rotating the session.
The only thing I can think of that would cause this is Firefox's ability to restore previous tabs. This actually restores the session cookie even after the browser is closed.
She said this also happens in Internet Explorer...I couldn't find a setting in IE 11 to persist session cookies after the browser closes.
Do you have any ideas what could be causing this or an idea of what to investigate?
EDIT: This happened to another client. It happens only some days and doesn't happen to users at a different location. Is there anything I can do to determine how this is happening?
Try testing it in a few different browsers and see if it's still happening.
If it is, maybe:
Check if there are any cron jobs running server side that could be killing session cookies on the server?
Use a tool like IECookiesView to see what cookies are there, when they're set to expire and if anything is changing?
If they keep getting logged out at similar times try working out anything that might be happening server or local side at that time. It's unlikely a restore tabs (with cookies) feature could be randomly running at the same time.
I remember seeing a feature in Firefox to clear all cookies on exit as well, are they rebooting around that time?
Hope I helped.
I'm not sure that you're setting the actual expiration period of sessions to PHP_INT_MAX. As stated in the manual sess_time_to_update config controls how often the session class will regenerate itself and create a new session ID. In other words it's how often the session details (such as last activity) are getting updated, not expired.
On the other hand there are a few configuration directives that have influence on unexpected session expirations of your case:
sess_expiration: The number of seconds you would like the session to last. The default value is 2 hours (7200 seconds). If you would like a non-expiring session set the value to zero: 0.
sess_expire_on_close: Whether to cause the session to expire automatically when the browser window is closed.
Make sure that these settings are set fine and then try to reproduce the situation on your own browser to minify the scope of the problem. If you still experience random logouts add a log_message() call to session library's sess_destroy() to keep track of user session destruction that may give you a clue about the destruction pattern.
If nothing, I think that would be user's browser or CCleaner-like apps on her machine wiping off the cookie. Instruct her to factory reset her browser settings or install a brand new browser.
The other thing worth noting is that some CI libraries such as IonAuth has their own related configs. If you're using IonAuth for authentication please have a look at user_expire and remember_users directives in the ion_auth.php config file.
Hope it helps.
I have setup a simple user login session as below in the pages of my web app:
if (!isset($_SESSION['username'])){
if (isset($_COOKIE['username'])){
$_SESSION['username'] = $_COOKIE['username'];
}
I started to notice that on some occasions I would loose my login session. I checked the cookie expiry time and that was definitely set for a future date. The behaviour was quite random where sometimes replicating the action would not cause the issue.
Today I discovered that the web servers (x2) are load balanced (clumsy of me to not have picked up on this) and now I suspect the issue spits up when a user sends a request to the 2nd web server where a cookie doesn't exist.
I would have thought when you hit a web server it would maintain a session with it. However the behaviour suggests otherwise.
I have not spoken to the web admin yet. Is there a magic solution the web admin can sort me out with? or is this an implementation problem? If so, any ideas on how I can solve this?
Suggestions are much appreciated.
The cookie doesnt care what backend server handles the request, unless the url changes. If the url changes from www1.xxx.xx to www2.xxx.xx then you could save the cookies with the path included (xxx.xx) and both subdomains will be able to see the cookie.
Another thing that is more likely to go wrong is that the sessions arent shared between both servers. You could use memcached for this.
I'm having problems with the PHP site I run at work where users are being logged out after a few minutes (the exact time varies, but it is frequent enough to be an issue), regardless of whether they have been actively using the site or not.
The difficulty is that I can't reproduce this problem, if I login as the same users using the same browser I don't get logged out, which suggests it is not a case of the site being completely broken. Unfortunately I don't have access to the user machines to run any traffic-sniffing software.
The things I have already checked are:
Asking users to try different browsers. This doesn't seem to solve the problem and isn't a long-term solution anyway as I can't dictate which browsers customers will use.
The server time is correct and in line with the user machines.
The user Apache runs as has permission to write to the session folder, and I can see the session files being created and their modification times being updated.
No output buffering functions are being used.
The problem is happening on a variety of pages which seem to have nothing in common (i.e. it's not that they all use AJAX, or update the database or some other reason).
Users only access their account from one machine, i.e. they don't do a bit of work on their laptop, switch to the desktop and then wonder why they've been logged out on their laptop (we don't allow multiple simultaneous logins for the same user).
The session settings in PHP are the Debian defaults, and haven't been changed in a .htaccess file or anywhere else. The main ones are:
session.cookie_lifetime 0
session.gc_divisor 100
session.gc_maxlifetime 1440
session.gc_probability 0
session.save_handler files
session.save_path /var/lib/php5
session.use_cookies On
Debian deletes sessions through a cron job instead of using PHP's garbage collector, which is why gc_probability is set to 0. The PHP version we're running is: PHP 5.2.6-1+lenny13 with Suhosin-Patch 0.9.6.2 (cli) (latest version in Lenny, we'll be upgrading to Squeeze soon but I don't think that is the cause of the problem).
We use Zend_Session to manage sessions, and an instance of Zend_Session_Namespace is created once on every page, thus automatically calling session_start(). Sessions are cleared by calling Zend_Session::destroy() on the logout page, so the only ways a user should be logged out are:
If they explicitly click the logout link (we log when this happens and it doesn't seem to be the case that browsing are pre-fetching the page and thus logging the user out).
If they leave the session inactive for more than 24 minutes, at which point Debian will probably delete their session (there's a cron job which runs every half hour deleting all sessions which have been unmodified for over 24 minutes).
If they close the browser, as their session cookie with an expiry time of 0 will be deleted.
The checks for seeing whether a user is logged in are:
They have a valid session (checked by seeing whether we can access $zsession->user_id).
There is a row in the sessions table which has a matching user ID and session ID, and this was last updated less than an hour ago. We delete this row on logout so that even if the session still exists on disk, no one can access that account without logging in.
Can anyone suggest other things I can try?
Edit: Some additional things I have tried based on comments left:
Setting session.cookie_domain: This seems to have very odd behaviour in PHP. If I do not set this variable and leave it as the default of '' (empty string), then a request for www.domain.com will produce a cookie of www.domain.com. However, if I set cookie_domain to 'www.domain.com', the domain for the cookie is '.www.domain.com' (notice leading dot, which means valid for everything below www.domain.com, e.g. subsite.www.domain.com).
Setting session.cookie_lifetime: PHP does not seem to update the expiry time on each request, so if I set cookie_lifetime to 3600 the cookie will expire one hour after the user first visits the site, even if they login and constantly use it.
Edit 2: Based on other things people have asked:
The site is hosted in a datacentre, on a separate VLAN. No one accessing the site is on the same network as the site.
There is no IP authentication used, nor is the IP address of the client used in any part of the session process (e.g. we don't attach the session to an IP address and block the user if their next request comes from a different IP).
Debian deletes sessions through a cron job instead of using PHP's garbage collector
That's very odd - and what is the code that runs in the cron job?
We delete this row on logout
I suggest you keep this for, say, 2 days after the session has expired / is deleted (but flag it as dead at the point where you currently delete it). Also, start logging the session id in your webserver logs.
In the end, the answer was to just scrap sessions and write my own very simple cookie code which differs from sessions in the following ways:
Stores a hash (bit like a session ID) in the database rather than in files.
Sets the cookie to expire in 3600 seconds from now (updated on each page) instead of 0 seconds (the latter seemed to cause problems for IE users, although I could never replicate it).
Only sends the cookie header when the user logs in or is logged in.
It's not an ideal situation as there's some reinventing the wheel going on, but my small solution seems to work where PHP sessions didn't, and having a working site is the most important thing.
I think you count change the value of
session.gc_maxlifetime
I also faced the same problem. I spent lots of time on it then i ask my web service provider and as he got the permission he changed that vale. Now it works fine.
Are there other php applications running on the same system (under different vhosts, for instance?)? Are they also saving sessions in /var/lib/php5?
If so, and one of those apps has a low session garbage-collection threshold, they will trash your app's session files.
I do a lot of ZF development, and if I'm using filesystem-based sessions, I stick them in application/data/session instead of the system default.
your session.gc_maxlifetime is set to 1440 ms which is only 1.44 seconds. shouldn't it be 1440000 ms = 24 minutes?
You could try setting session.use_only_cookies to a value of 1 and session.cookie_lifetime to a value of 1440 seconds.
is your site on different domains ? for example domain.com, www.domain.com, subdomain.domain.com ? if some pages are redirected to a different domain (www is considered a subdomain that is different) than the sessions will not work when the address changes
EDIT:
You must reproduce the problem. Ask your clients what kind of browser do they use, what action they do until they are logedout, are they viewing the same ip for the site as you do? (that is you are both in external networks or both in the same network with the site)
When you manage to find the problem, check the request/response headers when it the session works, and also when it does not work and then compare.
In the end I opted to send a Set-Cookie header on every page request, similar to what FlyBy suggested in one of the comments. The relevant code/logic now is (assuming session_start() has already been called):
$this->session_name = session_name();
$update_cookie = isset($_COOKIE[$this->session_name]); // Check if cookie already set, as PHP will send the first Set-Cookie when the session is started
$this->logged_in = $this->checkSession(); // Function which checks whether a valid (i.e. not timed-out) session row exists in the DB
if ($this->logged_in) {
$this->updateSession(); // Update the session row to the current time
if ($update_cookie) {
// Update the cookie expiry only if it existed before the login check
setcookie($this->session_name, $_COOKIE[$this->session_name], $this->time + 3600, '/');
}
}
I'm not sure why this worked, but I haven't had any further complaints and the number of logins has dropped drastically (no longer are there several logins in the logs for the same user within a few minutes of each other).
However, I will probably rewrite the code at some point to just use a database row and a cookie on the client, because the session functionality in PHP has so many variables that it's extremely difficult to work out what is causing the problem, and the session cookie handling is slightly different to how normal cookies are handled. In particular, you have to be careful with the setcookie function, because the default path for session cookies started by PHP is '/', but the default for setcookie is the current directory path, and these will not necessarily be the same.
The session in my application often gets expired.
session_gc_maxlifetime is set to 24 minutes(default);
since my apps is a real time application that basically uses AJAX. Every second my ajax function calls a http request. As far as i know my session should not expire because it always called upon the ajax request.
It works for sometime and getting expired very soon sometimes(about 2-3 minutes of inactivity).
Can anyone help me out in solving this problem. Not only my website but the others website hosted in the same server encountered the same problem.
With Thanks and Regards,
Trez
The session_gc_maxlifetime is basically useless when sessions share location with other hosted sites: PHP does not track which site owns which session file so the site with the shortest session_gc_maxlifetime is likely to remove session data from all sites.
I suggest you enable a directory for your site and set it with the session_save_path() function before calling session_start().
Can you reproduce this problem on a non-production server?
Have you got any scripts which clean out the sessions directory? Have you looked in the sessions directory to see how old the files are?
If you are not the only one with root access, I'd suspect someone else who is, try talking to them.