HTML Cookies From PHP

by Patrick Horgan

(Back to Web tutorials)

Introduction

If you're looking for a basic introduction that explains what Cookies are, this is not it, try HTML Cookie Introduction. If you're looking for a tutorial on how to deal with Cookies with javascript, see my tutorial HTML Cookies From Javascript. This short tutorial tells you what's possible from PHP, and how to accomplish that. It will not explain Cookies, the Set-Cookie header, or tell you what the attributes of a Cookie mean. See HTML Cookie Introduction for that.

How do you look at the Cookies sent from the browser?

Lets look at the Cookie header

You can get a raw look at the Cookies, by looking at the Cookie header that was sent.

$thecookies=$_SERVER["HTTP_COOKIE"];

They'll look just like they did in the Cookie header, so you'll see something like

cookie1=value1; user=joe; rock=roll

The cookies that come to you from the browser are ones that you set before. The browser sends them along with a request for the page your PHP code runs in only if the Domain, Path, and Secure attributes match the URL of your page.

Conveniently PHP Puts Cookies In An Associative Array

Instead of dealing with the raw Cookies, we can deal with an array provided for us by PHP. It's called the $_COOKIE array.

cookie1=$_COOKIE['cookie1']; // value1 cookie2=$_COOKIE['user']; // joe cookie3=$_COOKIE['rock']; // roll

If you weren't sure if the Cookie was already set, then you'd check first,

if(array_key_exists('user',$_COOKIE)){ theuser=$_COOKIE['user']; // joe }else{ // haven't seen this user before (or the Cookie was not saved or deleted). }

How does a server set a Cookie

A server sets a Cookie by sending a Set-Cookie header to the browser. When you are writing code in PHP that sends Cookies, that's your job. Get a Set-Cookie header sent.

You have to do it before anything else is sent, because as soon as any part of a page is sent, the headers go just before them. After that, it's too late. The headers already went.

I'm going to show you two ways to send Cookies from PHP. First you can set any headers you want, including a Set-Cookie header. You can just build the header and send it off. Second, PHP has a set of functions just for dealing with Cookies. I'll show you those second, so you'll understand better what they are doing, but the thing to remember, is that the only way to set a Cookie is by sending a Set-Cookie header.

Setting the header directly

PHP has a header() method to set a header. Sending a Cookie from PHP can be as simple as

header("Set-Cookie: user=joe");

to set a Cookie named user with the value joe

As detailed in HTML Cookie Introduction (and specified in RFC 6265 - HTTP State Management Mechanism, [If you don't know what an RFC is, see RFCs and a Script to get them]), the date used with a Set-Cookie header is in Greenwich Mean Time (now called UTC). That means that if you send a Set-Cookie header with an Expires attribute, it needs to be in GMT. To set a cookie to expire in a day, you could do this:

// 24 hr * 60 min/hr * 60 sec/min = 86400 sec $thedate=gmdate('D, d M Y H:i:s \G\M\T',$time()+24*60*60);

time() returns the time in seconds since the Unix Epoch (January 1 1970 00:00:00 GMT). We add to that the number of seconds in a day, to get the time for a day from now. We pass that to gmdate along with a format string that gives exactly the format specified in RFC 6265. You can replace the format string with the predefined constant DATE_COOKIE, but oddly, although it produces a date string that can be parsed according to the rules in RFC 6265, it is not exactly the one that the specification says you should use, substituting dashes for spaces between the day, month and year. Both work, but I like to specify the format string as above, so it agrees with the RFC.

gmdate(DATE_COOKIE,time()); // Sat, 20-Aug-2011 18:28:52 GMT

versus

gmdate('D, d M Y H:i:s \G\M\T',time()); // Sat, 20 Aug 2011 18:28:52 GMT

In reality both work.

That means that from PHP you can do something like

header("Set-Cookie: user=joe; Expires=".gmdate('D, d M Y H:i:s \G\M\T',time()+24*60*60));
which will send a header like
Set-Cookie: user=joe; Expires=Sat 21 Aug 2011 18:28:52 GMT

Using the PHP Cookie methods

There are two PHP methods used to set Cookies,

bool setcookie ( string $name [, string $value [, int $expire = 0 [, string $path [, string $domain [, bool $secure = false [, bool $httponly = false ]]]]]] )
bool setrawcookie ( string $name [, string $value [, int $expire = 0 [, string $path [, string $domain [, bool $secure = false [, bool $httponly = false ]]]]]] )

and

The only difference between these is that setcookie url encodes the cookie and setrawcookie does not. The $expire argument is in seconds since the Unix Epoch.

url encoding

urlencode means that spaces are replaced with + and anything else that's not

will be replaced by %XX where XX is the hexadecimal representation of the US-ASCII code.

N.B. That says US-ASCII. That is because the Cookie RFC, RFC 6265, states that all of the parts of a Cookie, including the value, have all characters in a subset of US-ASCII.

If you want to use characters outside of the US-ASCII range in the Cookie value they must be encoded somehow into the US-ASCII range.

Base64 encoding is a popular choice. Even if you think that you aren't using anything outside of the US-ASCII range, you might be. If you accept a user name from someone, they might have characters in their name that are outside of the US-ASCII range.

Base64 (RFC 4648) is a commonly used encoding that allows binary data to be converted to a subset of US-ASCII text, and PHP supports it with the routines base64_encode(string) and base64_decode(string).

There's optional arguments but you have to specify all up to the rightmost

Notice that all of the arguments except for $name are optional, but that if you want to provide an argument, you have to provide all of the arguments which proceed it.

That means that if you want to set only the name of the cookie and the HttpOnly attribute, a completely valid combination, you need to know what to send to the setcookie method for all of the other arguments.

The default values to set unused attributes to so that they won't have any effect are

Notice I didn't specify the $name default value, since it always needs a valid value, or $httponly, because you'd just leave it off if you weren't using it.

Here's some examples

setcookie("acookie")

Makes a cookie named acookie with no value

setcookie("acookie",NULL,NULL,"/",NULL,false,true)

A cookie named acookie with no value but HttpOnly set to true

setcookie("acookie",3,time()+7*24*60*60);

A cookie named acookie with value 3 that expires a week into the future

How does a server expire a Cookie?

To expire a Cookie, you set the Cookie with the time in the past so that it has already expired. The Cookie should have the same name as it was set with, and in addition should have the same domain, path, and secure attributes as were used to set it. To deal with time drift between machines, it's safest to use a time a week into the past, but if the times are synchronized, a time one second in the past will delete a Cookie. As an example:

header("Set-Cookie: user=joe; Expires=".gmdate('D, d M Y H:i:s \G\M\T',time()-7*24*60*60));

When using the setcookie() method you would just use a negative number for the $expires, and it's traditional, but not required to use "expired" for the $value.

setcookie("joe","expired",time()-7*24*60*60);
Set a Cookie

The cookies for this page as seen on the server

Remember, this sets cookies on your machine. The domain will always be the same as the page so that you can set them, and see them. They will always be set to expire when the session is over unless you click the Date in past to delete? button to delete them. The Path is always '/'. Secure is never set.

(Back to Web tutorials)