|
Contents
Introduction:
The Wine Shop Site
Writing a cookie
Reading a cookie
Getting the document.cookie
Splitting out cookie value from document.cookie
Updating document.cookie
Deleting cookies
Conclusion
Back
to page 1 of The Wine Shop article
|
 |
|
The
Wine Shop Site
The
Wine Shop is a basic, five page web site which was developed
to demonstrate how cookies can be used and how they can be
created and manipulated by JavaScriptr code.
The
site allows notional bottles of wine to be selected from two
store departments, placed in an electronic shopping basket
and notional orders placed for the notional wine.
The
order processing, for reasons of practicality, updates the
client side data but doesn't send the order back to the initiating
web server. Sorry, you'll have to continue going down the
off licence.
The
code fragments in the text below are intended to be illustrative
- See the code in the web pages themselves for complete, working
scripts.
|
 |
|
Writing
a cookie
A
cookie has the following format
cookieName=CookieValue;
expires=expirationDate.toGMTString();path=sitePath;domain=siteDomain
Only
the cookie name and cookie value pair is mandatory - The rest
is optional. Here we will use the name/value pair and the
expires/expiry date pair. The path and the domain pairs are
documented elsewhere.
An
example is seen in the checkout page (checkout.htm),
where the user is required to enter values for name and address:
 |
<form
name="frmContact"
method="post"
action="">
<p>
<font face="Verdana, Arial, Helvetica,
sans-serif"
size="2"
color="#000000">
First name
</font><br>
<input type="text" name="txtFirstName"
cols="30">
<Br>
<font color="#000000"
face="Verdana, Arial, Helvetica, sans-serif"
size="2">
Family name
</font><Br>
<input type="text" name="txtSurname"
cols="30">
<Br>
<font color="#000000"
face="Verdana, Arial, Helvetica, sans-serif"
size="2">
Address
</font><Br>
<textarea name="txtAddress"
rows="4"
cols="30">
</textarea>
</p>
</form>
|
When
the Place Order link is clicked, a JavaScript function is
invoked
<a
href="javascript:placeOrder();">Place order</a>
The
function placeOrder()
checks that the user has completed all the fields, then writes
out their values to cookies:
function
placeOrder() {
\\ There is some other code here
in the web page . . .
expireDate = new Date;
expireDate.setMonth(expireDate.getMonth()+6);
document.cookie = "firstName="
+
escape(document.frmContact.txtFirstName.value)
+
";expires="
+
expireDate.toGMTString();
document.cookie = "surName="
+
escape(document.frmContact.txtSurname.value)
+
";expires="
+
expireDate.toGMTString();
document.cookie = "Address="
+
escape(document.frmContact.txtAddress.value)
+
";expires="
+
expireDate.toGMTString();
Notice
here that, so long as the cookie's name is specified, followed
by = then its value, the browser handles its addition
to the cookies on file: document.cookie is always assigned
the value. The expiry date is set at six months from now.
Technically
the expiry date is optional but experience shows that, when
the expiry date is omitted, odd things can happen - Cookies
are deleted by the browser just when you start to need them
- This may be the way the browser determines the validity
of a memory-resident cookie: If no expiry is set then the
cookie should be kept in memory for the duration of the current
session, not written to a file and discarded when the session
ends.
When
the expiry date is reached, the cookie is said to be stale
and the browser will delete it without reference to the user.
Notice
also that the cookie name/cookie value pair is separated from
the rest of the cookie by <space> ;
The
delimiter for the rest of the cookie is just ;
This
allows for some flexibility in accessing the components of
a cookie when it is read back - See Reading
cookies, below.
Note
also that the process of writing a cookie is usually referred
to as setting a cookie. A cookie can be set by script
in a HTML page but it can't be set by the web server itself.
|
 |
|
Reading
cookies
Retrieving
cookies is a matter of extracting the appropriate name/value
pairs from document.cookie. Before we look at the examples
in The Wine Shop here are some basics to put those examples
into context. Notice, again, that all through these examples,
the browser determines which cookies we can access
- There is nothing the scripts (or the server) can do to determine
which stored cookies are made available. This makes cookies
very secure, both for the user and for the web site wanting
to store data on the client's machine.
At
its most straightforward you can insert the following line
into a script
alert(document.cookie);
which
will display the entire cookie string (as
shown below). To display all the currently-accessible
cookies on a web page, try the following code in a HTML page
and see its sample output.
<body
bgcolor="#FFFFFF" text="#000000">
Cookie contents<BR>
<SCRIPT LANGUAGE="JavaScript">
if (document.cookie == "")
{
document.write("<BR>There
are no cookies to display");
} else {
var
thisCookie = document.cookie.split("; ");
document.write("<BR>Raw
cookie data<BR>");
// Show the cookies as they are stored, together
with escape sequences
for
(i=0; i<thisCookie.length; i++) {
document.write("<BR>Cookie
named " +
thisCookie[i].split("=")[0]);
document.write("
has a value of " +
thisCookie[i]Split("=")[1]);
}
document.write("<BR><BR>Unescaped
cookie data<BR>");
// Show the cookies restored to plain text,
removing escape sequences
for
(i=0; i<thisCookie.length; i++) {
document.write("<BR>Cookie
named " +
unescape(thisCookie[i]Split("=")[0]));
document.write("
has a value of " +
unescape(thisCookie[i]Split("=")[1]));
}
}
</SCRIPT>
</body
If
the user had entered
Angus for the first name,
McNutter for the family name
and
3, Ironside Villas, Scunthorpe for
the address, as shown to the right, the alert message
would display as below:
|
|
|
|
While
the second script would output the following in the web page

The
alert(document.cookie)
function call displays the cookie data without unescaping
its contents, displaying spaces as %20, for instance.
In
The Wine Shop the cookie data is read back to display the
user's name on the home page (default.htm),
in code incorporating a check to determine whether there is
stored data to use:
<SCRIPT
LANGUAGE="JavaScript">
var
thisCookie = document.cookie.split("; ");
var
userName = "";
// Get user's name
for
(i=0; i<thisCookie.length;i++) {
// Check the name of each cookie returned
if
(thisCookie[i]Split("=")[0] == "firstName")
{
// Assign cookie value to field when its name is found
userName
= unescape(thisCookie[i]Split("=")[1]);
}
}
</SCRIPT>
Followed
later by this code which embeds the greeting, if available,into
the page
<SCRIPT
LANGUAGE="JavaScript">
if
(userName != "") {
document.write("Hello
" + userName + "<BR>");
}
</SCRIPT>
As
in all the cookie-retrieval code, we need to split the cookie
string into an array on the delimiter ;<space> using
document.cookie.split(";
"),
then loop through the cookies looking for the cookie name
in which we're interested. Once the cookie is located in the
array, we can split the name element and its associated value
by splitting the pair into a two-element array using thisCookie[i]Split("="),
accessing the name element in thisCookie[i]Split("=")[0]
and the cookie value in thisCookie[i]Split("=")[1].
Because = is one of the characters which is escaped
in text, it only appears in between the cookie elements. That
is, a cookie called TestCookie
with the content specified as Two=Parts
would store the data value Two%3Dparts,
the whole cookie being
TestCookie=Two%3Dparts;
%3D
being the escape sequence for the equals sign, =.
|
  |
|
Getting
the document.cookie
Cookies
may be stored -by default in Windows 2000, using Internet
Explorer 5.x, for instance - as text files in the folder
C:\Documents
and Settings\<user name>\Cookies
where
<user name>
is the user's NT login id, in my own case the folder would
be
C:\Documents
and Settings\CPearson\Cookies
Using
Netscape Communicator under Windows 9x, cookies are saved
in the folder
C:\Program
Files\Netscape\Users\<user name>
|
If
you can locate some cookies and take a look at them
(double click to open them, probably associated with
Notepad in Windows as they are .TXT files) you will
see the name/data pairs together with masses of information
on date and time and the originating web server.
All
of this allows the browser to manage access to cookies
and their security.
The
way they are stored, referencing the user's name, also
retains security between users on the same computer.
|
|
 |
But
knowing any of this doesn't enable you, as a script coder,
to get at cookies which don't belong to you. Getting access
to the cookies inside your web server's security fence is
simply a matter of using the existing contents of the document.cookie,
as we did above:
alert(document.cookie);
and
by assigning a value to the cookie:
document.cookie
= "cookieName" + "=" + "cookieValue"
+ "; ";
Remember,
also, that the user can opt to reject cookies or to choose
to detect each cookie access request and choose whether to
allow that action or not. If you're designing a site that
uses cookies then bear this in mind. If the user rejects a
cookie you probably won't want to continue challenging the
browser to write subsequent cookies.
Summary:
The browser manages access to cookies through document.cookie.
|
 |
|
Splitting
out cookie values from document.cookie
Name/value
pairs can be extracted from a cookie record by using the split
command, specifying a <semicolon><space> delimiter:
var
cookieArray = document.cookie.split("; ");
which
places the cookie elements into an array, starting at thisCookie[0],
through thisCookie[1]
up to the index thisCookie.length
- 1 (since the array starts at zero, the last array
element is indexed one less than the number of elements)
Since
the name is separated from its associated value by an equals
sign, the same technique can be used to extract the name and
the value
var
cookieName = cookieArray[0]Split[0];
which
gets the name from the first element of the two-element array
and
var
cookieValue = cookieArray[0]Split("=")[1];
where
[1] indexes
the second element in the array: the value element.
|
 |
|
Updating
document.cookie
Updating
a cookie requires exactly the same script code as writing
it in the first instance. Since all cookie information is
saved by reference to its name (within the server/user definition
handled by the browser) updating
from
document.cookie
= "orderValue" + "=" + "22.45"
+ "; ";
to
an order value of 35.55 is a case of rewriting the cookie
with the new value
document.cookie
= "orderValue" + "=" + "35.55"
+ "; ";
|
 |
|
Deleting
cookies
Cookies
become stale when their expiry date is reached. If a stale
cookie is read by a browser it is deleted - without a request
for confirmation - and treated as though it did not exist.
If cookies are not accessed it is possible for them to remain
physically on file beyond their expiry date, even though they
are inaccessible.
Deleting
a cookie is achieved by setting its expiry date to something
before now.
In
The Wine Shop the shopping basket cookies are cleared by deleting
them while the user's name and address cookies are retained.
The user's details are given an expiry of six months - This
was an arbitrary decision providing a long-enough shelf life
with expiry within a reasonable time frame.
The
cookies for the shopping basket are created in the shopping
pages (reds.htm and whites.htm)
using this function
<SCRIPT
LANGUAGE="JavaScript">
function addWine(wineType, winePrice)
{
// More code here in actual script . . .
expireDate
= new Date;
expireDate.setMonth(expireDate.getMonth()
+6 );
document.cookie
= escape(wineType) +
"="
+
winePrice
+
";expires="
+
expireDate.toGMTString();
which
is passed the name of the wine and its price from the hyperlink
<a
href="javascript:addWine('Wine 1', '2.99');">
Wine 1 £2.99
</a>
It
is cleared by setting its expiry date to a moment before now
in this function in checkout.htm:
function
placeOrder() {
// More code here in actual script . . .
// Create an expiry date in the past
deleteExpiry
= new Date;
deleteExpiry.setDate(deleteExpiry.getDate()-1);
// More code here in actual script . . .
// Must be a wine type cookie
cookieName
= unescape(thisCookie[i]Split("=")[0]);
cookieValue
= unescape(thisCookie[i]Split("=")[1]);
document.cookie
= escape(cookieName) +
"="
+
escape(cookieValue)
+
";expires="
+
deleteExpiry.toGMTString();
The
next time a browser sees any of these cookies it will delete
them.
|
 |
|
Conclusion
The
Wine Shop was designed and implemented to demonstrate how
cookies can be used to solve a common requirement - getting
data to persist between web pages without posting data back
to a server - and, within that context, how to
- write
cookies
- read
cookies
- update
cookies
- delete
cookies
by
discussing the JavaScript code which manipulates them.
Some
long time ago, Netscape published a fairly definitive article,
Persistent
Client Side HTTP Cookies, which said that cookies
are
a general mechanism which server side connections such as
CGI scripts can use to both store and retrieve information
on the client side of the connection
The
important security aspect of how these state objects,
as the article defines them, cookies as they are now generally
known, is that the information stored on the client side contains
the initiating server's identity and the accepting user's
identity, making the exchange of the information - passing
the cookie - an intimate transaction between, on one side,
the user and the user's browser and, on the other side, the
initiating web server and the page it has served.
Cookies
have a bad press, mostly down to completely unfounded security
fears, which they shouldn't have. Their main shortcoming is
down to users' distrust and users' propensity to disable cookie
processing by their browsers. To use cookies effectively,
you must check that they will be accepted by the client and
will be available when script attempts to access them. If
disabled, you must switch the cookie functionality to server-side
processing.
|
 |
| |
|
|