Beware of the Cookie Monster (http://preview.tinyurl.com/5964ho) -- always set $secure to true for cookies set within secure environments (i.e. when your code is being accessed via HTTPS).
Also be advised that PHP's session manager doesn't do that automatically -- by default starting a session within a secure environment sets a cookie which is then accessible via non-secure channels. For sessions started in secure environments use <? INI_Set('session.cookie_secure',true); ?> before starting the session.
setcookie
bogdan at moongate dot ro
11-Sep-2008 09:58
11-Sep-2008 09:58
Link dot random at gmail dot com
03-Sep-2008 09:49
03-Sep-2008 09:49
Platform: Windows XP SP2, IIS5.2, Php5.2.5:
I've had my share of sessioning problems and all of them came from the fact that i'm using Php Designer 2007 as my php editor.. Cookies must be sent before any output from your script including <html> and <head> tags as well as any whitespaces, well this php editor was sending a sort of data before the headers that i want to send which cause to have the given error: "Cannot send session Cookie - headers already sent", even after using output buffers to fixe the problem of the time the cookies are sent i still had the same problem.
Solution? Don't use any editor..! notepad is all you need... Used notepad, and it worked like magic!
tee at fee dot com
22-Aug-2008 08:15
22-Aug-2008 08:15
The link above to Netscape Cookie Specification for explanation of each of the parameters no longer works.
Here's an alternative - http://curl.haxx.se/rfc/cookie_spec.html
php at gigadepot dot com
27-Jul-2008 05:17
27-Jul-2008 05:17
If you use a multiple cookie name with the function bellow
example :
createcookie("member[name]","jack");
don't work with array
error with "rawurlencode($name)"
I'm use : createcookie(array('member'=>'name'),'jack');
<?php
createCookie($name, $value='', $maxage=0, $path='',$domain='', $secure=false, $HTTPOnly=false)
{
if(is_array($name))
{
list($k,$v) = each($name);
$name = $k.'['.$v.']';
}
$ob = ini_get('output_buffering');
// Abort the method if headers have already been sent, except when output buffering has been enabled
if ( headers_sent() && (bool) $ob === false || strtolower($ob) == 'off' )
return false;
if ( !empty($domain) )
{
// Fix the domain to accept domains with and without 'www.'.
if ( strtolower( substr($domain, 0, 4) ) == 'www.' ) $domain = substr($domain, 4);
// Add the dot prefix to ensure compatibility with subdomains
if ( substr($domain, 0, 1) != '.' ) $domain = '.'.$domain;
// Remove port information.
$port = strpos($domain, ':');
if ( $port !== false ) $domain = substr($domain, 0, $port);
}
// Prevent "headers already sent" error with utf8 support (BOM)
//if ( utf8_support ) header('Content-Type: text/html; charset=utf-8');
if(is_array($name))
{
header('Set-Cookie: '.$name.'='.rawurlencode($value)
.(empty($domain) ? '' : '; Domain='.$domain)
.(empty($maxage) ? '' : '; Max-Age='.$maxage)
.(empty($path) ? '' : '; Path='.$path)
.(!$secure ? '' : '; Secure')
.(!$HTTPOnly ? '' : '; HttpOnly'), false);
}else{
header('Set-Cookie: '.rawurlencode($name).'='.rawurlencode($value)
.(empty($domain) ? '' : '; Domain='.$domain)
.(empty($maxage) ? '' : '; Max-Age='.$maxage)
.(empty($path) ? '' : '; Path='.$path)
.(!$secure ? '' : '; Secure')
.(!$HTTPOnly ? '' : '; HttpOnly'), false);
}
return true;
}
?>
aymeric dot jouno at free dot fr
26-Jun-2008 04:28
26-Jun-2008 04:28
the cookie use is different as you're using firefox or IE
so if you've got probleme to kill cookie
dont forget to specify domain.
setcookie($name, "", time()-60*60*24*30, '/');
in procedurale methode theire as usual no probleme because
the place where is created the cookie is the same you kill it.
but in POO point of view, if you got an object who manage cookie, it can be call from anywhere of your site.
so the domaine mismatch...
dont forget '/' to get your cookie grant from all you directory.
user at NOSPAM dot example dot com
26-Jun-2008 03:25
26-Jun-2008 03:25
Note for Opera (and maybe FF) users - if you're having trouble deleting the PHPSESSID cookie, ensure you set the path when deleting, or Opera will ignore and send the cookie with all future requests in that session, for example:
session_start()
// creates a cookie using "Set-Cookie: PHPSESSID=b45c661720e0b3d27954a7d0225b1156; path=/"
Then to delete...
session_start();
$_SESSION = array(); // destroy all $_SESSION data
setcookie(session_name(), "", time() - 3600, "/");
session_destroy();
Note the last parameter on setcookie() to set the path, Opera requires this.
yawgmothcz at gmail dot com
05-Jun-2008 10:01
05-Jun-2008 10:01
Expiration time is set on the server side, based on server time(), howerver client must decide whether to use the cookie or not only by his system time, which may be different by a lot more than 30 seconds. So not accepting the cookie might not be your IE7 fault at all, just don't set cookie for such a short period, it's not reliable.
Jeff Stevenson
20-May-2008 06:50
20-May-2008 06:50
IE7 doesn't save cookies with short expiration times. For instance when I set the expiration to be time()+30 for 30 seconds, IE7 wasn't saving the cookie.
When I changed my code to be time()+4000 it worked!
Stupid IE
jphansen at uga dot edu
22-Apr-2008 12:43
22-Apr-2008 12:43
If you'd like to set a cookie for a prolonged time, here's an example for a cooking lasting 1 year, which passes seconds--60 seconds * 60 minutes * 24 hours * 365 days = 1 year--as the $expire argument.
<?php
setcookie($name, $value, time()+(60*60*24*365));
?>
isooik at gmail-antispam dot com
26-Feb-2008 02:20
26-Feb-2008 02:20
A small bug in the function below:
Change:
.(empty($expires) ? '' : '; Max-Age='.$maxage)
into:
.(empty($maxage) ? '' : '; Max-Age='.$maxage)
Regards,
Isaak
isooik at gmail-antispam dot com
26-Feb-2008 01:18
26-Feb-2008 01:18
Here's a more advanced version of the php setcookie() alternative function:
<?php
/**
* A better alternative (RFC 2109 compatible) to the php setcookie() function
*
* @param string Name of the cookie
* @param string Value of the cookie
* @param int Lifetime of the cookie
* @param string Path where the cookie can be used
* @param string Domain which can read the cookie
* @param bool Secure mode?
* @param bool Only allow HTTP usage?
* @return bool True or false whether the method has successfully run
*/
function createCookie($name, $value='', $maxage=0, $path='', $domain='', $secure=false, $HTTPOnly=false)
{
$ob = ini_get('output_buffering');
// Abort the method if headers have already been sent, except when output buffering has been enabled
if ( headers_sent() && (bool) $ob === false || strtolower($ob) == 'off' )
return false;
if ( !empty($domain) )
{
// Fix the domain to accept domains with and without 'www.'.
if ( strtolower( substr($domain, 0, 4) ) == 'www.' ) $domain = substr($domain, 4);
// Add the dot prefix to ensure compatibility with subdomains
if ( substr($domain, 0, 1) != '.' ) $domain = '.'.$domain;
// Remove port information.
$port = strpos($domain, ':');
if ( $port !== false ) $domain = substr($domain, 0, $port);
}
// Prevent "headers already sent" error with utf8 support (BOM)
//if ( utf8_support ) header('Content-Type: text/html; charset=utf-8');
header('Set-Cookie: '.rawurlencode($name).'='.rawurlencode($value)
.(empty($domain) ? '' : '; Domain='.$domain)
.(empty($maxage) ? '' : '; Max-Age='.$maxage)
.(empty($path) ? '' : '; Path='.$path)
.(!$secure ? '' : '; Secure')
.(!$HTTPOnly ? '' : '; HttpOnly'), false);
return true;
}
?>
Regards,
Isaak
sebasg37 at gmail dot com
08-Feb-2008 03:10
08-Feb-2008 03:10
As said, you can avoid the annoying "headers already sent in line..", using the ob_start() (function that serves as buffer) doing this:
<?php
ob_start();
echo "somtehing";
setcookie("cookie", "value"); /* if you didn't add the ob_start() function at this point the headers would have been already sent and the cookie have not been saved */
ob_end_flush();
?>
dave at shout411 dot com
04-Feb-2008 01:51
04-Feb-2008 01:51
firefox will permit a short cookie length, eg +60
IE6 (all i tested as yet) will not create the cookie for +60
It will though accept +120 (two minutes)
d.
globexdesigns at gmail dot com
07-Dec-2007 12:45
07-Dec-2007 12:45
Quotes are important when giving cookies parameters. If it looks like you can't delete your cookies, or cookies doesn't delete verify that both your cookies names are consistent.
<?php
setcookie(mycookie, $test, time() + 3600);
setcookie("mycookie","",time() - 3600);
?>
The above is wrong. But the examples are right:
<?php
setcookie("mycookie", $test, time() + 3600);
setcookie("mycookie","",time() - 3600);
?>
<?php
setcookie(mycookie, $test, time() + 3600);
setcookie(mycookie,"",time() - 3600);
?>
Alexander Fleischer
29-Nov-2007 04:48
29-Nov-2007 04:48
Using $httponly also prevents the browser to pass a cookie to the java class loader. If a session cookie is required to access java .class / .jar files, loading of the applet will fail. In this case, session.cookie_httponly may be switched off.
jim at combined-minds dot net
23-Nov-2007 01:23
23-Nov-2007 01:23
markraymondmason at yahoo dot ca:
Like said at the top of the page, no output may be send to the browser when trying to create a cookie. So it doesn't need to be at the top of a file, just before output.
soeren dot spreng at gmail dot com
22-Nov-2007 10:35
22-Nov-2007 10:35
Beware: The Internet Explorer doesn't accept Cookies with an expiretime, which is to long. time() + time() for example doesn't work and the Cookie won't be created!
markraymondmason at yahoo dot ca
10-Nov-2007 06:19
10-Nov-2007 06:19
Note for newbies - just found out that the cookie must be set at the very top of your page. Half-way through a page full of html is no good.
manfred dot p dot wilke at gmail dot com
05-Nov-2007 05:08
05-Nov-2007 05:08
mrvanes at gmail dot com:
The note did you wrote about the use of underscore (_) on 06-Jun-2006 11:22 basicaly saved my life.
I was encountering some troubles with Windows_Xp and IE 6 and 7, because IE does not recognize a value like "aaabbb_cccddd" (i think).
After change the value, deleting the underscore, the cookie works fine.
This is the complete line that worked:
setcookie("value", date("Y-m-d"), time()+3600, "/", false, 0);
Tks very much.
(PS.: Sorry for my bad english.)
amalinovski at yahoo dot com
30-Oct-2007 08:29
30-Oct-2007 08:29
Problem with setcookie() and UTF-8 recognizing by browser:
- If you want to use UTF-8 characters in your php file, some editors insert special bytes in the very beginning of the file. This prevents setcookie() from working, because these special bytes are sent to the browser BEFORE the header, and you get "Header already sent" error;
- If you delete these bytes (with a hex editor), setcookie() will work fine, but the browser will STOP recognizing UTF-8 encoding automatically! The user will need to set the encoding to UTF-8 manually to see your page correctly.
Here's how to get out of this:
Instead of:
<?
setcookie("aaa", "bbb");
?>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
Write this:
<?
header("Content-Type: text/html; charset=utf-8");
setcookie("aaa", "bbb");
?>
<html>
<head>
...
(make sure you have no special bytes before "<?")
mikeh at view22 dot com
19-Oct-2007 06:56
19-Oct-2007 06:56
Observed what I think is a bug: session cookies were expiring even though the session was still active. (To test, set a cookie expiry of 5 seconds and keep hitting the page every second. The session will expire and create a new SESSID after 5 seconds despite the fact that you hit the page only a second ago.)
Calling this function before starting the session fixed it. It copies the cookie contents back to itself while forcing an update to the expiry time in the cookie.
function FreshenSessionCookie($lifetimeSeconds, $cookieName = 'PHPSESSID')
{
if (isset($_COOKIE[$cookieName]))
{
$data = $_COOKIE[$cookieName];
$timeout = time()+$lifetimeSeconds;
setcookie($cookieName, $data, $timeout);
}
}
sony-santos at bol dot com dot br
02-Oct-2007 12:40
02-Oct-2007 12:40
The emulation proposed by jcastromail (below) is useful to solution a frequent problem: the server's and client's clock synchronization. By setting and deleting cookies via Javascript, the browser will use the client's clock as basis and the cookie will expire at desired time, no matter if it is seven years in the past or in the future.
cwillard at fastmail dot fm
22-Aug-2007 02:55
22-Aug-2007 02:55
If you're looking to set multiple values in your cookie (rather than setting multiple cookies) you might find these useful.
<?php
function build_cookie($var_array) {
if (is_array($var_array)) {
foreach ($var_array as $index => $data) {
$out.= ($data!="") ? $index."=".$data."|" : "";
}
}
return rtrim($out,"|");
}
function break_cookie ($cookie_string) {
$array=explode("|",$cookie_string);
foreach ($array as $i=>$stuff) {
$stuff=explode("=",$stuff);
$array[$stuff[0]]=$stuff[1];
unset($array[$i]);
}
return $array;
}
?>
Hopefully someone finds these useful.
Robert Chapin
23-Jul-2007 06:32
23-Jul-2007 06:32
I would enjoy any new comments or documentation to address these compliance problems:
RFC 2109 defines the cookie VALUE as a quoted-string.
RFC 2965 obsoletes the Set-Cookie header.
Robert Chapin
Chapin Information Services
bluewaterbob
13-Jul-2007 06:51
13-Jul-2007 06:51
if you are having problems seeing cookies sometimes or deleting cookies sometimes, despite following the advice below, make sure you are setting the cookie with the domain argument. Set it with the dot before the domain as the examples show: ".example.com". I wasn't specifying the domain, and finally realized I was setting the cookie when the browser url had the http://www.example.com and later trying to delete it when the url didn't have the www. ie. http://example.com. This also caused the page to be unable to find the cookie when the www. wasn't in the domain. (When you add the domain argument to the setcookie code that creates the cookie, make sure you also add it to the code that deletes the cookie.)
john at codeproject dot com
17-Jun-2007 05:52
17-Jun-2007 05:52
If you ever have to modify, add, or delete cookies (that you added with php) using Javascript, try using this piece of code i found here:
http://www.webtoolkit.info/javascript-cookies.html
Its rather simple and very useful.
Jim
15-Jun-2007 08:15
15-Jun-2007 08:15
Setting the expiration time using strtotime is a very convenient way to calculate cookie expiration.
setcookie ("TestCookie", "", strtotime("+1 week"));
jonathan dot bergeron at rve dot ulaval dot ca
24-May-2007 07:05
24-May-2007 07:05
About the delete part, I found that Firefox only remove the cookie when you submit the same values for all parameters, except the date, which sould be in the past. Submiting blank values didn't work for me.
Example :
- set -
setcookie( "name", "value", "future_timestamp", "path", "domain" );
- delete -
setcookie( "name", "value", "past_timestamp", "path", "domain" );
Jonathan
jcastromail at yahoo dot es
22-May-2007 08:40
22-May-2007 08:40
You always can "emulate" a php setcookies invoking javascript.
<?php
echo "<script type='text/javascript'>/n";
echo "document.cookie='example=cookie'; /n";
echo "</script>/n";
?>
Using javascript to set a cookie allow you to change the cookie anytime (not only prior the body) running javascript directly in the client side.
The disadvantage is the clients must support javascript.
Wernight
20-Apr-2007 08:34
20-Apr-2007 08:34
The timeout is tricky as far as I read it depends on the time synchronization between the server and the client. If the GMT time is different (for example your computer is 5 min forward from the server time, don't know about the daylight saving problem) then the cookie timeout if affected by this.
Since I didn't very this information don't take it as factual but as a possible reason for problem (like the one below about IE).
The second conclusion is to use big values. For small values use something else (sessions, database...).
anonIMouS
10-Apr-2007 08:42
10-Apr-2007 08:42
This code sets cookie with Max-Age.
See to:
http://www.zend.com/zend/week/week198.php#Heading3
http://www.faqs.org/rfcs/rfc2109.html
<?php
function set_cookie($Name, $Value = '', $MaxAge = 0, $Path = '', $Domain = '', $Secure = false, $HTTPOnly = false) {
header('Set-Cookie: ' . rawurlencode($Name) . '=' . rawurlencode($Value)
. (empty($MaxAge) ? '' : '; Max-Age=' . $MaxAge)
. (empty($Path) ? '' : '; path=' . $Path)
. (empty($Domain) ? '' : '; domain=' . $Domain)
. (!$Secure ? '' : '; secure')
. (!$HTTPOnly ? '' : '; HttpOnly'), false);
}
# examples:
set_cookie("TestCookie", $value, 3600); /* expire in 1 hour */
set_cookie("TestCookie", $value, 3600, "/~rasmus/", ".example.com", 1);
?>
Marcin Wiazowski
30-Mar-2007 08:08
30-Mar-2007 08:08
'session.cookie_domain' should be set to empty string for all local domain names, not only for 'localhost' (but should not be empty for local IP addresses):
<?php
ini_set('session.cookie_domain', (strpos($_SERVER['HTTP_HOST'],'.') !== false) ? $_SERVER['HTTP_HOST'] : '');
?>
mike
26-Mar-2007 04:00
26-Mar-2007 04:00
Be careful of using the same cookie name in subdirectories. Setting a simple cookie
<?setcookie("region", $_GET['set_region']);?>
both in the root / and for instance in this case /admin/ will create 2 cookies with different paths. In reading the cookies back only the first one is read regardless of path.
21-Mar-2007 10:40
if you only want to do something once per unique visitor, you can test if a cookie is set, and if not, set the cookie and perform the action. This being the poorman's version, it has a problem, where if a user is blocking cookies they will appear as a first time visitor each time. What you can do to avoid this is to set a test cookie first and check that it exists. If it exists, then check to see if your second cookie has been set. If the first one is set, but the second isn't, then you know this is a first time visitor.
mbowie at NOSPAM dot buzmo dot com
11-Mar-2007 10:29
11-Mar-2007 10:29
It would seem that set_cookie will still set a cookie via HTTP, even if the secure parameter is true.
So even if your site uses HTTPS/SSL to communicate sensitive data, if the initial cookie was set by set_cookie via HTTP, an attacker listening on the wire could easily spoof a visitor's cookie and gain access to their session.
See: http://bugs.php.net/bug.php?id=40778
suit at rebell dot at
03-Mar-2007 03:58
03-Mar-2007 03:58
// to create a session cookie use zero (0) instead of time
setcookie("name", "value", 0);
// to destroy the session-cookie use
setcookie("name", "", -1);
gabe at fijiwebdesign dot com
25-Feb-2007 03:25
25-Feb-2007 03:25
If you want to delete all cookies on your domain, you may want to use the value of:
<?php $_SERVER['HTTP_COOKIE'] ?>
rather than:
<?php $_COOKIE ?>
to dertermine the cookie names.
If cookie names are in Array notation, eg: user[username]
Then PHP will automatically create a corresponding array in $_COOKIE. Instead use $_SERVER['HTTP_COOKIE'] as it mirrors the actual HTTP Request header.
<?php
// unset cookies
if (isset($_SERVER['HTTP_COOKIE'])) {
$cookies = explode(';', $_SERVER['HTTP_COOKIE']);
foreach($cookies as $cookie) {
$parts = explode('=', $cookie);
$name = trim($parts[0]);
setcookie($name, '', time()-1000);
setcookie($name, '', time()-1000, '/');
}
}
?>
jonasschaub at gmail dot com
14-Feb-2007 11:57
14-Feb-2007 11:57
great firefox extension to enable httpOnly
https://addons.mozilla.org/firefox/3629/
09-Feb-2007 01:13
something that wasn't made clear to me here and totally confused me for a while was that domain names must contain at least two dots (.), hence 'localhost' is invalid and the browser will refuse to set the cookie! instead for localhost you should use false.
to make your code work on both localhost and a proper domain, you can do this:
<?php
$domain = ($_SERVER['HTTP_HOST'] != 'localhost') ? $_SERVER['HTTP_HOST'] : false;
setcookie('cookiename', 'data', time()+60*60*24*365, '/', $domain, false);
?>
brian dot powell at insetsolutions dot com
06-Feb-2007 02:35
06-Feb-2007 02:35
Here is problem I ran into during a recent bout with IE7 and cookies. IE will not delete a cookie value if the time is set to the past. It will hold the value no matter how far in the past you set the "expire" value. IE7 is the only browser I have had problems with - so here is the solution I came up with.
<?PHP
//check to see how to set the cookie
$Browsertype = $_SERVER['HTTP_USER_AGENT'];
$Parts = explode(" ",$Browsertype);
$MSIE = array_search("MSIE",$Parts);
if($MSIE)
{
setcookie("name", "", time()+20000);
}
else
{
setcookie("name", "", time()-20000, "/", ".domain.com" );
}
?>
ahmetantmen at msn dot com
19-Jan-2007 11:36
19-Jan-2007 11:36
You can be sure about the cookie files contents weren't changed.
<?php
$Seperator = '--';
$uniqueID = 'Ju?hG&F0yh9?=/6*GVfd-d8u6f86hp';
$Data = 'Ahmet '.md5('123456789');
setcookie('VerifyUser', $Data.$Seperator.md5($Data.$uniqueID));
if ($_COOKIE) {
$Cut = explode($Seperator, $_COOKIE['VerifyUser']);
if (md5($Cut[0].$uniqueID) === $Cut[1]) {
$_COOKIE['VerifyUser'] = $Cut[0];
} else {
die('Cookie data is invalid!!!');
}
}
echo $_COOKIE['VerifyUser'];
?>
Create a unique id for your site and create a hash with md5($Data.$uniqueID). Attacker can understant that it must be re-hash after change cookie content.
But doesn't. Because cannot guess your unique id. Seperate your hash and data with seperator and send that cookie. Control that hash of returned value and your unique id's is same returned hash. Otherwise you have to stop attack. Sorry for my poor english!
stovenator at gmail dot com
13-Jan-2007 02:54
13-Jan-2007 02:54
If you are having issues with IE7 and setcookie(), be sure to verify that the cookie is set via http for http sites, and https for https site.
Also, if the time is incorrect on your server, IE7 will also disallow those cookies from being set.
05-Jan-2007 09:33
If you ever find yourself in a situation where you need to overwrite a non-PHP application's session cookie, you can do that with the following line:
header("Set-Cookie: SIDNAME=$overwrite; path=/; secure");
I couldn't get setcookie() to do this for all major web browsers, but manually sending the header did the trick. Note: Remove secure if you aren't mandating SSL connections.
felixcca at yahoo dot ca
31-Dec-2006 05:36
31-Dec-2006 05:36
I found out recently that assigning FALSE to a cookie will destroy it.
I thought it might interest some of you.
core58 at mail dot ru
14-Dec-2006 04:35
14-Dec-2006 04:35
Regarding to "rajneshavon@gmail dot com" note:
There only one type of cookies, simply -- cookie is the data storage itself, without any types/categories.
Cookies have some parameters (expiration date, domain, path) which should be considered.
Sessions mechanism works kinda simply:
when You call "session_start();" -- server attaches header
Set_cookie: session_name()=session_id(); path=/
usually. This cookie can be used in the next browser request to distinct one user from another (suggesting that session_id() has unique value for every user -- is't usually 32 md-hash).
To be completely simple -- server just tries to open file at session storage with the name like sess_<session_id()>. If that file exists -- server reads the data and performs unserialize() and that gives You opportunity to get the stored data as $_SESSION array -- this array is being simply serialized/unserialized when operating with it in scripts.
If browser disables cookies -- You can set
session.use_trans_sid = 1
That will tell Your PHP parser to append ?session_name()=session_id() to every link being outputted at the page and also add hidden field with that name=value at forms if any.
Upon clicking such link with session in the query string, You will receive session_id but from $_GET array. That will tell server where to get session data, just without cookies.
The only minus is that Your links will become "variable" with that boring session hash.
kurtubba at gmail dot com
14-Dec-2006 01:12
14-Dec-2006 01:12
When setting a top level domain ex ".mydomain.com" you must add the secure arg so it should look like
setcookie("TestCookie", $value, time()+3600, "/", ".example.com", 0);
ignoring the secure arg makes IE ignores the cookie
to get the top level domain use
$myDomain = ereg_replace('^[^\.]*\.([^\.]*)\.(.*)$', '\1.\2',$_SERVER['HTTP_HOST']);
to avoid localhost switch use
$phpCkDmn = $_SERVER['HTTP_HOST'] != "localhost" ? $myDomain : false;
paul nospam AT nospam sitepoint dot com
07-Dec-2006 04:59
07-Dec-2006 04:59
Note when setting "array cookies" that a separate cookie is set for each element of the array.
On high traffic sites, this can substantially increase the size of subsequent HTTP requests from clients (including requests for static content on the same domain).
More importantly though, the cookie specification says that browsers need only accept 20 cookies per domain. This limit is increased to 50 by Firefox, and to 30 by Opera, but IE6 and IE7 enforce the limit of 20 cookie per domain. Any cookies beyond this limit will either knock out an older cookie or be ignored/rejected by the browser.
hansel at gretel dot com
06-Nov-2006 04:12
06-Nov-2006 04:12
The following code snippet combines abdullah's and Charles Martin's examples into a powerful combination function (and fixes at least one bug in the process):
<?php
function set_cookie_fix_domain($Name, $Value = '', $Expires = 0, $Path = '', $Domain = '', $Secure = false, $HTTPOnly = false)
{
if (!empty($Domain))
{
// Fix the domain to accept domains with and without 'www.'.
if (strtolower(substr($Domain, 0, 4)) == 'www.') $Domain = substr($Domain, 4);
$Domain = '.' . $Domain;
// Remove port information.
$Port = strpos($Domain, ':');
if ($Port !== false) $Domain = substr($Domain, 0, $Port);
}
header('Set-Cookie: ' . rawurlencode($Name) . '=' . rawurlencode($Value)
. (empty($Expires) ? '' : '; expires=' . gmdate('D, d-M-Y H:i:s', $Expires) . ' GMT')
. (empty($Path) ? '' : '; path=' . $Path)
. (empty($Domain) ? '' : '; domain=' . $Domain)
. (!$Secure ? '' : '; secure')
. (!$HTTPOnly ? '' : '; HttpOnly'), false);
}
?>
Basically, if the domain parameter is supplied, it is converted to support a broader range of domains. This behavior may or may not be desireable (e.g. could be a security problem depending on the server) but it makes cookie handling oh-so-much-nicer (IMO).
shitdeposit at hotmail dot com
21-Oct-2006 11:34
21-Oct-2006 11:34
An undocumented "feature" of setcookie:
Example:
setcookie( 'delete_me', '', time() - 1000, '/', '', '' );
The setcookie function will silently change the '' cookie value to 'deleted' and override your expiry time to time() - 1 year.
I only noticed this when the computer I was testing on had it's date set incorrectly to the > 1 year in the past. The computer connects to the server which has it's date correctly set and thus the cookie on the client doesn't delete but stores the value "deleted" instead.
adruff at gmail dot com
06-Aug-2006 05:14
06-Aug-2006 05:14
If you intend to use persistent cookies (vice session cookies that are deleted when the browser is closed) be aware:
1) Firefox appears to require that you include all paramaters, or it will ignore the expiration and treat the cookie as a session cookie
2) My version of firefox (1.5.0.6) defaults to 'keep cookies until i close firefox' , which essentially makes every cookie a session cookie. This of course sucks for devs, but i suppose is supposed to be a security feature for the end user. If the user wants to configure firefox to respect the expiration date and retain cookies beyond the session, the user must change it to 'keep cookies until they expire'.
mrvanes at gmail dot com
06-Jun-2006 02:22
06-Jun-2006 02:22
I just discovered that IE6 (6.0.2800.1106 at least) seems to have difficulties accepting cookies when the subdomain part of the URL is longer than 10 characters. This applies to automatic sessionid's as well (that's how I found out). So: Setting a cookie on a site named http://examples.test.com/ will work, doing the same on http://my_examples.test.com will fail (or at least, failed for me).
Tested it by snooping the outgoing traffic from the client: the GET request lacks the COOKIE: header in the last case. A closer inspection revealed that the cookie was never accepted in the first place: when the subdomain is longer than 10 characters, no cookiefile is created in the temporary internet files directory. Temporary cookies (like the PHP sessionid) have the same problem.
Firefox and Konqueror have no problem with this.
[Editor's note: Your comment is wrong. It is not the length of the hostname but the use of the underscore (_) char within it which makes IE (silently) freak out. The use of underscores in hostnames is an RFC violation and may very well not be supported at all by a browser, proxy or any http client.]
gareth at gw126 dot com
05-Jun-2006 02:38
05-Jun-2006 02:38
You can use cookies to prevent a browser refresh repeating some action from a form post... (providing the client is cookie enabled!)
//Flag up repeat actions (like credit card transaction, etc)
if(count($_POST)>0) {
$lastpost= isset($_COOKIE['lastpost']) ? $_COOKIE['lastpost'] : '';
if($lastpost!=md5(serialize($_POST))) {
setcookie('lastpost', md5(serialize($_POST)));
$_POST['_REPEATED']=0;
} else {
$_POST['_REPEATED']=1;
}
}
//At this point, if $_POST['_REPEATED']==1, then the user
//has hit the refresh button; so don't do any actions that you don't
//want to repeat!
Hope that helps :)
Gareth
matt at mattsoft dot net
05-May-2006 12:47
05-May-2006 12:47
using time()-1 to delete (expire) a cookie only works if the client's clock is set exact. my testing showed some weird results with my clock set 1 second or so behind the server. 1 day or even just a few seconds ahead of the server's time and the cookie doesn't expire when it's suposed to.
my test:
setcookie('k',$k+1,time()-1);
echo $k;
setting the expire time to 0 makes it a browser session cookie, lasting forever, until the browser is closed. but setting the expire time to 1 is the lowest timestamp possible and is most likely to expire the cookie without any problems.
my fix:
setcookie('k',$k+1,1);
echo $k;
this is my theory. I'm not sure why no one else has thought of this problem or solution, and I'm still testing, but please email me your questions or comments.
Brian
10-Mar-2006 07:56
10-Mar-2006 07:56
Firefox is following the real spec and does not decode '+' to space...in fact it further encodes them to '%2B' to store the cookie. If you read a cookie using javascript and unescape it, all your spaces will be turned to '+'.
To fix this problem, use setrawcookie and rawurlencode:
setrawcookie('cookie_name', rawurlencode($value), time()+60*60*24*365);
The only change is that spaces will be encoded to '%20' instead of '+' and will now decode properly.
php at macros dot org
03-Mar-2006 01:19
03-Mar-2006 01:19
I've just been fighting with an issue with setting cookie paths that contain the underscore [_] and dash [-] characters on IIS6.
This issue is a known "feature" that was added to IIS6 to help prevent cross-site scripting vunerabilities (See: http://tinyurl.com/n5hq9).
Basically, when IIS6 is asked to go to a URI that doesn't contain a trailing slash, it will "courtesy redirect" to the URI with a trailing slash, but in doing so will encode underscores and dashes into their ASCII codes (%5F and %2D respectively).
Now, while this normally wouldn't be an issue, when a cookie is set by PHP using a defined path the unencoded version is used for the path. PHP does not know that the path is encoded, as IIS6 decodes it before it's given to the script (I assume).
Example:
URI = http://somedomain.com/some_directory
IIS redirects = http://somedomain.com/some%5Fdirectory/
PHP sees: http://somedomain.com/some_directory/
PHP_SELF: /some_directory/script.php
So, setting the path: path="/some_directory/"
but browser sees: path="/some%5Fdirectory/" which are not equal, so therefore the paths aren't the same and the cookie isn't retrieved.
Normally this wouldn't be an issue: simply don't specify a path & the browser handles it for you; or don't use underscores or dashes in the URI; or specify the URI with the trailing slash. But when used to lock down sessions to a specific directory (which might have those characters) this becomes a big problem (default session path is /).
The solution is to also set a cookie using the session information (name, value & other parameters) for the encoded version of the path, then the same session will be used for either version of the path.
Cameron.
simon at ruderich dot com
01-Aug-2005 09:21
01-Aug-2005 09:21
If you want to delete a session cookie, you can do it with this code:
<?php
session_start();
// many code
$sessionName = session_name();
$sessionCookie = session_get_cookie_params();
session_destroy();
setcookie($sessionName, false, $sessionCookie['lifetime'], $sessionCookie['path'], $sessionCookie['domain'], $sessionCookie['secure']);
?>
This works also well if the session cookie params or the session name were changed.
lharkleroad at gmail dot com
18-Jul-2005 10:12
18-Jul-2005 10:12
In response to Snupha's note, one way to get the desired result on the server side, and therefore work around the user's local date and time, is to store your session information in a sessions table in your database.
For example:
1. Create a sessions table in your favorite db with a 32 char sessionid column, modifed and created datetime columns, and any other columns that you want to associate with the session such as a userid.
2. In your PHP script, create a variable containing the 32 char unique ID for your session, and store the result in a sessionid cookie that expires at the end of the browser session, and also insert it in a new row in your sessions table.
3. When your scripts check for the existance of the sessionid cookie, if a value is returned, they would check against the sessions table in your database to find the matching ID, updating the modified datetime for that record to keep the session active. If the server time elapsed since the record was modified exceeds your timeout constraints, you can force the user to reauthenticate and issue them a new session ID if desired.
4. If you require a login to some part of your site, you can also update the session record with the userid to link the session to the user.
I decided to use this method on a recent project where both PHP and ColdFusion needed to access the same datasource for different applications. The result is a language-independent session in which multiple web servers on the same domain (but potentially different sub-domains) can know when the user has logged in and allow them to continue the session on the other server. Otherwise, using the sessions built in to PHP and ColdFusion would require separate logins when switching between applications programmed in the two languages.
Going a little further with this, you can then report stats on the sessions table for the average session length by comparing the created and modified columns, or get a session history for a particular user.
I hope this helps a few people. Have fun!
Snupha
07-Jun-2005 08:24
07-Jun-2005 08:24
If you cannot get a cookie to stick when using an expiration date - check that local computer's time and time zone!
I spent hours trouble-shooting my code when I realized that the computer time on a client's computer was 7 years into the future which automatically expired the cookie before it could be used! Go figure, I'm going to look now for a work around that I can do on the server-side.
terry at scribendi dot com
08-May-2005 02:07
08-May-2005 02:07
A few comments have suggested using serialize() to set object or array data into a cookie. There are a couple of reasons to be carefull with that technique:
Security: If the cookie is human readable, then it is also fairly easy for end users to play around with it. Wrapping your cookie setting and getting in an encryption routine will prevent tampering, and make sure that your cookies don't make any sense to any client-side exploits or other sites they get sent to thanks to browser bugs.
Bulk: If you serialize even a fairly simple class, then you get a lot of data. Large cookies will make browser requests fat and slow, and some browsers have a limit on cookie size, so think about what data you really need to persist, and create __sleep() and __wakeup() methods to package the data into the shortest possible form. You can get better and faster results when you write your own __sleep() and __wakup() to implode() or pack() your data, than by using zlib compress() on the serialized object.
scissorjammer at hotmail dot com
08-Apr-2005 07:18
08-Apr-2005 07:18
As per Sijmen Ruwhof's comment:
It's not that the domain requires a dot as much as it requires a fully qualified domain name. Setting it to false is a valid workaround, as it will default to whatever domain the page is being accessed at. If a fully qualified domain name is unavailable, consider editing your hosts file on both the client and server to have a common domain name to use for the cookie.
Carl V
08-Apr-2005 03:29
08-Apr-2005 03:29
If you want to delete all the cookies set by your domain, you may run the following:
<?php
$cookiesSet = array_keys($_COOKIE);
for ($x=0;$x<count($cookiesSet);$x++) setcookie($cookiesSet[$x],"",time()-1);
?>
Very useful when doing logout scripts and the cookie name may have changed (long story).
jonathan at jonathanopie dot com
23-Mar-2005 10:00
23-Mar-2005 10:00
I've found that when using header("Location: <destination page>") type 302 redirect, that cookie information in the header will be silently dropped if the <destination page> path includes any non-alphanumeric (except the allowed "-" and ".") characters. That had been pointed out above, and is documented with Microsoft as by design...
http://support.microsoft.com/default.aspx?scid=kb;EN-US;316112
...but what is not made clear, is that the rule seems to include file and directory names too!
Also, I've had unpredictable results when the <destination page> filename begins with ANY character other than strictly alphanumeric characters, even the otherwise allowed "-" and "." characters; and/or if the <destination page> is in a different directory.
Alchaemist
14-Mar-2005 11:36
14-Mar-2005 11:36
setcookie + header Location + IIS 5 = Trouble
It took me a long time to figure out what was causing a missing cookie in one system while it worked perfectly in another...
See this one: http://support.microsoft.com/kb/q176113/
In short, this WILL NEVER WORK IN IIS 5:
<?php
header("Pragma: no-cache");
header('Location: http://www.example.com/');
setcookie('AA','1',0,'/');
setcookie('BB','2',time() + 24 * 3600,'/');
?>
You will ONLY get the Location Header, everything else will be "cut out" by IIS 5 CGI implementation.
Solutions:
1- Migrate to Apache/IIS6/Whatever
2- Use a Non Parsed Header Script (nph-*.php)
3- Try with header('Refresh: 0; $URL');
I hope this helps somebody not to spend hours knocking his/her head.
Alchaemist
do not spam M. Kristall at MKP
25-Jan-2005 06:18
25-Jan-2005 06:18
The "bug" that prevents cookies from working properly with Windows XP and Internet Explorer 6 seems to be a more strict following of the cookie specifications. This part in particular:
Only hosts within the specified domain can set a cookie for a domain and domains must have at least two (2) or three (3) periods in them to prevent domains of the form: ".com", ".edu", and "va.us". Any domain that fails [sic] within one of the seven special top level domains listed below only require two periods. Any other domain requires at least three. The seven special top level domains are: "COM", "EDU", "NET", "ORG", "GOV", "MIL", and "INT".
localhost should not work. Neither should localhost.localdomain. Though, it may be a bug that 127.0.0.1 does not work, even despit the fact that 127.0.0.1 is not a domain name.
Sijmen Ruwhof
02-Jan-2005 08:41
02-Jan-2005 08:41
My experience with setting cookies, a must read for every developer that doenst want to spend his time debugging cookies..
- if your're using windows XP with Internet Explorer, having a local webserver running and you're setting a cookie in you script, don't set the domain name! Use false instead. Windows XP in combination with Internet Explorer (with Firefox your cookie will be set successful) will not set a cookie when the domain name points to localhost. Examples:
<?
setcookie('test', 'value', false, '/', 'localhost', 0); // wil not work in WinXP with IE, but will work in WinXP with Firefox
?>
Someone noted already this bug in WinXP + IE, but said that the domainname should have a dot in it. That is totally untrue (i've tried a domainname with a dot in it that points to 127.0.0.1). I think that the problem persist that the domainname may not be pointing to 127.0.0.1 so the solution would be:
<?php
setcookie('test', 'value', false, '/', false, 0); // works
?>
- be sure that the 4th argument (path) always ends with a slash '/'
- be sure that the expire time is false or a timestamp, 0 is not the value for a session cookie (false is the value).
-- Sijmen Ruwhof
christophe at publicityweb dot com
