I have a site running on apache and using php. Sometimes I have users on the site doing work and then they suddenly lose their session. I start the session with
session_start()
and it puts a PHPSESSID cookie in the user's browser. I also have
session.cookie_lifetime=0
in my php.ini file. I also do a javascript long poll every 5 minutes to see if the session is still active.
Here is the php code that I use to see if the session is still active
public function actionPollLogin()
{
if (isset($_SESSION['user']['id']))
{
echo $this->renderAjaxJson(array("success"=>1));
} else {
echo $this->renderAjaxJson(array("success"=>0));
}
}
If success == 0 then I return the user to the public part of the site. But like I said, the weird thing is that the user can be actively using the site and then idle for 20 seconds and get logged out. And for testing, I dump the session to the screen that the users are returned to confirm the session is dead.
What settings to I need to tweak to allow active users to stay logged in.
Here are my current php.ini settings
session.hash_bits_pre_character=5
session.hash_function=0
session.cache_expire=180
session.cache_limiter=nocache
session.referer_check=
session.gc_maxlifetime=1440
session.gc_divisor=1000
session.gc_probability=1
session.serialize_handler=php
session.cookie_httponly=
session.cookie_domain=
session.cookie_path=/
session.cookie_lifetime=0
session.auto_start=0
session.name=PHPSESSID
session.use_only_cookies=1
session.use_cookies=1
session.use_strict_mode=0
Docs
session.gc_maxlifetime specifies the number of seconds after which data will be seen as 'garbage' and potentially cleaned up.
So after 24 minutes your sessions expire server-side and are potentially cleaned up.
The solution for me was to add this line after my session_start();
$_SESSION['activity']=time();
This updated the last modified date of the session file everytime the user interacted with the site.
Related
How do i set a fat-free framework session to expire after a duration, say 5 minutes, of inactivity? My web app keeps open until a user logouts out.
First of all you need to know about the PHP session garbage collector behaviour. By default, it triggers randomly on every 100th request (for performance purposes), looks for expired session files (default: 1440s) and remove them.
Also you need to know that some Linux distributions (e.g Debian/Ubuntu) disable this garbage collector and replace it with their own cron job.
You could start checking your PHP configuration:
foreach (['gc_probability','gc_divisor','gc_maxlifetime'] as $k)
echo $k,'=',ini_get("session.$k"),'<br>';
If the GC probability is 0, sessions files won't ever be removed (or could be removed by a cron job on Debian/Ubuntu). If it is not 0, but is low (e.g 1/100), sessions files will be removed some time (try to refresh the page 100 times).
In theory, you could set the probability to 1 (gc_probability=gc_divisor=1) to have sessions files removed as soon as they get expired. That would work on small apps with low traffic, but would affect performance on bigger apps (imagine that the GC needs to scan 1000 or more session files on each request).
The cleanest and most portable way of handle this issue is to expire sessions yourself. Every time you're loading a user session data, check the last time it was here and clear the session data if it's expired.
Here's a small example:
$f3->TIMEOUT=7200;// define session timeout here (in seconds)
ini_set('session.gc_maxlifetime',$f3->TIMEOUT);// see note (*) below
ini_set('session.cookie_lifetime',$f3->TIMEOUT);// optional (**)
$f3->route('GET|POST|DELETE /session',function($f3){
// load session data
$data=&$f3->ref('SESSION.data');
// sign in on POST requests
if ($f3->VERB==='POST') {
$data=['user'=>'John','stamp'=>time()];
$f3->reroute();
}
// sign out on DELETE requests
if ($f3->VERB==='DELETE') {
// sign out
$data=NULL;
$f3->reroute();
}
// check if session has expired
if (is_array($data) && time()>$data['stamp']+$f3->TIMEOUT) {
$data=NULL;
}
// check if user is authenticated
if (is_array($data)) {
echo 'Welcome ',$data['user'],' last time we\'ve seen you was ',date(DATE_W3C,$data['stamp']);
echo '<form action="" method="post"><button>Sign out</button><input type="hidden" name="_method" value="DELETE"/></form>';
$data['stamp']=time();// update session stamp
} else
echo 'You\'re not authenticated';
echo '<form action="" method="post"><button>Authenticate as `John`</button></form>';
});
Of course, you'd better wrap all this logic in a dedicated class.
(*) PHP GC maxlifetime should not be lower than $f3->TIMEOUT, otherwise it could interfere with it. Let's say $f3->TIMEOUT equals 7200 and session.gc_maxlifetime is set to 1440 (default), there are chances that your user sessions get expired between 1440 and 7200. NB: On Debian/Ubuntu, you should set this parameter inside php.ini otherwise the cron job cleaning up session files won't be aware of it.
(**) If you skip this line, the session cookie lifetime defaults to 0, which means "until the browser is closed". See here.
I have a login page/system which has worked correctly for years, leaving the user logged in until he/she either closes the browser window or logs out manually. But lately (starting yesterday) after only a few minutes of inactivity the session cookie/s seems to expire, causing the user to be logged out automatically.
This happens on different browsers and different operating systems, the PHP version is 5.6.29, which has been changed recently (before it was 5.5 and even 5.3).
I create and refresh the session on every page with session_start(). The login script first checks user name and PW and also gets some other user data from the database. These other data are first saved in variables and then written into session variables like
$_SESSION['username'] = $name;
$_SESSION['usertype'] = $type;
The successful login state is saved like this:
$_SESSION['login'] = "ok";
On the other pages I check the login state like this:
session_start();
if(($_SESSION['login'] != "ok") OR ($_SESSION['usertype'] != "xxx")) {
header("Location: ../login.php"); /* redirects to login page if conditions are not true */
exit;
}
The login works, and logged-in users can proceed to other pages as long as the do it more or less in constant succession, but if someone waits a few minutes before proceding (i.e. without any acitivity), he/she is logged out (i.e. redirected to the login page when trying to open another page).
To make it extra-nasty, half of the time it just works as expected, also after half an hour...
Any help would be very much appreciated.
UPDATE:
Adding ini_set('session.gc_maxlifetime', 3600'); and `ini_set('session.cookie_lifetime', 3600); didn't help. I removed it again.
After that I had a look in the error logs and found this:
ap_pass_brigade failed with error 103: Software caused connection
abort
(problem is, I don't have access to the server settings - this is on a shared webspace...)
You can see the php configuration (php.ini) by phpinfo();
<?php
phpinfo();
Check the session.gc_maxlifetime values first then if you need to set it see the following ways.
You can set it with .htaccess file if you don't have permission for edit the php.ini file.
.htaccess
<IfModule mod_php5.c>
php_value session.cookie_lifetime 3600
php_value session.gc_maxlifetime 3600
</IfModule>
Even you can set it by ini_set();
<?php
ini_set('session.gc_maxlifetime', 3600);
For anyone who is interested: The session didn't actually expire, but the session variables disappeared (and reappeared again randomly).
This is discussed in a follow-up question I posted here:
php $_SESSION variables disappear and reappear randomly
You must have changed the session.name from default PHPSESSID to something else. Keep its default value session.name = PHPSESSID. Everything will be OK.
It's a PHP bug.
I'm using a java based uploading construct http://www.javaatwork.com/java-upload-applet/details.html that I tried running over night.
It basically stores everything on the server's hard drive (/var/www/private/$userId)
Makes sure that data is well-formed
Then passes it onto a permanent storage (Amazon S3).
After step 1 completes, I run the following code:
if($_SESSION['userId'])
{//Makes sure that data is well-formed}
else
{echo 'you are not logged in';}
I tried running this for four hours only to find you are not logged in printed to the screen.
Here are the appropriate directives in the cgi php.ini file (I'm using ubuntu 12.04 with apache2.)
session.gc_probability = 0
session.gc_divisor = 1000
session.gc_maxlifetime = 14400 //this is 30 hours, which is far greater than the 4 hours it was running
session.cache_expire = 1800
session.cookie_lifetime = 0
Most of these directives are the default with exception to session.gc_probability and session.gc_maxlifetime.
I was trying to resolve this issue and came across a really helpful blog by Jeff from which I inferred that browsers can cause the PHPSESSID cookie stored in the browser to be deleted if a period of inactivity on the website from within the browser occurs. He suggests
"Create a background JavaScript process in the browser that sends regular heartbeats to the server. Regenerate a new cookie with timed expiration, say, every 5 or 10 minutes."
http://www.codinghorror.com/blog/2008/04/your-session-has-timed-out.html
So I decided to do just that.
function myTimeoutFunction()
{
$.ajax({
url: "heartbeat.php",
success: function() {
}
});
setTimeout(myTimeoutFunction, 15*60*1000);
}
myTimeoutFunction();
heartbeat.php
<?php session_start(); ?>
I'm about to test this for an upload that should take ~4 hours. However I just read the following
In general you can say session.gc_maxlifetime specifies the maximum lifetime since the last change of your session data (not the last time session_start was called)
https://stackoverflow.com/a/1516338/784637
If I had 3 session variables, $_SESSION['userId'] $_SESSION['firstName'] $_SESSION['lastName'], would I need to reset all their values in heartbeat.php
session_start();
$_SESSION['userId'] = $_SESSION['userId'];
$_SESSION['firstName'] = $_SESSION['firstName'];
$_SESSION['lastName'] = $_SESSION['lastName'];
Or could I just reset one value
session_start();
$_SESSION['lastHeartbeat'] = time();
so that the other three would not expire?
The PHP session is kept as a whole; any changes in $_SESSION will update the change time and, by extensions, preserve the entire session.
Concerning the actual issue: PHP shouldn't GC sessions until the max time is reached, but that doesn't mean PHP is always clearing it. By default, sessions are kept in the /tmp (or another) directory and some Linux distros will have cron jobs that may clean the folder out from time to tome. Check for crons or other things that may clear the sessions independent of PHP too.
How to set session lifetime in PHP? I Want to set it to forever as long as the request is exist. The request is AJAX. My PHP code that handle AJAX request is:
// AJAX.php
<?php
session_start();
$_SESSION['counter'] = $_SESSION['counter'] + 1;
header('Content-type: application/json');
echo json_encode(array('tick' => $_SESSION['counter']));
?>
and the JavaScript:
$(document).ready(function() {
function check() {
getJSON('ajax.php');
}
function getJSON(url) {
return $.getJSON(
url,
function(data) {
$("#ticker").html(data.tick);
}
);
}
setInterval(function() {
check();
}, 10000); // Tick every 10 seconds
});
The session always resets after 300 seconds.
The sessions on PHP works with a Cookie type session, while on server-side the session information is constantly deleted.
For set the time life in php, you can use the function session_set_cookie_params, before the session_start:
session_set_cookie_params(3600,"/");
session_start();
For ex, 3600 seconds is one hour, for 2 hours 3600*2 = 7200.
But it is session cookie, the browser can expire it by itself, if you want to save large time sessions (like remember login), you need to save the data in the server and a standard cookie in the client side.
You can have a Table "Sessions":
session_id int
session_hash varchar(20)
session_data text
And validating a Cookie, you save the "session id" and the "hash" (for security) on client side, and you can save the session's data on the server side, ex:
On login:
setcookie('sessid', $sessionid, 604800); // One week or seven days
setcookie('sesshash', $sessionhash, 604800); // One week or seven days
// And save the session data:
saveSessionData($sessionid, $sessionhash, serialize($_SESSION)); // saveSessionData is your function
If the user return:
if (isset($_COOKIE['sessid'])) {
if (valide_session($_COOKIE['sessid'], $_COOKIE['sesshash'])) {
$_SESSION = unserialize(get_session_data($_COOKIE['sessid']));
} else {
// Dont validate the hash, possible session falsification
}
}
Obviously, save all session/cookies calls, before sending data.
Set following php parameters to same value in seconds:
session.cookie_lifetime
session.gc_maxlifetime
in php.ini, .htaccess or for example with
ini_set('session.cookie_lifetime', 86400);
ini_set('session.gc_maxlifetime', 86400);
for a day.
Links:
http://www.php.net/manual/en/session.configuration.php
http://www.php.net/manual/en/function.ini-set.php
Prior to PHP 7, the session_start() function did not directly accept any configuration options. Now you can do it this way
<?php
// This sends a persistent cookie that lasts a day.
session_start([
'cookie_lifetime' => 86400,
]);
?>
Reference: https://php.net/manual/en/function.session-start.php#example-5976
Sessions can be configured in your php.ini file or in your .htaccess file. Have a look at the PHP session documentation.
What you basically want to do is look for the line session.cookie_lifetime in php.ini and make it's value is 0 so that the session cookie is valid until the browser is closed. If you can't edit that file, you could add php_value session.cookie_lifetime 0 to your .htaccess file.
Since most sessions are stored in a COOKIE (as per the above comments and solutions) it is important to make sure the COOKIE is flagged as a SECURE one (front C#):
myHttpOnlyCookie.HttpOnly = true;
and/or vie php.ini (default TRUE since php 5.3):
session.cookie_httponly = True
I dont see this mentioned anywhere, but setting ini_set('session.gc_maxlifetime', $max_lifetime); in the PHP file itself is usually not going to have the desired affect if the php.ini file has a LOWER value and the server hosts multiple domains/vhosts. If you have User on X website, and the maxlifetime is set to 10 seconds (not a real value, this is just for example) in the PHP file and then have the maxlifetime set to 5 in php.ini something interesting/unexpected will happen if you have multiple domains/vhosts.
When a 2nd user visits a site that HASNT set ini_set('session.gc_maxlifetime', $max_lifetime); in it's PHP file and it defaults to whatever php.ini has, that will cause PHP's garbage collection to fire using 5 seconds rather than 10 seconds as maxlifetime, thus deleting the user's session which was supposed to last at least 10 seconds.
Therefore, this setting should almost NEVER go in the PHP file itself and should actually be in the vhost entry if your setup has this capability and falls into this type of scenario. The only exception to this is if your server only hosts 1 website/vhost who's PHP files will always override whatever php.ini has.
This happens because all sites use the same tmp dir to store session data. Another mitigation solution would be to set the session tmp dir per vhost. And yet another (not recommended) solution is to simply disable session.cookie_lifetime completely in php.ini by setting it to 0.
As long as the User does not delete their cookies or close their browser, the session should stay in existence.
I was working in a project where another developer wrote the code,while a user is login the session_start() as usual and then he is cheking like belows:
if($a['userName'] == $username && $a['password'] == $pwd)
{
$_SESSION['id'] = $a['id']; ?> <script language="javascript"type="text/javascript">window.location="host.php";</script> } else {
$msg= "Invalid Username Password";
}
And when a user want to use the form after couple of seconds its logout and user can not submit data.
I have tried increasing session life time duration:
$sessionCookieExpireTime=8*60*60;
session_set_cookie_params($sessionCookieExpireTime);
And also tried with increasing session lifetime in runtime like below:
ini_set('session.gc_maxlifetime', '3600');
And finally tried by increasing php.ini session lifetime .
Unfortunately those did not work.
One thing I should mention that,there is no session_destroy() for logout issues.
Thanks in advance.
What kind of server are you working on?
On a shared server that runs multiple sites that use a shared session directory the session.gc_maxlifetime is in effect the shortest lifetime of all sites accessing that shared directory.
If the problem is on a development server, find out where the session files are stored and look at what happens to them.
It is also possible that the directory where the sessions are stored is not writeable. In that case the session variable is never stored in the first place.
In all three cases: try to store the session files in a different directory. In code you have to set the session directory with session_save_path() before you call session_start().
The timeout occurs when user idle activity for certain time. There is no way to logout automatically unless using session_destroy.
It may be possible that your code
$a['id'];
returns null by chance.
Also, you need to checkout which page is getting logged out.
Giving the full code may be easy to identify the issue.