!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN"> Complete Idiot's Guide to JavaScript
Chapter 17
Care for a Cookie?

In This Chapter

It’s one of the tastiest of morsels. That’s why most of us experience a specific pleasant sensation when we think of the word cookie. With that in mind, we placidly consider the Web-based cookie, which—though coined with the driest of technogeek humor—has absolutely nothing to do with the aforementioned snack food. In fact, there’s no good reason why the subject of this chapter is called a cookie. Nonetheless, what it lacks in taste, the Web cookie possesses in style: It’s a useful little critter, despite its non-sequitir name.

Using Web cookies, you can personalize Web pages and keep track of information about a user. In this chapter, I’ll introduce the concept of a cookie, and you’ll learn to create and access them with JavaScript.

Behind the Ball of Dough: Cookie Basics

Cookies allow a Web page to “track” information about a particular visitor. Introduced with the release of Netscape Navigator 2.0, cookies have become widely used on Web sites in the months and year(s) since.

To better illustrate the function of a cookie, let’s look at a typical, but simple, example. You own a Web page. A user, whom we’ll call Mark Harmon (for no particular reason), visits your Web page. He might have reached it by typing its URL into his Web browser, or he might have simply clicked on a link from a different page. But it makes no difference how he got there.

When Mark Harmon visits your page, you assign him a specific identification number behind the scenes; Mark Harmon is not aware of this (unless he’s configured his browser to alert him of cookie requests). Using a cookie, you then save this identification number to Mark Harmon’s hard drive. The next time Mark Harmon visits your Web page, you know it’s him—or, more accurately, you know that it’s the same computer from which Mark Harmon first visited your page.

The above concept is an example of one use of a cookie: You have stored information to track a particular visitor to your page. You can expand on that concept in a variety of ways. You might use cookies to record past options that Mark Harmon has selected on your site so you can personalize your site and show only information that is relevant to Mark Harmon, based on his past selections.

Cookies have been applied to a wide variety of Web sites, from mail order catalogs to search engines. Using cookies in an ethical manner, you have the potential to mold your Web pages to fit each visitor by remembering their past preferences, and so forth.

In this chapter, I’m going to show you how you can use JavaScript to create some simple cookies. Then you’ll retrieve these cookies and customize your Web page to reflect the cookie. While the potential applications and implementations of cookies can grow quite complex, I’ll stick to the basics. (Or should that read “non-stick”!?)

Cookie Crumbs: Ethical Issues

The widespread use of cookies has raised the hackles of paranoia among a growing segment of Web users. For many, the mere notion that a Web page can “track” their actions conjures up frightening implications. Others dissent from this view, believing that cookies are by-and-large a harmless convenience. In reality(as usual), both sides have valid points.

It is true that a cookie can be used to keep a record of a fair amount of information about your visit to a site. The cookie can “remember” which links you’ve selected, which products you’ve ordered, and so forth. Using this data, many Web marketers hope to collect demographic statistics that they can use to target promotions and so forth.

However, there are certain limitations to exactly how much information a cookie can track and how personal that information can be. Consider these restrictions on cookies:

While the above points make a strong case for the safety of data security with regards to cookies, they do not necessarily prevent cookies from being used unethically. One question is this: Is it ethical to e-mail reams of promotional messages based on the selections of a visitor on a Web page? Many would say no; some would say yes. There is much subjectivity to ethical judgments, but the main point is that cookies simply track information; what other people do with that information and how they use it is where social ethics begin and technology ends.

The Vanilla Cookie

To begin this culinary lesson, let’s start with a very basic cookie: merely tracking the date and time of the user’s last visit to the Web page.

The mechanics behind a cookie are simple enough. When the user opens your page, you read any data that exists in the currently stored cookie for this user. You use this data in whatever way you want, and then you update the cookie—which contains a name, a value, and other possible information—to reflect the current visit. 

In this particular example, you’ll check the existing cookie for the last time the user visited this page (if there is any), display that information on the page, and then update the cookie to reflect the current date and time of this visit.

Keep the above process in mind, or refer back to it if necessary as I explain each step in the cookie making process. While the basic concept is simple, there are a lot of details that can become confusing. I’ll start simply.

What Are the Ingredients of a Cookie?

Glad you asked. Literally, a cookie is a piece of data that is stored either in the computer’s memory or on the hard drive. This piece of data may contain such information as:

How Do I Create a Cookie?

Another excellent question. By combining the ingredients, of course! Specifically, using JavaScript, you assign a string value to the cookie property of the current document:

document.cookie = “name = value; expires = date_to_expire”

Ingredients

Suppose, then, that you want to store a cookie that tracks the current date and time of the user’s visit to this Web page. You’ll name the cookie lastvisit; the variable today will contain the current date and time; and the variable expdate will contain the date on which the cookie expires.

document.cookie = “lastvisit = today; expires = expdate”

The above is fine and good, but here come the details. As it is, cookie syntax requires that the expiration date be in a very specific format: Wdy, DD-MMM-YYYY HH:MM:SS GMT.

Wdy can be any valid three-letter abbreviation for a day name (such as Sun); DD represents a two-digit reflection of the day of the month (such as 09); MMM represents any of the valid three-letter abbreviations for the month (such as Sep); YYYY is the four-digit year (such as 1996). Hours, minutes, and seconds are represented by two digits each (such as 22:15:00). And finally, GMT is the only valid time zone. So if you are calculating an expiration time, don’t neglect to account for the time difference between GMT and your own time zone.)

Fortunately, you’ll soon learn about a JavaScript function that can construct the proper date format for you in many cases. However, if you want to specify a specific expiration date that is not calculable in a JavaScript function (in other words, if you want the cookie to expire on “January 1, 1998” as opposed to the calculable “30 days from today”), you still have to refer to the syntax rules above.

Unlike the expiration date, the variable today (which contains the date of the user’s lastvisit) can be stored in any format you want. After all, that’s your data, which you can use however you want.

Procedure 

Now you’re ready to write your first function. Combining the ingredients discussed so far, you’ll code a small function named BakeCookie(), which creates the above-described cookie. First, the code, and then the explanation.

function BakeCookie()
{
var today = new Date ();
var expdate = new Date ();
expdate.setTime(expdate.getTime() + (1 * 24 * 60 * 60 * 1000 * 365));
expdate=expdate.toGMTString();
document.cookie="lastvisit="+escape(today)+";expires="+expdate+";"
}

Following your function definition, you define two variables—today and expdate—and assign the current date to each of them. Next, you use a somewhat complicated call to the setTime() method of expdate, setting it to 24 hours ahead of the current time. In doing so, you’re preparing to bake your cookie to expire in 24 hours (or one day). To set expdate 30 days ahead, for instance, simply change the initial 1 to 30 in line 5 (where it begins 1 * 24).

After assigning the expiration date to expdate, you call its toGMTString() method, which converts the date into the syntax needed for the cookie. Lastly, and most importantly, you make the assignment to document.cookie, which bakes the cookie. 

Notice that you add the expression escape(today) to the string value assigned to document.cookie, instead of merely adding today. This is because the value of the cookie cannot contain white space or punctuation marks, and calling escape(today) will insert the value of today without any such characters (by saving each illegal character as a special code). Later, when you read the value of the cookie, you’ll reverse this effect so that any white space and punctuation marks can be returned to the cookie’s value.

Hands Off! Domain Restrictions

Matters can become a little more complicated here. By specifying a domain name in your cookie, you limit which Web pages have access to that cookie. For instance, if in your cookie creation, you appended the specification domain=mysite.com, only Web pages that reside on mysite.com could access this cookie.

The example above assumes that your original Web pages does reside on mysite.com; remember that you cannot specify a domain other than the one the Web page currently resides in! In other words, you cannot tell a Web page located at beagledog.com that it can access cookies only at terrier.com. That would violate all attempts at cookie privacy.

Every subdomain of the specified domain can access the cookie. To clarify, if you restrict a cookie’s domain to mysite.com, all Web pages on bob.mysite.com and mary.mysite.com can access the cookie because those are both subdomains of mysite.com. If you wanted to be even stricter, you could restrict the cookie to mary.mysite.com, in which case pages on bob.mysite.com or mysite.com could not access the cookie.

Furthermore, you can also restrict which pages within a domain can access the cookie. This is done using the path= specification in the cookie definition. For instance, if your Web pages reside within http://mary.mysite.com/marypages/, you could specify path=/marypages. And if you combine that with the domain restriction, you might wind up with a cookie assignment that looks something like this:

document.cookie = “lastvisit = today; expires = expdate; domain = mary.mysite.com; path=/marypages”

This would restrict access to the cookie to Web pages that are within /marypages on the server mary.mysite.com. Whew, this can become quite a mouthful! 

In the interest of shortcuts, I should note that leaving out the domain or path specifications does not leave your cookie completely vulnerable. If you do not specify a domain restriction, a default restriction will be used (which consists of the domain within which the Web page resides). Therefore, if your page is on a server at mary.mysite.com, and you don’t specify the above domain restriction, access to the cookie will be restricted to pages on mary.mysite.com anyway! Thus, in many cases, you can omit the domain restriction, as you did in the earlier example function BakeCookie(). However, in certain unusual server configurations, you might find that your page functions better if you do include the domain and/or path restrictions. When it comes to circumstances where security matters, specifying restrictions is always safer than not doing so.

How Many Cookies in a Batch?

While creating a cookie from a Web page is simple enough (document.cookie=”cookie_attributes”), you 
might be wondering how many cookies you can create from a page? The answer, in fact, lies not with
JavaScript but with the Web browser.

Netscape Navigator 2.0 and 3.0, for instance, honor up to 20 cookies per domain. This means that across 
all of the pages that reside in the same server domain, you can create a maximum of 20 cookies. Dramatically
different, however, is Microsoft Internet Explorer 3.0, which supports only one single cookie per domain!

As the JavaScript author, you should keep the above limitations in mind. If your pages are primarily 
intended for Netscape users, you can bake a 20-cookie batch. But if you want to remain compatible 
with Microsoft Internet Explorer users, you should pack as much information as you need to into a single
cookie(Internet Explorer will silently refuse to create a new cookie if a valid cookie from the same domain 
already exists).

Setting the table

Now that you’ve created your BakeCookie() function, you’re ready to incorporate it into a very simple Web page. Consider the HTML code below:

<html>
<head>
<script>
function BakeCookie()
{
var today = new Date ();
var expdate = new Date ();
expdate.setTime(expdate.getTime() + (1 * 24 * 60 * 60 * 1000 * 365));
expdate=expdate.toGMTString();
document.cookie="lastvisit="+escape(today)+";expires="+expdate+";"
}
</script>
</head>
<body bgcolor="#FFFFFF">
<p align="center"><H1><strong>Welcome to the Cookie Monster!</strong></H1></p><br>
<script>
BakeCookie()
</script>
</body>
</html>

Now you’ve created a simple page, which contains only the centered text “Welcome to the Cookie Monster!”. Within the <HEAD> tags is your first function, BakeCookie(), and at the end of the document is a simple JavaScript call to the function.

When a user loads this page for the first time, he sees only the welcome text; but the current date and time cookie is stored. In this case, because you specified an expiration date, the cookie is stored to his hard drive. Had you not specified an expiration date, the cookie would remain in RAM and would expire as soon as the user shut down his Web browser.

That’s just wonderful, right? But how, then, do you make use of this cookie? Conceptually, it’s simple: When the user loads this page, you read the value of the cookie and use it to customize the message on the page. Following that, you update the cookie with the new date and time.

The First Bite: Reading the Cookie

To read the value of the cookie, you need to create a function. This function will search the user’s cookie list for the named cookie of your choice. If it finds that cookie, and if the page has access to the cookie (as explained in the earlier section on domain and path restrictions), it returns the value of that cookie. The skeleton of such a function would look like this in pseudo-JavaScript:

function ServeCookie (cookie_name)
{statements which search for and retrieve value of cookie}

You could then incorporate a call to ServeCookie() into some other JavaScript code, which would use the value of the cookie as in:

document.writeln (“Hi again! Your last visit to this page was on “ + ServeCookie(“lastvisit”))

The above code would add a message to the current Web page, greeting the user with the exact date and time of his last visit, as recorded in the cookie. Of course, if the cookie has expired since the user’s last visit, the situation will be as if the person had never visited before and has no pre-existing cookie for this page.

Before you, then, lies the matter of coding the ServeCookie() function. The truth is, this function is a bit complicated. Needless to say, I don’t want to burden an audience new to JavaScript with a complex, long, and possibly confusing explanation. Fortunately, this function is very portable: You can use it, as is, in any Web page, without having to understand exactly how it works. All you have to do is call it with the name of the cookie to serve, and it delivers that cookie’s value. If the cookie does not exist or has expired, this function returns the value null. Here is the function ServeCookie():

function ServeCookie(name)
{
var namestr = name + "="
var namelen = namestr.length
var cooklen = document.cookie.length
var i = 0
while (i < cooklen)
{ var j = i + namelen
if (document.cookie.substring(i, j) == namestr)
{ endstr = document.cookie.indexOf (";", j)
if (endstr == -1) {endstr = document.cookie.length}
return unescape(document.cookie.substring(j,endstr)) 
}
i = document.cookie.indexOf(" ", i) + 1
if (i == 0) break
}
return null
}

 

The Confessions of ServeCookie()

A technically curious sort, eh? You really want to know what is going on inside the ServeCookie() function?
Well, I’m not going to spell it out line by line, but here’s a basic summary.

Using a combination of string properties, such as length, and string methods, such as substring() and 
indexOf(), as well as several if statements, this function locates the first character to the right of the equal 
sign following the cookie name and extracts the string of characters from that position to the character 
immediately preceding the first semicolon. If the cookie name cannot be found, a value of null is returned.
Well, now look, I’ve gone and spilled all the secrets. Happy now?

Got Milk? Washing It Down

All of the essential elements have been covered: you know the functions for creating the cookie, as well as for reading its value. You have the basic HTML for your Web page, and you’ve seen how to incorporate a call to ServeCookie in a document.writeln JavaScript statement. Now, then, you dunk:

<html>
<head>
<script>
function BakeCookie()
{
var today = new Date ();
var expdate = new Date ();
expdate.setTime(expdate.getTime() + (1 * 24 * 60 * 60 * 1000 * 365));
expdate=expdate.toGMTString();
document.cookie="lastvisit="+escape(today)+";expires="+expdate+";"
}
function ServeCookie(name)
{
var namestr = name + "="
var namelen = namestr.length
var cooklen = document.cookie.length
var i = 0
while (i < cooklen)
{ var j = i + namelen
if (document.cookie.substring(i, j) == namestr)
{ endstr = document.cookie.indexOf (";", j)
if (endstr == -1) {endstr = document.cookie.length}
return unescape(document.cookie.substring(j,endstr)) 
}
i = document.cookie.indexOf(" ", i) + 1
if (i == 0) break
}
return null
}
</script>
</head>
<body bgcolor="#FFFFFF">
<p align="center"><H1><strong>Welcome to the Cookie Monster!</strong></H1></p><br>
<script>
if (ServeCookie("lastvisit") == null)
{document.writeln ("<H2>Hello stranger! Enjoy your first visit to this page.</H2><HR>")}
else {document.writeln("<H2>You’re back! Last visit to this page:<BR>"+ServeCookie("lastvisit")+"</H2><HR>")}
BakeCookie() 
</script>
</body>
</html>

The only new bit above is the logic added to the end of the document between the final set of <SCRIPT> tags (seven lines up from the last line). You test to see if the value for the lastvisit cookie is null, in which case the user has not visited this page before (or his cookie has expired). If his cookie is null, you write an appropriate first-time greeting to the page. If his cookie does contain a value, you welcome him back and display the time and date of his last visit. Finally, you call the BakeCookie() function and update the cookie.

An initial visit to this page, then, would result in a screen resembling the one shown here.

Either this is the user’s first visit to this page, or his cookie has expired.

Someone who’s re-visiting this page and has a valid cookie would receive the familiar greeting shown in the following figure.

This is no stranger; he’s been to this page before! Cookies remember.

Chips, Almonds, and Assorted Cookie Magic

In this chapter, we’ve looked in detail at constructing a relatively simple cookie. The basic procedure, however, can be applied to any level of complexity. For instance, you could do any of the following:

You can do any of these things by building on the JavaScript concepts and code shown in this chapter. Certainly, the code will grow more complex as you send the values from form fields to cookie-baking functions. To repeat a standard recommendation, learn by watching others! When you come across a Web page which is “remembering” your choices, it’s using cookies. Spend some time studying the source code for that Web page to see how the author created it.

Remember, though, that not all Web pages use JavaScript to track cookies. Obviously, look for Web pages whose source code indicates that they are using JavaScript!

All Together Now

The tools provided throughout these chapters should serve as a good overview of JavaScript and its applications. I've avoided delving into highly complex programming examples in part because this is an introduction to the language and in part because such examples are more about programming science than the JavaScript language itself.

The best way to learn a programming language is, as my irritating piano teacher used to say, through “Practice, practice, practice.” And experimentation, although she didn't ever mention that. You'll need to read these chapters multiple times, in different manners. For the first read-through, you might look to pick up the general concepts behind JavaScript programming. On a second read-through, try focusing on the specific syntax of the JavaScript statements and expressions.

Then, at each example, attempt to throw together your own code that varies slightly from the example. See if it works, and if so, vary it further with new ideas. Eventually, you work toward combining concepts from multiple examples, and before you know it, you're constructing your own programs from scratch. Be sure to read through the script example chapters in Part 4, “Scripting the Whole Bean.” They provide full examples of JavaScript programs, with explanations, which pull together all the concepts from throughout this book.

One word of advice is not to be beset by frustration when programs don't work the first time through. Errors and malfunctions are the stuff that programs and programmer's lives are made of. Sometimes, the error is caused by something silly, such as forgetting a closing bracket or parenthesis. Other times, you haven't a clue why the program is not working. In those cases, it's a good idea to try other approaches to the end, and see if they work. Or just scream. There is a whole science to debugging—which is of great value to learn if you become heavily involved in programming—but when all else fails, I always recommend the "clear head" approach. That is, walk away. Come back another day. Many dastardly bugs are resolved this way. The rested, clear mind can solve some problems in minutes that the haggard mind struggles with for hours. A perusal through Chapter 25, “What to Do When It Won’t Work: Debugging Your Scripts,” might be beneficial, as well. There you'll find some further consideration given to script debugging and pest extermination.

Now that you’ve had that not-exactly-a-pep talk, you're off and programming!

The Least You Need to Know

Previous Chapter Next Chapter


Beginning of ChapterTable of ContentsBook Home PageQue Home Page


For comments or technical support for our books and software, select Talk to Us.
To order books, call us at 800-716-0044 or 317-228-4366.

© 1997, QUE Corporation, an imprint of Macmillan Publishing USA, a Simon & Schuster Company.