Understanding sessions in PHP - php

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.

Related

Can I make a session alive after when user closes his browser?

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

Session cannot remain for a long time its automatically destroyed

I have an issue with session , my session is automatically destroyed after few minutes of inactivity ,i think its must be 24 minutes i.e. 1440 seconds.I want to session remain for a long time , i am using .user.ini file on the server and set session.gc_maxlifetime to 31557600 seconds and session.cookie_lifetime to 31557600 but nothing happened for me .Its still logout after 1440 seconds of inactivity .I have also attached session value of png image of phpinfo.
I hope your answer or any help will work for me.Thanks.
I'm not sure why your settings aren't working but I use the following on my scripts to overwrite the php.ini settings for session maxlifetime and session_save_path:
session_save_path('/pathto/writable/dir/on/your/account');
ini_set('session.gc_maxlifetime', 24*60*60); // 24 hours; change as necessary
session_start();
NOTE:
The session_save_path is important because the default path is /tmp and it may get deleted by the system administrator on a daily/week? basis.
In my experience, it's always been related to the php.ini file. In your case, the master and local values for session.gc_maxlifetime contradict. (gc stands for garbage collect) They don't have to agree with each other, since the local value is used for the running script. It just means there's two php.ini files on your system, located in different places, and the local php.ini file is overriding the master php.ini file settings. But, I'd be VERY suspicious of any files on your server which call session_start() which use the master php.ini file, or call ini_set(...) within the script itself. The way this works is that no matter what the value is set to, it only has meaning when it's time to do garbage collecting. And garbage collecting is done by session_start() but you can also trigger garbage collecting in other ways such as SessionHandler::gc or a cronjob as explained later in this post. When called, it checks the last modified time of the file on the server storing your session information. If the number of seconds that elapsed since then is greater than the current session.gc_maxlifetime value, it will destroy the session. Note this is the last modified time, not the last accessed time, so you'll want to change your session data frequently to prevent it from getting deleted if it's not changing. You should also be aware that there is a setting here, called session.lazy_write which, if enabled, and is enabled by default, WILL NOT update the last modified time of the session file in the event which the session data did not change. Thus you'll want to disable this if you want to minimize the chances of sessions being destroyed early for some unknown reason, or store a timestamp on the session so the data is always changing and you know when the session was last used, if old, you can manually call session_destroy(). To start another session, you can commit with session_write_close() then recall session_start(). Or, do all 3 at once with session_regenerate_id(true).
Nextly, if you initialize a session with session_start() with your intended settings, and continue to call session_start() with the intended settings with each request, awesome. But, once any file on your server calls session_start() with a different value for session.gc_maxlifetime, either from using the master php.ini value in your case, or the script calling ini_set(...) and ignoring the master value, it will check the file's last modified time against a different value and destroy your session despite your intended settings - is assuming it gets elected to be one of the 1 in 100 requests which have to garbage collect.
Another thing to be concerned with is session.cookie_lifetime. A value of 0 here turns the cookie into a browser session cookie. This means if the user closes their browser, then the session cookie will be deleted by the browser. Your master value is using 0. But your local value is using 31557600 (the average seconds in a year). So you should be fine here. But keep your eyes open if any scripts on your server override this value, use a value of 0, or use the master php.ini file.
You should also be aware of the default 1% garbage collecting CHANCE that a session will be destroyed as defined by session.gc_probability and session.gc_divisor which default to 1 and 100 respectively. Garbage collecting is done when start_session() is called, if, and only if, the request "randomly" gets picked to be the request to manage the Garbage Collecting. This means that even if the number of defined seconds for a session elapsed for it to expire, start_session() STILL won't garbage collect even for this expired session. Rather, most users will notice their sessions expire exactly to schedule due to the cookie the browser keeps track of having its timestamp expire. But the session isn't enforced until PHP garbage collects as per the garbage collection change when start_session() is called. If you want sessions to be wiped clean when they've expired, and start a new one, you should use session_regenerate_id(true). The true here means trash the $_SESSION data tied to the previous session and toss them a different session id as though their session expired.
You should also be aware that some systems, such as debian-based systems, have a cronjob which runs every 30 minutes to garbage collect based on the master php.ini configuration information.
See the comment here by Christopher Kramer: http://php.net/manual/en/session.configuration.php
I cannot verify if the above information about debian systems is true, but I've considered garbage collecting with a cronjob before to speed up users' requests so no one user gets stuck having to wait for their request to go through due to the maintenance which a cronjob could be handling.
In terms of solutions here:
One solution here is to adjust the master php.ini value, if you have access to it, then search your server for any PHP files which might be calling ini_set to see if there's any files conflicting with your settings to make sure they're not causing the unexpected behavior.
Another solution would be to limit such conflicts the script might be encountering by: (1.) renaming the session.name to something other than PHPSESSID. And/or (2.) changing the session.save_path path. Either of these by itself would suffice and avoid script conflicts.
A temporary fix might be to do something like change your session.gc_probability to 0 so the session garbage collecting NEVER happens. Or make it a much smaller chance by using something like session.gc_probability=1 and session.gc_divisor=100000. Then setup a cronjob to call SessionHandler::gc
See http://php.net/manual/en/session.configuration.php for more session config information.
Lastly I'd like to point you to this post which suggests good practices to prevent session hijacking, and for the most-part is the post I referenced when putting this post together: https://stackoverflow.com/a/1270960/466314
Note that it uses an approach to sessions which makes sure sessions expire on time, and not later (although browsers do a good job of this already with cookie garbage collecting). And it also makes changes to sessions, keeping track of the session last used time, so the session data is always changing to avoid the issue with session.lazy_write.
This concludes my suggestions. If you can narrow down the issue, try searching stackoverflow or asking a new question.
As stated here :
The best solution is to implement a session timeout of your own. Use a
simple time stamp that denotes the time of the last activity (i.e.
request) and update it with every request:
if (isset($_SESSION['LAST_ACTIVITY']) && (time() - $_SESSION['LAST_ACTIVITY'] > 1800)) {
// last request was more than 30 minutes ago
session_unset(); // unset $_SESSION variable for the run-time
session_destroy(); // destroy session data in storage
}
$_SESSION['LAST_ACTIVITY'] = time(); // update last activity time stamp
Updating the session data with every request also changes the session
file's modification date so that the session is not removed by the
garbage collector prematurely.

Can't extend session expiry

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.

How does PHP know when to delete a session?

I thought that sessions were stored on the client side because of the session getting deleted when the browser closes. However, today I've been told that this is not true and that the session is stored on the server.
So how does a session know when a browser was closed, so that the session gets deleted?
It doesn't. There are two factors at play:
the lifetime of the cookie on the client-side;
This cookie contains the session ID. It does not have anything to do with the session data itself.
The manual probably doesn't stress this enough:
This has nothing to do with lifetime of a session
Whatever you set this setting to, it won't change how long sessions
live on your server.
This only changes HTTP cache expiration time (Expires: and
Cache-Control: max-age headers), which advise browser for how long it
can keep pages cached in user's cache without having to reload them
from the server.
the lifetime of the session data on the server-side;
The session is "activated" via a lookup with the session ID from the client. Its lifetime is controlled via session garbage collection settings discussed here.
A commenter posted on the session.cache_expire documentation page, presumably actually talking about the session data:
What most people also don't know, is that most Linux distributions
(Debian and Ubuntu for me atleast) have a cronbjob that cleans up your
session dir using the value set in the global /etc/php5/php.ini (which
defaults to 24mins). So even if you set a value larger in your
scripts, the cronbjob will still cleanup sessions using the global
value.
If you run into that situation, you can set the global value higher in
/etc/php5/php.ini, disable the cronjob or even better, do your own
session cleanup in a non-systemwide directory or a database.
As you can see, confusing abounds amongst the community when making the distinction between session tracking and session data storage.
Session is identified by a cookie, which does get stored in the browser. It can have an expiry date/time, or it can be set to expire when the browser is closed. When the cookie expires, you can't identify your session storage any more, and the session is effectively expired. It does not get deleted unless the system admins or programmers specifically make a cleanup.
EDIT Just noticed the PHP tag. For how PHP cleans up its session files, check this question.
The server has no way of knowing when the browser is closed.
Closing the browser will delete the session ID cookie from the client.
The session is deleted from the server once there are no requests in a given amount of time (the session timeout).

How does a server judge a session to be expired and how can the expiry time be changed?

I understand that a session cookie can be given a lifetime (session.cookie_lifetime) and that after that lifetime the cookie expires regardless of whether a user interacts with the site.
I would therefore assume to set this to 0 to indicate they should stay live until the browser closes.
I also think I understand that the garbage collection lifetime (session.gc_maxlifetime) can be set for a cookie and that as long as a user does not exceed this time between their clicks then the cookie will remain active.
To test this out I've been trying to get a 10 second session timeout.
I tried:
ini_set('session.gc_maxlifetime',10);
but the session doesn't timeout after 1 minute at least.
Is this because I am only saying to the garbage collector that the session has a life of 10 seconds but I'm not actually triggering the garbage collector?
How do you set the garbage collector going or does it just run every time a session is requested?
First of all, don't confuse cookie settings (which are client-side) and garbage collection (which is server-side). Cookie settings only affect the expiration of the session_id. Session data may still exist on the server even if the browser has removed the cookie and, on the contrary, the server can remove the data while the session_id is still remembered by the browser.
The cookie can be set to expire when you close the browser or in a specific date and time (I believe the default option is the first one, but I'd have to check it). In both cases, if the user interacts with the site the cookie will remain valid since it's renewed on each response.
Session data is removed when the garbage collection is launched but you must take into account that:
The garbage collection is started randomly, triggered by a page request.
It removes session data not modified in more that gc_maxlifetime seconds.
By default, session data is stored in files and PHP doesn't track what site owns what files. That means that storing sessions in the default shared location makes you lose control on session expiration: the site that's configured to keep session data for the shortest time is likely to remove data from other sites with longer time.
To sum up, if you want full control on your data lifetime you need to store session data in a private directory, e.g.:
session_save_path('/home/foo/sessions');
ini_set('session.gc_maxlifetime', 3*60*60); // 3 hours
ini_set('session.use_only_cookies', TRUE);
session_start();
The server has a default timeout set in it's INI files, if not overridden from within a script. In apache it is set from within PHP.ini i believe. You also need to enable the garbage collection function, which I believe is also set in php.ini.

Categories