A quick cookie primer

What is a cookie?
A cookie is a piece of data stored by a web browser on a user's hard disk. Cookie storage is rigidly controlled for security purposes, and the amount of data that can be stored (which varies between browsers) is small - typically 4K bytes per cookie, and 20 cookies per web domain (e.g. paulspages.co.uk). 

Despite their limitations cookies are very useful, because they allow you to store data on a per-user basis.  For example, instead of keeping a database of user names and preferences on your server, you can store each user's details on their own disk. 

Disappearing cookies
Cookies are useful, but they're also unreliable. Some users set their browsers not to accept cookies, and cookies can 'disappear' from a disk for a variety of reasons, including space limitations or the user switching to a different browser. Cookies should never be used to store irreplaceable data, and cookie-handling code should always be defensive, i.e. able to handle situations where an expected cookie isn't found.

JavaScript and cookies
Using JavaScript, you can create and use cookies direct from web pages. This is called 'client-side' cookie handling because the code runs in the browser, or 'client', as opposed to server-side cookie handling, where code (e.g. cgi or ASP) running on the web server sends cookie-handling instructions to the browser. The code in the paulspages functions runs on Microsoft and Netscape browsers from version 3.0 onwards, as well as other compatible browsers such as Opera.

Why do I need these libraries?
JavaScript's built-in cookie-handling features are very basic. As you'll see from the examples below, they leave it to you to extract individual cookies from the document.cookie string, rely on you to convert data between escaped (special character-encoded) and unescaped format, make setting expiry dates difficult, and offer no support for space-saving multi-field cookies. Don't worry though, because the paulspages.co.uk cookie-handling functions do all that for you!

What does a cookie look like?
A cookie is basically a text string consisting of a name and a value, like this.

website=www.paulspages.co.uk

When a web page loads, the browser assembles all the cookies that are available to that page (see below) into a single string, called document.cookie. The cookies are separated by semicolons (;). Here's an example:

website=www.paulspages.co.uk; name=Paul Stephens; location=Bath, UK

The document.cookie string may include cookies written by other pages in your website. You don't get any choice about which cookies appear in document.cookie - the browser just sends you everything. 

Extracting individual cookies
In basic JavaScript it's up to you to extract individual cookies from document.cookie, and to handle any problems caused by values containing = or ; characters (e.g. "location=Bath; UK"). In practice the latter means using the escape() function to convert any special characters to "escape sequences" before writing a cookie, so the actual data stored is something like this:

location=Bath%2C%20UK

where %2C is the 'escaped' code for a comma, and %20 the code for a space. When you read the cookie back, you use the unescape() function to convert the escape sequences back to characters.  

Access paths
Web pages can "see" cookies created by other pages, but only within strict rules enforced by the browser. The main rule is that a page will only see cookies written by pages from the same server domain (e.g. paulspages.co.uk). 

Furthermore, a page will only see cookies written by pages from the same or higher-level folders within its domain.  For example, if your server has this folder structure:

               / (root folder)
               index.htm
                    |
          |---------------------|
        /news               /reviews
        newspage1.htm       reviewpage1.htm
        newspage2.htm
        |
   |----
/news/newsflash
newsflash1.htm
By default, the page newspage1.htm will see cookies written by itself, index.htm and newspage2.htm, but not those written by reviewpage1.htm or newsflash1.htm. Reviewpage1, meanwhile, will see only cookies written by itself and index.htm. 

You can override this by setting an access path when writing a cookie (see "Writing cookies", below, for details of how to do this).

In this example, giving a cookie from newsflash1.htm an access path of "/news" would enable newspage1.htm and newspage2.htm to see it.  Setting an access path of "/" (root folder) makes a cookie available to all pages in your domain.

Name clashes avoided
The access  rules prevent pages from snooping on cookies written by other websites, and also avoid cookie name clashes. This means that you can create a cookie named "location" without worrying whether a page from another website has created one with the same name, because only your site's 'location' cookie will be supplied to your pages. The folder rules do the same thing within your website - unless, of course, you give all your cookies an access path of "/".

Note that there's no way of telling which folder or page an existing cookie has come from, or what its access path is, unless the page that created it included these details as part of its data value.

Sub-domains 
Some websites use sub-domains, for example news.mydomain.com and reviews.mydomain.com. By default these count as separate domains, so a cookie from one sub-domain can't be seen by pages from another. However you can override this by specifying a domain for the cookie. (see "Writing cookies", below, for details of how to do this).

For example, setting a domain of mydomain.com would cause pages from news.mydomain.com and reviews.mydomain.com to see the cookie.

You can set a path and a domain for a cookie.

Cookie expiry
Cookies are designed to have temporary lifespans. By default, this is just the current browser session; when the user unloads the browser, the cookie is deleted from their disk. 

Alternatively you can set an expiry date when you create a cookie (see "Writing cookies" for details). The browser will then attempt to keep the cookie on disk until that date. However the cookie may be deleted before then for a number of possible reasons (for example because the cookie storage limit has been reached), so remember - always program defensively to handle "missing" cookies!

To delete an existing cookie, you write it with an expiry date earlier than the present date.

Note that there's no way of telling an existing cookie's expiry date, unless the page that created it  included this information as part of its data value.

Writing cookies
In most respects JavaScript is a very consistent language, but not when it comes to cookie handling. 

When you read the document.cookie string (e.g. myCookies = document.cookie), it consists of name=value pairs for all the cookies available to the page, as described above. However, when you write to it (e.g. document.cookie = myCookieData) it behaves completely differently.

(NOTE - the details below are included for information only - the cookie-handling libraries take care of writing cookies for you).

When you write to document.cookie, the browser expects just a single cookie's name=value pair. This will be used to either create a new cookie, or update an existing one if the name already exists. Never include the name=value pairs for the other cookies that were in the original document.cookie string - doing this is likely to create spurious cookies with the "wrong" expiry dates and access paths.

Here's the code to add a cookie:

document.cookie = "location=" + escape("Bath, UK")

As well as the name=value pair, you can add extra pairs to control the path and expiry date (see above). 

You add a path like this:

document.cookie  = "location=" + escape("Bath, UK") + "; path=/news"

In this example, the actual value written to document.cookie would be 

location=Bath%2C%20UK; path=/news

Expiry dates need to be expressed as string values, like this:

document.cookie  = "location=" + escape("Bath, UK") + "; path=/" +
        "; expires=" + myDateObj.toGMTString()

where myDateObj is a JavaScript Date() object, set to the date on which you want the cookie to expire.

You add a domain like this:

document.cookie  = "location=" + escape("Bath, UK") + "; path=/"
          + "; expires=" + myDateObj.toGMTString() + "; domain=mydomain.com"

What do the paulspages.co.uk cookie functions do?
The cookie functions take the hard work out of handling cookies from JavaScript. They:

Multi-field cookies
Strictly speaking there's no such thing as a multi-field (or multi-value) cookie; each cookie contains one data value, so if you want to store a user's website, name and location, you need three cookies, as shown above. 

You can, however, make your own multi-field cookie by concatenating (assembling) its fields into a single string, which becomes the cookie's data value. For example, instead of having three separate cookies ("website", "name" and "location"), you could have one named "userdetails", with three fields. Here's an example:

userdetails=www.paulspages.co.uk#Paul%20Stephens#Bath%2C%20UK

Note the # characters, used as field delimiters (separators). When you read the cookie into a page, you split the data into separate variables or array elements by finding the # characters. 

Multi-field cookies save space (by not having a separate name for each data value), use up fewer of the 20 cookies per domain allowed by some browsers, and make programming easier, since you only have to read and write one cookie.

The object-based www.paulspages.co.uk cookie functions support multi-field cookies automatically. Each cookie object you create contains an array, named fields[]. You can add as many elements as you like to this array, and when you write the cookie to disk, the cookie object concatenates them into a single string, inserting the fields delimeters automatically. When you read the cookie into a page, the object splits the string back into elements of its fields[] array.