I am currently building a website where basket data etc is being stored in session variables. The issue is that with default settings the session expires at the end of the session.
I have tried a range of suggestions as to how to modify the session expiry date, and on using $params = session_get_cookie_params(); var_dump($params); I can see that the session expiration has changed to what I set.
My issue using the web inspector on Safari 8.0.8, the session cookie still says to expire at the end of the session. I have also tried manually updating the cookie using the setcookie() command.
Currently I'm running on a localhost, but with a view to initially deploy on a shared web server.
Is this expected? A problem with safari? Any ideas?
Session timeout is a notion that has to be implemented in code if you want strict guarantees; that's the only way you can be absolutely certain that no session ever will survive after X minutes of inactivity.
If relaxing this requirement a little is acceptable and you are fine with placing a lower bound instead of a strict limit to the duration, you can do so easily and without writing custom logic.
Convenience in relaxed environments: how and why
If your sessions are implemented with cookies (which they probably are), and if the clients are not malicious, you can set an upper bound on the session duration by tweaking certain parameters. If you are using PHP's default session handling with cookies, setting session.gc_maxlifetime along with session_set_cookie_params should work for you like this:
// server should keep session data for AT LEAST 1 hour
ini_set('session.gc_maxlifetime', 3600);
// each client should remember their session id for EXACTLY 1 hour
session_set_cookie_params(3600);
session_start(); // ready to go!
This works by configuring the server to keep session data around for at least one hour of inactivity and instructing your clients that they should "forget" their session id after the same time span. Both of these steps are required to achieve the expected result.
If you don't tell the clients to forget their session id after an hour (or if the clients are malicious and choose to ignore your instructions) they will keep using the same session id and its effective duration will be non-deterministic. That is because sessions whose lifetime has expired on the server side are not garbage-collected immediately but only whenever the session GC kicks in.
GC is a potentially expensive process, so typically the probability is rather small or even zero (a website getting huge numbers of hits will probably forgo probabilistic GC entirely and schedule it to happen in the background every X minutes). In both cases (assuming non-cooperating clients) the lower bound for effective session lifetimes will be session.gc_maxlifetime, but the upper bound will be unpredictable.
If you don't set session.gc_maxlifetime to the same time span then the server might discard idle session data earlier than that; in this case, a client that still remembers their session id will present it but the server will find no data associated with that session, effectively behaving as if the session had just started.
Certainty in critical environments
You can make things completely controllable by using custom logic to also place an upper bound on session inactivity; together with the lower bound from above this results in a strict setting.
Do this by saving the upper bound together with the rest of the session data:
session_start(); // ready to go!
$now = time();
if (isset($_SESSION['discard_after']) && $now > $_SESSION['discard_after']) {
// this session has worn out its welcome; kill it and start a brand new one
session_unset();
session_destroy();
session_start();
}
// either new or old, it should live at most for another hour
$_SESSION['discard_after'] = $now + 3600;
Session id persistence
So far we have not been concerned at all with the exact values of each session id, only with the requirement that the data should exist as long as we need them to. Be aware that in the (unlikely) case that session ids matter to you, care must be taken to regenerate them with session_regenerate_id when required.
Related
How can I keep the user's session active, even if they accidentally closed their browser. Like in Facebook for example.
If you log in to their site and you close the tab or the browser, when you open a browser again and visits Facebook, they will automatically detect the active user and will not redirect you to the log in page.
How do I do that?
There's two relevant settings that control session's lifetime.
The first is session.cookie-lifetime. This is the lifetime of the cookie, which by default is 0, which means the cookie is destroyed when the browser is closed. You can set a longer lifetime by increasing this variable. It is relative to the server time, so you need to account for differences in the time in your clients' machine and your server's. Assuming they were the same, setting the option to i.e. 3600 would mean the session would expire in an hour. If you want to keep the session alive for a very long time, you increase this number.
However changing this value is not enough. There's also session.gc-maxlifetime, which is the time after which the session data is seen as garbage in the storage and is destroyed. This differs from session.cookie-lifetime because this option checks the last access time of the session data, so it is relative to the time the session data was last used (i.e. when the user was last active). Even if you set your session.cookie-lifetime to a high value, it'll not be enough because session.gc_maxlifetime is relatively low usually (1440 is the default, which is only 24 minutes).
While you can set these settings both to relatively high values and have it working, I would recommend against doing so, as this will leave a lot of unnecessary session data hanging around in your session storage, due to the GC not collecting actual dead session (which also increases the chance of someone hijacking a session in a system that is not properly secured). A better approach is making a remember me cookie. Basically you assign the user's ID and some authentication token that you store in the database for each user (this is to prevent someone spoofing the cookie) in the cookie, and give it a long lifetime. In your application's initialization code you'll check if the user is logged in. If he/she is not logged in, you'll check if the remember me cookie is set. If it is, you pull the user from the database based on the user ID in the cookie, and then validate the authentication token in the db is the same one as in the cookie. If they match, you simply create the session and log the user in automatically.
For anyone that come across this same issue, to keep the session cookie set for a long time is easy, on the login form, when you are creating the session for first time use this code, it will set the cookie time for a year (use your own time as its needed).
ini_set('session.cookie_lifetime', 60 * 60 * 24 * 365);
ini_set('session.gc-maxlifetime', 60 * 60 * 24 * 365);
session_start();
That should set the PHPSESSID cookie and your session will be safe... but is not the most secure way, so use it if you don't mind security issues
By default, PHP keeps a user's session open until their browser is closed. You can override that behaviour by changing the session.cookie-lifetime INI setting:
http://www.php.net/manual/en/session.configuration.php
However please see rekot post for a full answer
You should use cookies: http://php.net/manual/en/function.setcookie.php
Just store there some unique value that will help you identify the user.
Anyway, I strongly recommend you using some kind of framework, like CodeIgniter or Zend Framework, unless you're just learning how it works. It is easy to make critical mistakes in such a code and most frameworks are already well tested and safe to use.
Hello everyone,
This is mostly a proof-reading question, if I may put it like that.
So, I need to create a persistent session for a webshop/e-commerce site. A session lasting over the specified time is not really an issue, but making it last for, say 24 hours since the last click, is important.
Why: To quickly check cart status, last visited pages, tax- and currency choices etc. without querying, let alone writing to the database or some other storage mechanism on each page request. The cart and browsing history are complicated enough to be stored in a session, Language, currency etc. could admittedly be cookies as well.
Most of our site is cached as html, and only a few elements like cart contents are strapped to the otherwise finished page. We have very good server response times, and I'd like to keep them that way and avoid anything too heavy especially for users who don't have anything in their cart.
I've gone through quite a few posts on StackOverflow and Google in general to get a basic idea of this. Most results were about being concerned and making sure the session would close in any case after a certain period of time. This case is the opposite.
So, PHP has a few session setting in the ini, of which three are the most important:
session.gc_maxlifetime: Determines the time after which a garbage collection cycle will remove the file. This is not an exact time, it
is a minimum time for the session to last since the last change of
the $_SESSION variable data. Default is 1440 seconds / 24 minutes.
session.cookie_lifetime: This is the lifetime for the PHPSESSID -cookie which enables PHP to fetch a corresponding session. This defaults to zero, which means the cookie is destroyed when the
browser closes. It could thus live for one millisecond or two years
if set to zero.
Setting this to an integer value will give the cookie an expiration
from the time it is first set. The lifetime will not be forwarded on subsequent page loads with session starts.
session.save_path: Tells PHP where to save the session files. This is also the directory which will get garbage collected for
expired sessions.
So here's an example "session header" I came up with. It should at least ensure session files are stored for at least $lt seconds from the first session start, and the session cookie $lt seconds from the last execution of this script. In the question -comment the session gets written to, which would in my thoughts cause the file time to get updated, and thus push session expiry to $lt since the last execution of the script.
<?php
/**
* Example "header" to start a session in a simple environment
*/
// Lifetime setting in seconds
$lt = 1440;
// Set maxlives to $lt
ini_set('session.gc_maxlifetime', $lt);
ini_set('session.cookie_lifetime', $lt);
// Save sessions in a different directory than other sessions. The gc
// will run on a probability base on each session start and clean the default
// directory. If our (longer) sessions are saved in a shared session dir
// for other PHP scripts which have a shorter expiry, our files will also be
// removed.
// If we run a single site, use php.ini to set the above max lives,
// or are the only ones using sessions, we can omit this directive.
ini_set('session.save_path', '/var/www/mysite/separate-session-dir');
// Start the session AFTER setting the parameters
session_start();
// Update the cookie expiration on a page load.
// This will simply overwrite the system-set session cookie.
setcookie(session_name(),session_id(),time()+$lt, '/');
// QUESTION: Would this forward the session FILE lifetime by writing to it.
$_SESSION['random-field'] = uniqid();
// Do what you really meant to do with your script.
So. Here it is. Does this work as a simple way to ensure sessions live for at least $lt seconds, or have I overlooked something?
I am currently running this on our server, without the ini_sets and save path as they are set in the php.ini instead. The cookie part seems easy enough to verify by closing the browser and returning to see if a cart is emptied or not, but the file -part is harder to verify and I'd like your input about this.
PS. Sorry about stuffing e-commerce/webshop tags, but I searched for hours for a post which would look at things from this perspective.
I'm trying to implement a system to keep an user logged in for a while. I can do that by using cookies and storing it into database and then identifying him.
But recently I heard a session can be alive even when user closes his browser and opens a new window. I mean can a session still be available after closing/opening the browser again (or even multiple time)?
How much time (maximum) can I use $_SESSION["LoginValidation"] in following script?
<?php
session_start();
$_SESSION["LoginValidation"] = ture;
Currently that session will be available until closing the browser.
In order to make the session persist after closing the browser you need to set an expiry time for the session cookie. A cookie without an expiry time is deleted when the browser is closed, and is normally referred to as a session cookie (which is not the same thing as a PHP session - just related).
(side note: if your browser is configured to "save open tabs" at exit, then the session cookies may be saved by the browser even though they should be deleted)
So you could just set session.cookie_lifetime to a large value. But that doesn't stop the session data stored on your server from being deleted - to keep the data for longer you need to up the value for session.gc_maxlifetime.
BUT THIS IS THE WRONG WAY TO FIX THE PROBLEM
There are security and capacity implications to implementing such persistent sessions - you should certainly NEVER implement this as default behaviour - only where the user has explicitly given their consent.
Using a "Remember me" cookie as a sort of lightweight session system is the best practice solution. Give it a random value (suggest you use a reasonably reliable source of random numbers, e.g. base64_encode(openssl_random_pseudo_bytes(64)) and a name which does not conflict with other cookies, and store it along with the data you really want to persist across the actual sessions (e.g. authenticaticated username).
Approach 1) session.cookie-lifetime : This is the lifetime of the cookie, which by default is 0, which means the cookie is destroyed when the browser is closed. You can set a longer lifetime by increasing this variable.
It is relative to the server time, so you need to account for differences in the time in your clients' machine and your server's.
There's also session.gc-maxlifetime, which is the time after which the session data is seen as garbage in the storage and is destroyed.
While you can set these settings both to relatively high values and have it working, I would recommend against doing so, as this will leave a lot of unnecessary session data hanging around in your session storage, due to the GC not collecting actual dead session
Or
another approach is for session to make alive even after closing of browser save session in db and get its id , and set that id in user cookie via
setcookie("name","value",time()+$int);
so you can fetch that value from $_COOKIE["name"]; use it to get session variables from data base
My questions:
session.gc_maxlifetime in php.ini: Does the session.gc_maxlifetime start from the session_start() point or the latest request to the server? (Assuming I have a few requests without a session_start() being called.)
What is the best practice to use the $_SESSION object so as to not waste precious RAM (automatically clear idle sessions in time)? Or is this something that happens automatically by the time mentioned in session.gc_maxlifetime?
How do I correctly check if a session has expired (as against a session which never got created)? Or are both the same? isset($_SESSION['any_variable']) === FALSE
Assuming I don't have control over php.ini, how do I increase session.gc_maxlifetime?
session_start(): If a session has "timed out", calling session_start will always start a session with the previous variables unavailable(a brand new session). Is that correct?
Good question! I would assume that the default filesystem session handler would go off last access but not all filesystems support an atime timestamp. I'll see what I can find out on that front.
Sessions are by default stored as files on disc. They only take memory when loaded. Unless you've built a custom session handler that stores sessions in a RAM disc or in a memcache server or similar, or unless you're storing a huge amount of state in the user's session I doubt memory use will be a major concern.
When session_start() is called the previous session data is loaded into PHP. If the session has expired then there will be no session data to load and a new empty session will be created. So yeah, if you check for the existence of a variable in $_SESSION that you're expecting to always be there then you can use that to determine if the user's session has expired (but only after session_start() was called).
Simply set gc_max_lifetime to how long you want sessions to last in seconds. 600 is 10 minutes, 86400 is one day, etc.
Yes (with some caveats, see below).
There are a few things you need to be aware of with sessions though. First is that there's two components to a session: A server side state record that holds all the data stored in the session, and a client side token that PHP uses to associate a particular user with a particular state record. Normally the client side token is a cookie. Cookies have their own expiration date, so it's possible that the session can expire before the session state is due to do so. In that case the user will stop sending the token and the session state is effectively lost. If you're adjusting how long a session lasts you need to set both the server side state expiration time and the client side cookie expiration time.
As for stale state, the session garbage collection system doesn't always run every time session_start() is called. If it was the overhead would be crippling to a big PHP site with a lot of sessions. There are configuration options that specify the probability that the GC will run on any given invocation of session_start (I believes it defaults to 1%). If it doesn't run then a stale session record may still be treated as valid and used to populate $_SESSION. It probably won't have a serious effect on your system but it's something you need to bear in mind.
How can I keep the user's session active, even if they accidentally closed their browser. Like in Facebook for example.
If you log in to their site and you close the tab or the browser, when you open a browser again and visits Facebook, they will automatically detect the active user and will not redirect you to the log in page.
How do I do that?
There's two relevant settings that control session's lifetime.
The first is session.cookie-lifetime. This is the lifetime of the cookie, which by default is 0, which means the cookie is destroyed when the browser is closed. You can set a longer lifetime by increasing this variable. It is relative to the server time, so you need to account for differences in the time in your clients' machine and your server's. Assuming they were the same, setting the option to i.e. 3600 would mean the session would expire in an hour. If you want to keep the session alive for a very long time, you increase this number.
However changing this value is not enough. There's also session.gc-maxlifetime, which is the time after which the session data is seen as garbage in the storage and is destroyed. This differs from session.cookie-lifetime because this option checks the last access time of the session data, so it is relative to the time the session data was last used (i.e. when the user was last active). Even if you set your session.cookie-lifetime to a high value, it'll not be enough because session.gc_maxlifetime is relatively low usually (1440 is the default, which is only 24 minutes).
While you can set these settings both to relatively high values and have it working, I would recommend against doing so, as this will leave a lot of unnecessary session data hanging around in your session storage, due to the GC not collecting actual dead session (which also increases the chance of someone hijacking a session in a system that is not properly secured). A better approach is making a remember me cookie. Basically you assign the user's ID and some authentication token that you store in the database for each user (this is to prevent someone spoofing the cookie) in the cookie, and give it a long lifetime. In your application's initialization code you'll check if the user is logged in. If he/she is not logged in, you'll check if the remember me cookie is set. If it is, you pull the user from the database based on the user ID in the cookie, and then validate the authentication token in the db is the same one as in the cookie. If they match, you simply create the session and log the user in automatically.
For anyone that come across this same issue, to keep the session cookie set for a long time is easy, on the login form, when you are creating the session for first time use this code, it will set the cookie time for a year (use your own time as its needed).
ini_set('session.cookie_lifetime', 60 * 60 * 24 * 365);
ini_set('session.gc-maxlifetime', 60 * 60 * 24 * 365);
session_start();
That should set the PHPSESSID cookie and your session will be safe... but is not the most secure way, so use it if you don't mind security issues
By default, PHP keeps a user's session open until their browser is closed. You can override that behaviour by changing the session.cookie-lifetime INI setting:
http://www.php.net/manual/en/session.configuration.php
However please see rekot post for a full answer
You should use cookies: http://php.net/manual/en/function.setcookie.php
Just store there some unique value that will help you identify the user.
Anyway, I strongly recommend you using some kind of framework, like CodeIgniter or Zend Framework, unless you're just learning how it works. It is easy to make critical mistakes in such a code and most frameworks are already well tested and safe to use.