With many natively compiled programs, you have the ability to read, write, and change files on the computers on which the programs run. Natively compiled programs have nearly unlimited access to any file anywhere on your hard drive.This is generally not a problem because these types of programs are usually written by professionals in well-known software companies whose reputations are on the line. But that's not the case with Web pages. Anybody who has Internet access and a simple text editor has the ability to create potentially dangerous or destructive programs. An unsuspecting Web surfer could visit such a site designed by a malicious person and end up with all of the information on his or her hard drive completely corrupted. Or worse yet, the person who created the site could steal sensitive information from the visitor and use it against him.
For this reason, most programming languages that are used on Web pages, JavaScript included, do not allow you to use files that are stored on a client's machine. The browser that a Web page visitor uses will also have strict rules built into it that prevent the nightmare situations mentioned above. There is one way, however, to store on a client's computer semi-permanent data that can be accessed pragmatically, and that is by using cookies.
A cookie, in its simplest form, is a text file. Cookies can be used to identify a user, store personal information about a Web site visitor, or modify the way a Web page looks and feels based on a user's preference. This information can be used on subsequent visits to your Web page to greet the visitor in his own language, fill out long forms automatically, or resume his visit where he left off the previous time. Cookies are also very easy to store and read compared to other types of files. Unlike other types of files, a cookie file has a size limit of 4 kilobytes or 4096 characters.
Because reading and writing files with Web pages can be such a dangerous operation, the browser takes care of all of the low-level I/O required to read and write to the cookie file. The benefits of this are twofold. First of all, the common Web surfer will not need to fear malicious code that could damage his or her computer. Secondly, the programmer does not have to worry about the complexities of creating file streams—reading and writing data and then remembering to close the file stream when I/O is complete. To write a string to the cookie file, all you need to do is assign a value to the document.cookie parameter. The browser will do the rest.
Here is an example of writing a value to the cookie file taken from a form field:
<html> <head> <title> JavaScript Professional Projects - Writing Cookies </title> <script language=&"JavaScript"> <!-- var now = new Date(); now.setMonth( now.getMonth() + 1 ); document.cookie = "expires=" + now.toGMTString(); --> </script> </head> <body> <center> <font size=6>JavaScript Professional Projects</font><br> <font size=4>Chapter 11: Writing Cookies</font> </center> <br><br> <br><br> <form onSubmit="JavaScript: document.cookie = this.Name.value;"> Please tell me your name: <input type="text" name="Name" size="20"> <input type="submit" value=" Ok "></p> </form> </body> </html>
This example sets the cookie parameter of the document object equal to the value in the text box. The value assigned to this parameter can be of any form. When you want to store more than one item in the cookie file, it is a good idea to use a delimiter, such as a comma or semicolon, so that each item can be accessed via the String object's split() method. Here is an example of doing just that:
<html> <head> <title> JavaScript Professional Projects - Writing Cookies </title> <script language="JavaScript"> <!-- var now = new Date(); now.setMonth( now.getMonth() + 1 ); document.cookie = "expires=" + now.toGMTString(); function getFormData( form ) { var answer = ""; answer += form.Name.value + ","; answer += form.Age.value + ","; answer += form.Color.value; return( answer ); } // --> </script> </head> <body> <center> <font size=6>JavaScript Professional Projects</font><br> <font size=4>Chapter 11: Writing Cookies</font> </center> <br><br> <br><br> <form onSubmit="JavaScript: document.cookie = getFormData( this );"> Please tell me your name: <input type="text" name="Name" size="20"><br> How old are you: <input type="text" name="Age" size="10"><br> What is your favorite color: <input type="text" name="Color" size="10"><br> <input type="submit" value=" Ok "></p> </form> </body> </html>
This example takes the values from each form field and stores them in the cookie file. A comma separates each field value so that they can be easily split up next time the page loads.
It is often a good idea to store the value's name along with the value itself. This will be useful if the number and order of values is not known before the page loads. For example, the previous example could be rewritten as follows:
<html> <head> <title> JavaScript Professional Projects - Writing Cookies </title> <script language="JavaScript"> <!-- var now = new Date(); now.setMonth( now.getMonth() + 1 ); document.cookie = “expires=" + now.toGMTString(); function getFormData( form ) { for( i = 0 ; i < form.elements.length ; i++ ) { with( form.elements[i] ) { if( type != "submit" && type != "button" ) document.cookie = name + "=" + value; } } // --> </script> </head> <body> <center> <font size=6>JavaScript Professional Projects</font><br> <font size=4>Chapter 11: Writing Cookies</font> </center> <br><br> <br><br> <form onSubmit="JavaScript: getFormData( this );"> Please tell me your name: <input type="text" name="Name" size="20"><br> How old are you: <input type="text" name="Age" size="10"><br> What is your favorite color: <input type="text" name="Color" size="10"><br> <input type="submit" value=" Ok "></p> </form> </body> </html>
This example saves all information contained in the form in a name = value pair. With this approach, it would be easy for your Web page to fill in the form automatically the next time the visitor visited or to get just one value out of the cookie file without searching the entire thing.
Because the document.cookie parameter is essentially a string object, the reading of cookies is very simple. Again, all of the low-level I/O operations required to read the cookie file are taken care of by the browser.The only task left to the programmer is parsing the cookie values. If there is only one value in the cookie file, as with the first example in the previous section, it is relatively easy to retrieve it:
<html> <head> <title> JavaScript Professional Projects - Reading Cookies </title> <script language="JavaScript"> <!-- var now = new Date(); now.setMonth( now.getMonth() + 1 ); document.cookie = "expires=" + now.toGMTString(); function getName() { if( document.cookie != "" ) { document.write( "<font size='5'>Welcome back " + document.cookie + "!</font>" ); } } // --> </script> </head> <body> <center> <font size=6>JavaScript Professional Projects</font><br> <font size=4>Chapter 11: Reading Cookies</font> </center> <br><br> <br><br> <script language="JavaScript"> <!-- getName(); // --> </script> <form onSubmit="JavaScript: document.cookie = this.Name.value;"> Please tell me your name: <input type="text" name="Name" size="20"> <input type="submit" value=" Ok "></p> </form> </body> </html>
This example will display a welcome message if the visitor has entered his name previously; otherwise, the page displays as usual. This example is useful only if you are storing a single value in the cookie file. Unfortunately, a single value is not always enough for a good Web site.
Another way to store values in a cookie file is to separate each value by a comma. This makes retrieving data from the file very simple. The following example shows how it is done:
<head> <title> JavaScript Professional Projects - Reading Cookies </title> <script language="JavaScript"> <!-- var now = new Date(); now.setMonth( now.getMonth() + 1 ); document.cookie = "expires=" + now.toGMTString(); function getFormData( form ) { var answer = ""; answer += form.Name.value +","; answer += form.Age.value +","; answer += form.Color.value; return (answer); } function getCookieValue( index ) { var value = document.cookie.split( "," )[index]; return( value == undefined ? "" : value ); } // --> </script> </head> <body> <center> <font size=6>JavaScript Professional Projects</font><br> <font size=4>Chapter 11: Reading Cookies</font> </center> <br><br> <br><br> <form name="theForm" onSubmit="JavaScript: document.cookie = getFormData( this );"> Please tell me your name: <input type="text" name="Name" size="20"><br> How old are you: <input type="text" name="Age" size="10"><br> What is your favorite color: <input type="text" name="Color" size="10"><br> <input type="submit" value=" Ok "><p></p> </form> <script language="JavaScript"> <!-- document.theForm.Name.value = getCookieValue( 0 ); document.theForm.Age.value = getCookieValue( 1 ); document.theForm.Color.value = getCookieValue( 2 ); --> </script> </body> </html>
This example demonstrates how to split the cookie string into its respective parts. Using the String class's split() method, the previously stored values can be broken down into an array, which you can then use in any way you see fit. The example above uses the array for a very short amount of time before discarding it. This reduces the amount of code required—and therefore the download time—but makes the program run slower once downloaded.
The only drawback to this approach is that each value in the cookie file must be read back in the same order that it was entered. If you are working with a team to create a page, this can become a hassle. There is, however, one last way to store values in the cookie file that will let you store and retrieve them in any order, and that is by storing the information you need in a name=value pair. So, instead of storing data in a comma-separated list, the previous example could have stored the form data like this:
function getFormData( form ) { document.cookie = "Name=" + form.Name.value; document.cookie = "Age=" + form.Age.value; document.cookie = "Color=" + form.Color.value; }
As you might have guessed, this creates extra complexity while reading the data back from the cookie file. The previous page could be rewritten using this technique as follows:
<head> <title> JavaScript Professional Projects - Reading Cookies </title> <script language="JavaScript"> <!-- var now = new Date(); now.setMonth( now.getMonth() + 1 ); document.cookie = "expires=" + now.toGMTString(); function getFormData( form ) { document.cookie = "Name=" + form.Name.value; document.cookie = "Age=" + form.Age.value; document.cookie = "Color=" + form.Color.value; } function getCookieValue( name ) { var c = document.cookie; var begin = c.indexOf( name ); if( begin < 0 ) return( "" ); begin += name.length + 1; var end = c.indexOf( ";", begin ); if( end == -1 ) end = c.length; return( c.slice( begin, end ) ); } // --> </script> </head> <body> <center> <font size=6>JavaScript Professional Projects</font><br> <font size=4>Chapter 11: Reading Cookies</font> </center> <br><br> <br><br> <form name="theForm" onSubmit="JavaScript: document.cookie = getFormData( this );"> Please tell me your name: <input type="text" name="Name" size="20"><br> How old are you: <input type="text" name="Age" size="10"><br> What is your favorite color: <input type="text" name="Color" size="10"><br> <input type="submit" value=" Ok "><p></p> </form> <script language="JavaScript"> <!-- document.theForm.Name.value = getCookieValue( "Name" ); document.theForm.Age.value = getCookieValue( "Age" ); document.theForm.Color.value = getCookieValue( "Color" ); --> </script> </body> </html>
This technique allows you to write and read cookie values in any order and without having to parse the entire cookie file. It is usually more work than it's worth if you only need to remember one or two pieces of information, but it makes things much easier if you need to save a lot of data, such as the entire contents of a form.
One example of where saving form data in a cookie file would be beneficial to your visitor would be when entering shipping or billing information. This process can be long and repetitive for the visitor, but can be significantly shortened if the Web page remembers his or her information from page to page. The following example, which is of a form that actually remembers the visitor's address from the last time it was entered and automatically fills out the form, is adapted from an example presented in Chapter 8 on Forms:
<html> <head> <title> JavaScript Professional Projects - Reading Cookies </title> <script language="JavaScript"> <!-- var now = new Date(); now.setMonth( now.getMonth() + 1 ); document.cookie = "expires=" + now.toGMTString(); function saveForm( form ) { for( i = 0 ; i < form.elements.length ; i++ ) { with( form.elements[i] ) { if( type != "submit" && type != "button" && type != "reset" ) document.cookie = name + "=" + value; } } } function loadForm( form ) { for( i = 0 ; i < form.elements.length ; i++ ) { with( form.elements[i] ) { if( type != "submit" && type != "button" && type != "reset" ) value = getCookieValue( name ); } } } function getCookieValue( index ) { var c = document.cookie; var begin = c.indexOf( index + "=" ) + index.length + 1; var end = c.indexOf( ";", begin ); if( end == -1 ) end = c.length; return( c.slice( begin, end ) ); } --> </script> </head> <body onLoad="JavaScript: loadForm( document.mailingForm );"> <center> <font size=6>JavaScript Professional Projects</font><br> <font size=4>Chapter 11: Reading Cookies</font> </center> <br><br> <br><br> <table cellspacing="4" cellpadding="4" width="65%"> <tr> <td> <form name="mailingForm" onSubmit="JavaScript: saveForm( this );"> <b><font size="5">Mailing Address<br></font></b> <br> <b>Last name, First name:</b><br> <input type="text" name="firstLine" size="36"><br> <b>Street/Address:</b><br> <input type="text" name="secondLine" size="36"><br> <b>City State, Zip code:</b><br> <input type="text" name="thirdLine" size="36"> <input type="submit" value="Submit"> </form> </td> </tr> </table> </body> </html>
Because commas may be part of the data in this example, the plus symbol (+) was used as a delimiter between name=value pairs. This simple application makes a visitor's visit much more enjoyable, which in turn makes them want to use your site again.
There are many uses for the cookie file beyond automatically filling out forms for a visitor. Some of its uses include visit counters, remembering user-specific details such as color scheme and language preferences, customization of your Web site, and much more. All this data and more can be stored in a single cookie file in such a way that it can be easily accessed, updated, and applied at a later date. The proper use of the cookie file will make the visitors to your Web site feel welcome and at home. If you greet them with a customized start page containing their name and a list of their commonly used links, they will be more willing to return the next time.
One very popular way to use the cookie file is to count the number of times a specific person has visited your site. Although this example is not useful in terms of Web design, it does illustrate how to alter a preexisting value in a cookie file:
<html> <head> <title> JavaScript Professional Projects - Using Cookies </title> <script language="JavaScript"> <!-- var now = new Date(); now.setMonth( now.getMonth() + 1 ); document.cookie = "expires=" + now.getGMTString(); function getCookieValue( name ) { var c = document.cookie; var begin = c.indexOf( name ); if( begin < 0 ) return( "" ); begin += name.length + 1; var end = c.indexOf( ";", begin ); if( end == -1 ) end = c.length; return( c.slice( begin, end ) ); } function updateVisitCount() { var count = getCookieValue( "visits" ); if( count == "" ) { document.cookie = "visits=" + 1; } else { document.cookie = "visits=" + (parseInt(count)+1); } } --> </script> </head> <body onLoad="JavaScript: updateVisitCount();"> <center> <font size=6>JavaScript Professional Projects</font><br> <font size=4>Chapter 11: Using Cookies</font> </center> <br><br> <br><br> Welcome, you have visited this site <script language="JavaScript"> <!-- var count = getCookieValue( "visits" ); document.write( count == "" ? "0" : count ); --> </script> times! </body> </html>
As you can see, all that you need to do to change a value in a cookie file is to assign the name=value pair to the cookie file a second time.
One important variable in the cookie file that must be replaced very often is the expires variable. This cookie variable holds the date on which the client computer should delete the cookie file. The expires value should be in the format that is returned by the Date class's getGMTString() method. You may have noticed the following three lines:
var now = new Date(); now.setMonth( now.getMonth() + 1 ); document.cookie = "expires=" + now.getGMTString();
in the examples in this chapter. They tell the client computer to delete the cookie file one month after the current date. Every time a person visits a site with that code, the expires variable will be updated. When a client has not visited the site in a month, the cookie file for that site is deleted. If the expires value is set to a date before the current browser date, or is left out altogether, the cookie file will be deleted as soon as the visitor closes his browser window.
Two other generic cookie variables help to hide the data from other Web sites. The path variable, if set, will limit access to the cookie file to only the pages within the given path on the Web server. Similarly, the domain variable, if set, will restrict the cookie file's access to only the pages in the given domain.
Allowing a user to customize your Web site's color scheme is another popular use for the cookie file. For instance, a user might not like the various colors used on your Web page for one reason or another and may want to change it.
Here is a simple example of how to customize your site for your visitor's color preferences (among other things!):
<html> <head> <title> JavaScript Professional Projects - Using Cookies </title> <script language="JavaScript"> <!-- var now = new Date(); now.setMonth( now.getMonth() + 1 ); document.cookie = "expires=" + now.toGMTString(); function saveForm( form ) { for( i = 0 ; i < form.elements.length ; i++ ) { if( form.elements[i].value != "" && form.elements[i].name != "" ) { document.cookie = form.name + "." + form.elements[i].name + "=" + form.elements[i].value; } } } function loadForm( form ) { for( i = 0 ; i < form.elements.length ; i++ ) { if( form.elements[i].name != "" ) { form.elements[i].value = getCookieValue( form.name + "." + form.elements[i].name ); } } } function getCookieValue( name ) { var c = document.cookie; var begin = c.indexOf( name ); if( begin < 0 ) return( "" ); begin += name.length + 1; var end = c.indexOf( ";", begin ); if( end == -1 ) end = c.length; return( c.slice( begin, end ) ); } function updateVisitCount() { var count = getCookieValue( "visits" ); if( count == "" ) { document.cookie = "visits=" + 1; } else { document.cookie = "visits=" + (parseInt(count)+1); } } function setCustoms() { var bg = getCookieValue( "custom.bgColor" ); var fg = getCookieValue( "custom.fgColor" ); if( bg != "" ) document.bgColor = bg; if( fg != "" ) document.fgColor = fg; } // --> </script> </head> <body onLoad="JavaScript: loadForm( document.mailingForm ); loadForm( document.custom ); updateVisitCount(); setCustoms();"> <center> <font size=6>JavaScript Professional Projects</font><br> <font size=4>Chapter 11: Using Cookies</font> </center> <br><br> <br><br> Welcome, you have visited this site <script language="JavaScript"> <!-- var count = getCookieValue( "visits" ); document.write( count == "" ? "0" : count ); --> </script> times!<br><br> <table cellspacing="4" cellpadding="4" width="85%"> <tr> <td> <form name="mailingForm" onSubmit="JavaScript: saveForm( this );"> <b><font size="5">Mailing Address<br></font></b> <br> <b>Last name, First name:</b><br> <input type="text" name="firstLine" size="36"><br> <b>Street/Address:</b><br> <input type="text" name="secondLine" size="36"><br> <b>City State, Zip code:</b><br> <input type="text" name="thirdLine" size="36"> <input type="submit" value="Submit"> </form> </td> <td> <form name="custom" onSubmit="JavaScript: saveForm( this );"> <table> <tr> <td><b><font size="5">Customize<br> <br></font></b></td> <tr> <td><b>Background Color: </b></td> <td><input type="text" name="bgColor" size="15"></td> </tr> <tr> <td><b>Foreground Color:</b></td> <td><input type="text" name="fgColor" size="15"></td> <td> <input type="submit" value="Submit"></td> </tr> </table> </form> </td> </tr> </table> </body> </html>
This example uses cookies to perform three different operations. The first simply counts the number of times a person has visited the page. The second automatically fills not one, but two forms with information that has been entered by the visitor previously. The third operation the cookie file above performs is to customize the background and foreground colors on the page.
The following function stores data in the cookie file, in this case the mailing address of the visitor:
function setCustoms() { var bg = getCookieValue( "custom.bgColor" ); var fg = getCookieValue( "custom.fgColor" ); if( bg != "" ) document.bgColor = bg; if( fg != "" ) document.fgColor = fg; }
reads values from the cookie file, which had previously been saved from a form, and changes the colors of the page accordingly. You'll notice the addition of the form name followed by a period and the field name being used as the name part of the name=value pair. This is used to be able to distinguish elements on the separate forms apart. It was not really necessary in this example because none of the elements have the same name, but could be useful later on as you learn how to use a single cookie file for multiple Web pages.
One very useful feature of cookie files is that Web pages can share the data stored in them. For example, if a Web page stores data in the cookie file, as follows:
<html> <head> <title> JavaScript Professional Projects - Using Cookies </title> <script language="JavaScript"> <!-- var now = new Date(); now.setMonth( now.getMonth() + 1 ); document.cookie = "expires=" + now.toGMTString(); function saveForm( form ) { for( i = 0 ; i < form.elements.length ; i++ ) { if( form.elements[i].value != "" && form.elements[i].name != "" ) { document.cookie = form.name + "." + form.elements[i].name + "=" + form.elements[i].value; } } } function lodeForm( form ) { for( i = 0 ; i < form.elements.length ; i++ ) { if( form.elements[i].name != "" ) { form.elements[i].value = getCookieValue( form.name + "." + form.elements[i].name ); } } } function getCookieValue( name ) { var c = document.cookie; var begin = c.indexOf( name ); if( begin < 0 ) return( "" ); begin += name.length + 1; var end = c.indexOf( ";", begin ); if( end == -1 ) end = c.length; return( c.slice( begin, end ) ); } // --> </script> </head> <body onLoad="JavaScript: loadForm( document.mailingForm );"> <center> <font size=6>JavaScript Professional Projects</font><br> <font size=4>Chapter 11: Using Cookies</font> </center> <br><br> <br><br> <table cellspacing="4" cellpadding="4" width="85%"> <tr> <td> <form method="POST" action="Display.html" name="mailingForm" onSubmit="JavaScript: saveForm( this );"> <b><font size="5">Mailing Address<br></font></b> <br> <b>Last name, First name:</b><br> <input type="text" name="firstLine" size="36"><br> <b>Street/Address:</b><br> <input type="text" name="secondLine" size="36"><br> <b>City State, Zip code:</b><br> <input type="text" name="thirdLine" size="36"> <input type="submit" value="Submit"> </form> </td> </tr> </table> </body> </html>
Then a second page, named Display.html, could read the data and display it:
<html> <head> <title> JavaScript Professional Projects - Using Cookies </title> <script language="JavaScript"> <!-- var now = new Date(); now.setMonth( now.getMonth() + 1 ); document.cookie = "expires=" + now.toGMTString(); function getCookieValue( name ) { var c = document.cookie; var begin = c.indexOf( name ); if( begin < 0 ) return( "" ); begin += name.length + 1; var end = c.indexOf( ";", begin ); if( end == -1 ) end = c.length; return( c.slice( begin, end ) ); } // --> </script> </head> <body> <center> <font size=6>JavaScript Professional Projects</font><br> <font size=4>Chapter 11: Using Cookies</font> </center> <br><br> <br><br> This is the mailing address you have entered.<br> Please check to make sure it is correct. <br><br> </div> <table border="1" cellspacing="5" cellpadding="5"><tr><td> <b> <script language="JavaScript"> <!-- document.write( getCookieValue( "mailingForm.firstLine" ) + "<br>" ); document.write( getCookieValue( "mailingForm.secondLine" ) + "<br>" ); document.write( getCookieValue( "mailingForm.thirdLine" ) ); // --> </script> </b> </td></tr></table> </body> </html>
Display.html can read the data and display it because nothing in the cookie file tells Display.html that it can't use the data therein. You can restrict access to data in the cookie file by setting the path and domain values in the cookie. These values default to the directory or domain in which the Web page resides. This makes it so that only pages in the same directory/domain or deeper can view the cookie data of the page that creates it.
There are two fundamental limitations to the cookie file itself. First of all, it can only be 4 kilo-bytes or 4096 characters long. That is approximately equal to the number of characters in a full page of text (12–point serif font) including the spaces. Secondly, the semicolon (;) and equal sign (=) are reserved characters in the cookie file and should not be used in either the name or value of the name=value pair.
Another cookie limitation concerns the browser itself: Settings within the browser may not allow your Web page to create cookies at all. It is very simple to tell whether cookies are enabled in the client's browser—simply set a cookie and try to read it back. If you are unable to read back the value you set in the cookie file, then cookies are not enabled.
Here's an example of how to check whether cookies are enabled in the client's browser:
<html> <head> <title> JavaScript Professional Projects - Using Cookies </title> <script language="JavaScript"> <!-- function cookiesEnabled() { document.cookie = "Enabled=True"; return( getCookieValue( "Enabled" ) == "True" ); } function getCookieValue( name ) { var c = document.cookie; var begin = c.indexOf( name ); if( begin < 0 ) return( "" ); begin += name.length + 1; var end = c.indexOf( ";", begin ); if( end == -1 ) end = c.length; return( c.slice( begin, end ) ); } // --> </script> </head> <body> <center> <font size=6>JavaScript Professional Projects</font><br> <font size=4>Chapter 11: Detecting if Cookies are Enabled</font></center> <br><br> <br><br> <script language="JavaScript"> <!-- if( cookiesEnabled() ) { document.write( "<b>Congratulations, cookies are" + " enabled in your browser.</b>" ); } else { document.write( "<b>Sorry, cookies are not" + " enabled in your browser.</b>" ); } // --> </script> </body> </html>
Upon discovering that the client does not have cookies enabled, you can either redirect him to a cookie-less page or instruct him on how to enable cookies.