Using Cookies


Cookies are a way for a server to store information on the user's machine. This is one way that a site can remember or track a user over the course of a visit. Think of a cookie like a name tag: you tell the server your name and it gives you a sticker to wear. Then it can know who you are by referring back to that name tag.

Testing for Cookies

To effectively program using cookies, you need to be able to accurately test for their presence. The best way to do so is to have your Web browser ask what to do when receiving a cookie. In such a case, the browser will prompt you with the cookie information each time PHP attempts to send a cookie.

Different versions of different browsers on different platforms all define their cookie handling policies in different places. I'll quickly run through a couple of options for popular Web browsers.

To set this up using Internet Explorer on Windows XP, choose Tools > Internet Options. Then click the Privacy tab, followed by the Advanced button under Settings. Click "Override automatic cookie handling" and then choose "Prompt" for both First- and Third-party Cookies.

Using Firefox on Windows, choose Tools > Options. Then click Privacy and expand the Cookies section. Finally, select "ask me every time" in the Keep Cookies drop-down menu. If you are using Firefox on Mac OS X, the steps are the same, but you must start by choosing Firefox > Preferences.

Unfortunately, Safari on Mac OS X does not have a cookie prompting option, but it will allow you to view existing cookies, which is still a useful debugging tool. This option can be found under the Security Preferences panel.


Some people are suspicious of cookies because they believe that cookies allow a server to know too much about them. However, a cookie can only be used to store information that the server is given, so it's no less secure than most anything else online. Unfortunately, many people still have misconceptions about the technology, which is a problem as those misconceptions can undermine the functionality of your Web application.

In this section you will learn how to set a cookie, retrieve information from a stored cookie, alter a cookie's settings, and then delete a cookie.

Setting cookies

The most important thing to understand about cookies is that they must be sent from the server to the client prior to any other information. Should the server attempt to send a cookie after the Web browser has already received HTMLeven an extraneous white spacean error message will result and the cookie will not be sent (Figure 9.1). This is by far the most common cookie-related error.

Figure 9.1. The headers already sent… error message is all too common when creating cookies. Pay attention to what the error message says in order to find and fix the problem.


Cookies are sent via the setcookie() function:

 setcookie (name, value); setcookie ('first_name', 'Larry'); 

The second line of code will send a cookie to the browser with a name of first_name and a value of Larry (Figure 9.2).

Figure 9.2. If I have my browser set to ask for permission when receiving cookies, I'll see a message like this when a site attempts to send one.


You can continue to send more cookies to the browser with subsequent uses of the setcookie() function:

 setcookie ('ID', 263); setcookie ('email', 'phpmysql2@  dmcinsights.com); 

As when using any variable in PHP, when naming your cookies, do not use white spaces or punctuation, but do pay attention to the exact case used.

To send a cookie

1.

Create a new PHP document in your text editor (Script 9.1).

 <?php # Script 9.1 - login.php 

Script 9.1. The login.php script creates cookies upon a successful login.


For this example, I'll make a new login.php script (which works in conjunction with the scripts from Chapter 7, "Using PHP with MySQL").

2.

Validate the form.

 if (isset($_POST['submitted'])) {   require_once ('../mysql_connect.    php);   $errors = array();   if (empty($_POST['email'])) {      $errors[] = 'You forgot to enter        your email address.';   } else {      $e = escape_data($_POST       ['email]);   }   if (empty($_POST['password'])) {      $errors[] = 'You forgot to enter       your password.';   } else {      $p = escape_data($_POST       ['password]);   } 

These steps are very similar to those in Chapter 7. The main conditional checks if the form has been submitted. Then the database connection is made by including the connection script (which also defines the escape_data() function as of Chapter 8, "Web Application Development"). Finally, the email address and password inputs are checked for values.

3.

Retrieve the user_id and first_name for this user from the database.

 if (empty($errors)) {   $query = "SELECT user_id,    first_name FROM users WHERE    email='$e AND password=    SHA('$p)";   $result = @mysql_query ($query);   $row = mysql_fetch_array    ($result, MYSQL_NUM); 

If both validation tests were passed, the database will be queried, retrieving the user_id and first_name values for the record where the email column matches the submitted email address and the password matches an encrypted version of the submitted password.

4.

If the user entered the correct information, log the user in.

 if ($row) {   setcookie ('user_id', $row[0]);   setcookie ('first_name', $row[1]); 

The $row variable will have a value only if the preceding query returned at least one record (indicating the submitted email address and password match those on file). In this case, two cookies will be created.

5.

Redirect the user to another page.

 $url = 'http://' . $_SERVER  ['HTTP_HOST] . dirname($_SERVER  ['PHP_SELF]); if ((substr($url, -1) == '/') OR  (substr($url, -1) == '\\') ) {   $url = substr ($url, 0, -1); } $url .= '/loggedin.php'; header("Location: $url"); exit(); 

Using the steps outlined in Chapter 8, the redirection URL is first dynamically generated. To do so, various $_SERVER values are referenced, along with the dirname() function. Any trailing slashes are also chopped off should this script be within a subdirectory (this is all covered in Chapter 8).

Finally the header() function is called to redirect the user and the script's execution is terminated with exit().

6.

Complete the $row conditional (started in Step 4) and the $errors conditional, and then close the database connection.

   } else {     $errors[] = 'The email address      and password entered do not      match those on file.';     $errors[] = mysql_error() .      '<br /><br />Query: ' $query;   } } mysql_close(); 

The error management in this script is much like that in the register.php script in Chapter 8. Because nothing can be sent to the Web browser before calling the setcookie() and header() lines, the errors have to be saved and printed later.

The second error message here is for debugging purposes only and shouldn't be used on a live site.

7.

Complete the main submit conditional, include the HTML header, and print any error messages.

 } else {   $errors = NULL; } $page_title = 'Login'; include ('./includes/header.html'); if (!empty($errors)) {    echo '<h1 >Error!     </h1>    <p >The following     error(s) occurred:<br />';    foreach ($errors as $msg) {     echo " - $msg<br />\n;   }   echo '</p><p>Please try again.     </p>'; } ?> 

Again, this and the previous steps are like those in Chapter 8's register.php script. The first else conditional sets the $errors variable to NULL, indicating that no errors need to be printed out when this page is first run. Then the page's title is set and the template's header file is included (this application uses the same template as those in Chapters 7 and 8). Finally, any existing errorsfrom the form's submissionare printed.

8.

Display the HTML form.

 <h2>Login</h2> <form action="login.php"   method="post>   <p>Email Address: <input type=    "text name="email" size="20"    maxlength="40 /> </p>   <p>Password: <input type=    "password name="password"     size="20 maxlength="20" /></p>   <p><input type="submit" name=    "submit value="Login" /></p>   <input type="hidden" name=    "submitted value="TRUE" /> </form> 

The HTML form takes two inputsan email address and a passwordand submits the data back to this same page. You can make the email address input sticky by presetting a value attribute, if you'd like.

9.

Include the PHP footer.

 <?php include ('./includes/footer.html'); ?> 

10.

Save the file as login.php, upload it to your Web server in the same directory as the files from Chapter 7, and load the form in your Web browser (Figure 9.3).

Figure 9.3. The login form.


Tips

  • Cookies are limited to about 4 KB of total data, and each Web browser can remember only 20 cookies from any one server.

  • Because cookies rely upon the HTTP header, you can set them in PHP using the header() function. It's very important to remember that the setcookie() and header() functions must be called before any data is sent to the Web browser.

  • The setcookie() function is one of the few functions in PHP that could generate different results in different browsers, since browsers will treat cookies differently. Be sure to test your Web sites in multiple browsers on different platforms to ensure consistency

  • In Chapter 11, "Extended Topics," I'll show how to control browser output so that cookies can be sent at nearly any point in a script.


Accessing cookies

To retrieve a value from a cookie, you only need to refer to the $_COOKIE superglobal, using the appropriate cookie name as the key (as you would with any array). For example, to retrieve the value of the cookie established with the line

 setcookie ('username', 'Trout'); 

you would use $_COOKIE['username'].

In the following example, the cookies set by the login.php script will be accessed in two ways. First a check will be made that the user is logged in (otherwise, they shouldn't be accessing this page). Next, the user will be greeted by their first name, which was stored in a cookie.

To access a cookie

1.

Create a new PHP document in your text editor (Script 9.2).

 <?php # Script 9.2 - loggedin.php 

Script 9.2. The loggedin.php script prints a greeting to a user based upon a stored cookie.


The user will be redirected to this page after successfully logging in. It will print a user-specific greeting.

2.

Check for the presence of a cookie.

 if (!isset($_COOKIE['user_id'])) { 

Since I don't want a user to access this page unless that user is logged in, I first check for the cookie that should have been set (in login.php).

3.

Complete the if conditional.

   $url = 'http://' . $_SERVER    ['HTTP_HOST] . dirname($_SERVER    ['PHP_SELF]);   if ((substr($url, -1) == '/') OR     (substr($url, -1) == '\\') ) {      $url = substr ($url, 0, -1);   }   $url .= '/index.php';   header("Location: $url");   exit(); } 

If the user is not logged in, they will be automatically redirected to the main page. This is a simple way to limit access to logged-in users.

4.

Include the page header.

 $page_title = 'Logged In!'; include ('./includes/header.html'); 

5.

Welcome the user, using the cookie.

 echo "<h1>Logged In!</h1> <p>You are now logged in, {$_COOKIE  ['first_name]}!</p> <p><br /><br /></p>"; 

To greet the user by name, I refer to the $_COOKIE['first_name'] variable (enclosed within curly braces to avoid parse errors).

6.

Complete the HTML page.

 include ('./includes/footer.html'); ?> 

7.

Save the file as loggedin.php, upload to your Web server (in the same directory as login.php), and test in your Web browser by logging in through login.php (Figure 9.4).

Figure 9.4. If you used the correct username and password, you'll be redirected here after logging in.


Since these examples use the same database as those in Chapter 7, you should be able to log in using the registered username and password submitted at that time.

8.

If you like, change the cookie settings for your browser (Figure 9.5) and test again (Figure 9.6).

Figure 9.5. To see the effect of the setcookie() function, set your Web browser to ask before storing a cookie.


Figure 9.6. The user_id cookie with a value of 1.


Tips

  • If the submitted email address and username do not match those on file, a public message is displayed, followed by the query (Figure 9.7). Remember to delete the debugging message (the MySQL error plus the query) before using this code on a live site.

    Figure 9.7. If no record was returned from the database, this will be the result. The blank space after the second dash is for the mysql_error(), which doesn't exist (since the query ran fine).


  • If your mysql_connect.php file sends anything to the Web browser or even has blank lines or spaces after the closing PHP tag, you'll see a headers already sent error.

  • With register_globals enabled, PHP will load variables in a specific order (depending upon the setting in the php.ini file), normally: get, post, cookie, session. If you do not use the superglobal arrays to refer to variables, then the value of a $username variable in a form could be overridden by the value of a $username variable stored in a cookie. This is one reason why you should program without relying upon register_globals.

  • A cookie is not accessible until the setting page (e.g., login.php) has been reloaded or another page has been accessed (in other words, you cannot set and access a cookie in the same page).

  • If users decline a cookie or have their Web browser set not to accept them, they will automatically be redirected to the home page in this example, even if they successfully logged in. For this reason you may want to let the user know when cookies are required.


Setting cookie parameters

Although passing just the name and value arguments to the setcookie() function will suffice, you ought to be aware of the other arguments available. The function can take up to four more parameters, each of which will alter the definition of the cookie.

 setcookie ('name', 'value', expiration,   'domain', secure); 

The expiration argument is used to set a definitive length of time for a cookie to exist, specified in seconds since the epoch (the epoch is midnight on January 1, 1970). If it is not set, the cookie will continue to be functional until the user closes his or her browser. Normally, the expiration time is determined by adding a particular number of minutes or hours to the current moment, retrieved using the time() function. The following line will set the expiration time of the cookie to be 1 hour (60 seconds times 60 minutes) from the current moment:

 setcookie ('name', 'value', time()+  3600); 

The path and domain arguments are used to limit a cookie to a specific folder within a Web site (the path) or to a specific host. For example, you could restrict a cookie to exist only while a user is within the admin folder of a domain (and the admin folder's subfolders):

 setcookie ('name', 'value', time()+  3600, '/admin/'); 

Finally, the secure value dictates that a cookie should only be sent over a secure HTTPS connection. A 1 indicates that a secure connection must be used, and a 0 says that a standard connection is fine.

 setcookie ('name', 'value', time()+   3600, '/admin/', '', 1); 

As with all functions that take arguments, you must pass the setcookie() values in order. To skip any parameter, use NULL or an empty string. The expiration and secure values are both integers and are therefore not quoted.

To demonstrate this information, I'll add an expiration setting to the login cookies so that they last for only one hour.

To set a cookie's expiration date

1.

Open login.php in your text editor (refer to Script 9.1).

2.

Change the two setcookie() lines to include an expiration date that's 60 minutes away (Script 9.3):

 setcookie ('user_id', $row[0],  time()+3600, '/', '', 0); setcookie ('first_name', $row[1],  time()+3600, '/', '',  0); 

Script 9.3. The login.php script now uses every argument the setcookie() function can take.


With the expiration date set to time() + 3600 (60 minutes times 60 seconds), the cookie will continue to exist for an hour after it is set. While I'm at it, I explicitly state the other cookie parameters.

3.

Save the script, upload to your Web server, and test in your Web browser (Figure 9.8).

Figure 9.8. Once an expiration date or time has been set, it will be reflected in the cookie sent to the Web browser.


Tips

  • Some browsers have difficulties with cookies that do not list every argument. Explicitly stating every parametereven as an empty string, as I did herewill achieve more reliable results across all browsers.

  • Here are some general guidelines for cookie expirations: If the cookie should last as long as the session, do not set an expiration time; if the cookie should continue to exist after the user has closed and reopened his or her browser, set an expiration time months ahead; and if the cookie can constitute a security risk, set an expiration time of an hour or fraction thereof so that the cookie does not continue to exist too long after a user has left his or her browser.

  • For security purposes, you could set a five- or ten-minute expiration time on a cookie and have the cookie resent with every new page the user visits (assuming that the cookie exists). This way, the cookie will continue to persist as long as the user is active but will automatically die five or ten minutes after the user's last action.

  • Setting the path to '/' will make the cookie visible within an entire domain (Web site).

  • Setting the domain to '.site.com' will make the cookie visible within an entire domain and every subdomain (www.site.com, admin.site.com, pages.site.com, etc.).

  • E-commerce and other privacy-related Web applications should use an SSL (Secure Sockets Layer) connection for all transactions, including the cookie.


Deleting cookies

The final thing to understand about using cookies is how to delete one. While a cookie will automatically expire when the user's browser is closed or when the expiration date/time is met, sometimes you'll want to manually delete the cookie instead. For example, in Web sites that have registered users and login capabilities, you will probably want to delete any cookies when the user logs out.

Although the setcookie() function can take up to six arguments, only one is actually requiredthe cookie name. If you send a cookie that consists of a name without a value, it will have the same effect as deleting the existing cookie of the same name. For example, to create the cookie first_name, you use this line:

 setcookie('first_name', 'Larry'); 

To delete the first_name cookie, you would code:

 setcookie('first_name'); 

As an added precaution, you can also set an expiration date that's in the past.

 setcookie('first_name', '', time()-300); 

To demonstrate all of this, I'll add logout capability to the site, which will appear only to logged-in users. As an added bonus, the header file will be altered so that a Logout link appears when the user is logged-in and a Login link appears when the user is logged-out.

To delete a cookie

1.

Create a new PHP document in your text editor (Script 9.4).

 <?php # Script 9.4 - logout.php 

Script 9.4. The logout.php script deletes the previously established cookies.


2.

Check for the existence of a user_id cookie; if it is present, delete both cookies.

 if (!isset($_COOKIE['user_id'])) {   $url = 'http://' . $_SERVER    ['HTTP_HOST] . dirname($_SERVER    ['PHP_SELF]);   if ((substr($url, -1) == '/') OR     (substr($url, -1) == '\\') ) {      $url = substr ($url, 0, -1);   }   $url .= '/index.php';   header("Location: $url");   exit(); } else {   setcookie ('first_name', '',     time()-300, '/', '', 0);   setcookie ('user_id', '',     time()-300, '/', '', 0); } 

As with my loggedin.php page, if the user is not already logged in, I want this page to redirect the user to the home page. If the user is logged in, these two cookies will effectively delete the existing ones.

3.

Make the remainder of the PHP page.

 $page_title = 'Logged Out!'; include ('./includes/header.html'); echo "<h1>Logged Out!</h1> <p>You are now logged out, {$_COOKIE  ['first_name]}!</p> <p><br /><br /></p>"; include ('./includes/footer.html'); ?> 

The page itself is also much like the loggedin.php page. Although it may seem odd that you can still refer to the first_name cookie (that you just deleted in this script), it makes perfect sense considering the process:

  1. This page is requested by the client.

  2. The server reads the appropriate cookies from the client's browser.

  3. The page is run and does its thing (including sending new cookies).

So, in short, the original first_name cookie data is available to this script when it first runs. The set of cookies sent by this page (the delete cookies) aren't available to this page, so the original values are still usable.

4.

Save the file as logout.php.

To create the logout link

1.

Open header.html (refer to Script 7.1) in your text editor.

2.

Change the links to (Script 9.5)

 <li ><a href=  "index.php title="Go to the Home   Page>Home</a></li> <li><a href="register.php" title=  "Register>Register</a></li> <li><?php if ( (isset($_COOKIE['user_id'])) &&   (!strpos($_SERVER['PHP_SELF],   'logout.php)) ) {   echo '<a href="logout.php" title=  "Logout>Logout</a>'; } else {   echo '<a href="login.php" title=  "Login>Login</a>'; } ?></li> 

Script 9.5. The header.html file now displays either a login or a logout link depending upon the user's current status.


Instead of having a permanent login link in my template, I'll have it display a Logout link if the user is logged in or a Login link if the user is not. The preceding conditional will accomplish just that based upon the presence of a cookie.

Because the logout.php script would ordinarily display a logout link (because the cookie exists when the page is first being viewed), I have to add a statement to my conditional, checking that the current page is not the logout.php script. The strpos() function, which checks if one string is found within another string, is an easy way to accomplish this.

3.

Save the file, upload to the Web server (placed within the includes directory), and test the login/logout process in your Web browser (Figures 9.9, 9.10, and 9.11).

Figure 9.9. The home page with a Login link.


Figure 9.10. After the user logs in, the page now has a Logout link.


Figure 9.11. The result after logging out.


Tips

  • To see the result of the setcookie() calls in the logout.php script, turn on cookie prompting in your browser (Figure 9.12).

    Figure 9.12. This is how the deletion cookie appears in a Firefox prompt.


  • Due to a bug in how Internet Explorer on Windows handles cookies, you may need to set the domain parameter to false (without quotes) in order to get the logout process to work when developing on your own computer (i.e., through localhost).

  • When deleting a cookie, you should always use the same parameters that were used to set the cookie. If you set the domain and path in the creation cookie, use them again in the deletion cookie.

  • To hammer the point home, remember that the deletion of a cookie does not take effect until the page has been reloaded or another page has been accessed (in other words, the cookie will still be available to a page after that page has deleted it). This is why I needed to add the && (!strpos($_SERVER['PHP_SELF'], 'logout.php') clause to the header.html conditional (because the cookie itself would still be available on the logout.php page).




    PHP and MySQL for Dynamic Web Sites. Visual QuickPro Guide
    PHP and MySQL for Dynamic Web Sites: Visual QuickPro Guide (2nd Edition)
    ISBN: 0321336577
    EAN: 2147483647
    Year: 2005
    Pages: 166
    Authors: Larry Ullman

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net