This is a really odd issue I'm having, and I'm having a hard time figuring out what's going on. Once in awhile, my cookie returns the value "deleted" instead of its proper value. Do any web browsers turn the cookie value to "deleted" if it has expired?
I've done a ton of Google searches and SO searches, and can't find anything like this.
Has anyone seen this before?
Check to ensure that when you call setcookie() you are setting a reasonable expiry time that will ensure that your cookie will not expire while being used.
From the php documentation (trimmed for important parts):
The time the cookie expires. This is a Unix timestamp so is in number
of seconds since the epoch. In other words, you'll most likely set
this with the time() function plus the number of seconds before you
want it to expire.
If set to 0, or omitted, the cookie will expire at the end of the
session (when the browser closes).
EDIT
further down the setcookie() documentation I found this
Cookies must be deleted with the same parameters as they were set
with. If the value argument is an empty string, or FALSE, and all
other arguments match a previous call to setcookie, then the cookie
with the specified name will be deleted from the remote client. This
is internally achieved by setting value to 'deleted' and expiration
time to one year in past.
i.e. it seems that your cookie is somewhere being updated to either an empty string or being set to false.
Related
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 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.
I've found that if I set a cookie with no expiration value and then create another cookie, the first cookie seems to be destroyed. Is this because a new session is created or is it because it is another request?
I've resolved my 'problem' by actually setting an expiration time, but I'm just curious to know what is actually happening when the second cookie is being created.
setcookie('cookieA', 'stuff', null, '/');
setcookie('cookieB', 'stuff', time() + 1200, '/');
$expire_time has it's own role in function setcookie and if it's less than now the cookie is deleted. There's no way not to set an expiration time or set it to null. It's simply a specification of cookies to achieve an expiration time (http://www.faqs.org/rfcs/rfc2965.html).
If you want the cookie to last forever, just set it to enormously huge number
Good Luck. :)
I have a problem with zend session.If i don't define expire date parameter for session while using it, and i close the browser in firefox the session destroyed.However, in IE it doesn't.
Thanks in advance
There are several parameters that can be manipulated to change the behavior of the PHP session management. These parameters are set in the php.ini file in the section headed [Session].
look for:
session.cookie_lifetime
This parameter holds the life of a session cookie in seconds and is used by PHP when setting the expiry date and time of a cookie. The default value of 0 sets up a session cookie that lasts only while the browser program is running. Setting this value to a number of seconds other than 0 sets up the cookie with an expiry date and time. The expiry date and time of the cookie is set as an absolute date and time, calculated by adding the cookie_lifetime value to the current date and time on the server machine.
[ The actual expiry of the cookie is performed by the browser, which compares the expiry date and time of the cookie with the client machine's date and time. If the date and time are incorrectly set on the client, a cookie might expire immediately or persist longer than expected. ]
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.