Chapter 6
IN THIS CHAPTER
Storing data
Using cookies
Working with sessions
Playing with carts
In the previous chapters of this minibook, I show you how to use the HTTP GET
and POST
methods to send data from one web page to another. Although they work fine for clicking links and submitting forms, they're somewhat impractical to use for sharing data between all the web pages in an application. To do that requires some other form of persistent data, someplace where you can temporarily store it so that your PHP programs can access the data at any time from any page. This is where sessions and carts help out. This chapter explains how they work, why you shouldn’t be afraid of them, and how to use them as another piece of your dynamic web applications.
Most dynamic web applications require some way of temporarily storing data while site visitors work their way through the application web pages. I’m not talking about long-term storage of data (I cover that in the next minibook). I’m talking about short-term storage of data that one web page can store and another web page retrieves, such as passing an authenticated user’s info through the website. This helps your application track the site visitors and what they’re doing within the application.
This is where HTTP cookies come into play. Cookies have received somewhat of a bum rap in the web world, mainly because of a misunderstanding of how companies use them. A company can’t track all of your browsing history using cookies, but it can track which of its advertisements you’ve visited. This helps the marketing gurus target advertising to your browser based on which of the company’s links you’ve already visited. Cookies do have a valid place in the assembly line of dynamic web application tools, playing a crucial function in being able to keep track of individual site visitors in your application. It’s crucial that you know how they work and how to use them.
This section walks through the basics of cookies, why you need them, and how to safely (and responsibly) use them in your dynamic web applications.
In the mainframe computer world, people who need to access programs running on the system must first log in to the system. This usually requires entering some type of data that uniquely identifies you, such as typing a user ID, placing your finger on a scanner, or inserting a smart ID card that includes a unique encrypted key. When the system authenticates that you are who you say you are, it allows you access to the system and your data. This process starts what’s called a session.
The mainframe tracks every transaction you perform within the session. A system administrator can look through the log file and identify the user who performed each transaction on the system.
When you’ve finished entering transactions, you must log off of the system to stop the session. If you forget to log out, another user can come in and enter new transactions that the mainframe credits to your session.
On a mainframe system, keeping track of sessions is easy, because each user logs in from a specific device (either a directly connected terminal or a persistent network connection), performs transactions, and then logs out. Unfortunately, it’s not that easy in our dynamic web applications.
The HTTP standard was intended to retrieve data from a remote server in an anonymous, stateless manner. This means not having to deal with the formalities of a session. In essence, a web session consists of a single transaction, and it doesn’t even require an ID to identify the user.
Dynamic web applications are somewhat of a hybrid of these two environments. You want to maintain the ease of an HTTP anonymous session, but you need to track users and their transactions like a mainframe session. This is where cookies come to save the day.
Cookies are data that a server can temporarily store in the browser of each site visitor. When the browser stores the cookie data, the server can retrieve that information in later transactions with the site visitor. This allows the server (and, thus, the server-side application) to identify individual site visitors and keep track of what they’re doing within the application. This is the beginning of a true web session.
Before you start thinking chocolate chip and oatmeal raisin, let me start out by saying we’re not talking about those types of cookies here. There are several different characteristics of HTTP cookies, each one defining a different way to use the cookie. Table 6-1 lists the different HTTP cookie types you can use.
TABLE 6-1 Types of HTTP Cookies
Type |
Description |
|
Can only be accessed via HTTP, not via JavaScript |
|
Expires at a specific date/time or after a specific length of time |
|
Can only be sent in requests from the same origin as the target domain |
|
Can only be sent in HTTPS connections |
|
Expires when the client browser window closes |
|
Uses a top-level domain as the origin, allowing multiple websites access |
|
Uses a domain that doesn't match the URL domain for the web page |
The standard type of cookie is the persistent cookie. Persistent cookies are sent by the web server to be stored in the client browser for a specific amount of time. Your application can store data in a persistent cookie and then access that data any time in the future until the cookie expires.
As opposed to persistent cookies, session cookies only last for as long as the client browser window stays open. When the site visitor closes the browser window, the session cookies (and the data they contain) go away.
Third-party cookies are what gave cookies a bad name. With persistent and session cookies, a web server can only retrieve and read the cookies that it sets — it doesn’t have access to cookies set by other servers. This helps protect the privacy of site visitors by preventing a single server from determining all the websites a site visitor has visited. Third-party cookies use a loophole to get around that.
These days it’s very common for a web page to contain embedded advertisements from other websites. Those embedded advertisements run code created by the remote website and can set cookies from the remote website, storing the location of the main website the advertisement is embedded in. This allows a company to purchase advertising space on multiple common websites and then determine which site visitors have visited which website by tracking the cookies that it sets in the advertisements. Now that’s sneaky!
The HTTP standard defines how web servers set and retrieve cookies within the HTTP session with a client browser. When a client browser requests to view a web page on a server, it sends an HTTP GET
request:
GET /index.php
Host: www.myserver.com
The request specifies the web page to retrieve and the host from where to retrieve it (usually the same server the request is sent to). The host server returns an HTTP response, which includes the status code for the request, along with any cookies that it wants to set using the Set-Cookie
statement and then the HTML for the requested web page:
HTTP/1.0 GET OK
Content-type: text/html
Set-Cookie: name1=value1; attributes
Set-Cookie: name2=value2; attributes
Web page HTML content
The cookie information appears before the HTML from the requested web page. The server assigns each cookie a unique name and a value, and possibly adds optional attributes that define the cookie type. The client browser stores each cookie as a separate temporary file on the client workstation.
The Set-Cookie
statement can list one or more optional attributes for the cookie. Table 6-2 lists the cookie attributes that you can set.
TABLE 6-2 HTTP Cookie Attributes
Attribute |
Description |
|
Specifies the domain the cookie applies to. If omitted the server is the default location. |
|
Specifies the expiration date for the cookie as an HTTP timestamp value. |
|
Specifies that the cookie can only be retrieved in an HTTP session. |
|
Specifies the expiration time for the cookie in seconds. |
|
Indicates the path in the URL that must exist in the requested resource. |
|
Specifies if the cookie can only be accessed from the same site that set it. Values are |
|
Specifies that the cookie can only be sent in an HTTPS secure session. |
If either the Expires
or Max-Age
attributes are set, the cookie is a persistent cookie. It will remain available until the expiration date and/or time. If no attributes are specified, the cookie is a session cookie and will be deleted when the client browser window closes.
The Expires
attribute specifies an exact date and time the cookie will expire:
Set-Cookie: id=25; Expires=Mon 12 May 2025 13:30:00 GMT;
The Max-Age
attribute sets a time duration (in seconds) that the cookie should remain valid:
Set-Cookie: id=25; Max-Age=3600
After the server sets a cookie, the next time the client browser requests a web page from the same destination, it sends all the cookies set from that destination in the HTTP request using a single Cookie
statement:
GET /index.php
Host: www.myserver.com
Cookie: name1=value1; name2=value2
The Cookie
statement just sends the name/value pair for all the cookies set by that server. It doesn't send any attributes that the server had set for the cookies. The server can then extract the separate cookie names and values and pass them to any server-side programming language (such as your PHP programs).
Overall, the implementation of cookies in browsers is somewhat nonstandard. No two client browsers may handle cookies the same way. There are however a few minimum requirements that the HTTP standard specifies:
Most browsers exceed these requirements, but it’s best not to test the limits in your applications. If you need to store large amounts of data for an application, it’s best to use some other type of persistent data storage, such as a database. You can store a key identifying the site visitor as a cookie, and then use that key to reference the larger amounts of data stored in the database associated with that site visitor.
PHP allows you to fully interact with cookies in your web applications. You can set cookies from one web page, retrieve and read them in another web page, and remove them from yet another web page. This section walks through the code you need to use to implement cookies in your PHP applications.
PHP uses the setcookie()
function to set new cookies and update existing cookies. Here’s the basic format of the setcookie()
function:
setcookie(name [, value] [, expire] [, path] [, domain] [, secure] [, httponly])
The only required parameter is the name of the cookie, although you'll almost always want to include a cookie value, too. Leaving off the value sets the cookie value to NULL
.
The optional expire parameter allows you to specify the expiration date and time as a Unix timestamp value, making it a persistent cookie. The Unix timestamp format is an integer value of the number of seconds since midnight on January 1, 1970. The last four parameters allow you to specify the URL paths and domains allowed to access the cookie, and whether the cookie should be set as Secure
or HttpOnly
.
Be careful with the expire parameter. Even though the HTTP message sends the expire attribute as a full date and time, with the setcookie()
function you set it using a timestamp value, not a standard date and time. The way most PHP developers do that is by adding the number of seconds to the current date and time retrieved from the time()
function:
setcookie("test", "Testing", time() + (60*60*24*10));
This sets the cookie named test
to expire ten days from the time the web page is accessed by the site visitor.
Follow these steps to test setting a persistent cookie from a PHP application:
<?php
setcookie("test1", "This is a test cookie", time() + 600);
?>
<!DOCTYPE html>
<html>
<head>
<title>PHP Cookie Test</title>
</head>
<body>
<h1>Trying to set a cookie</h1>
</body>
</html>
Save the file as cookietest1.php
in the DocumentRoot
folder for the web server.
For XAMPP in Windows, that's c:\xampp\htdocs
; for XAMPP in macOS, that’s /Applications/XAMPP/htdocs
.
http://localhost:8080/cookietest1.php
You may need to change the TCP port number to match your web server.
Using your browser's Developer Tools, check the cookies that are set from the web page and their expiration date and time.
You should see the test1
cookie created. It should be set to expire in ten minutes.
The Developer Tools allow you to see the test1
cookie that was set by the program. For the Microsoft Edge browser, look in the Debugger section for the cookies, as shown in Figure 6-1.
FIGURE 6-1: Displaying the cookie in the Microsoft Edge Developer Tools window.
The cookie is set, along with the value, and the expiration time is set to ten minutes (600 seconds) in the future.
PHP makes reading cookies that your application sets a breeze. The PHP server automatically places all cookies passed from the client in the $_COOKIE[]
special array variable. The cookie name that you assigned in the setcookie()
statement becomes the associative array key:
$_COOKIE['name']
If a cookie has expired, you'll get an error message when trying to access it using the $_COOKIE[]
array variable. It’s a good idea to always check that the cookie exists first, using the isset()
function:
if (isset($_COOKIE['test'])) {
$data = $_COOKIE['test'];
} else {
$data = 0;
}
This code will set the value of the $data
variable used in the program to 0
if the cookie doesn't exist. You can then check for the 0
condition in the variable to determine if the cookie is missing.
Follow these steps to test reading the cookie you set in the cookietest1.php
program:
<!DOCTYPE html>
<html>
<head>
<title>PHP Cookie Test</title>
</head>
<body>
<h1>Retrieving the test cookie</h1>
<?php
if (isset($_COOKIE['test1'])) {
$data = $_COOKIE['test1'];
echo "<p>The cookie was set: $data</p> \n";
} else {
echo "<p>Sorry, I couldn't find the cookie</p> \n";
}
?>
</body>
</html>
cookietest2.php
in the DocumentRoot
folder for your web server.http://localhost:8080/cookietest2.php
If you run the cookietest2.php
program within ten minutes of the cookietest1.php
program, you should see the data stored in the cookie appear on the web page and in the browser Developer Tools, as shown in Figure 6-2.
FIGURE 6-2: The result of the cookietest2.php
code displaying the cookie data.
If you wait longer than the ten-minute expiration time of the cookie, you'll get the message that the program couldn’t find the cookie.
You can easily modify an existing cookie just by resending the cookie with the updated value:
setcookie("test1", "New data", time() + 600);
When you resend the cookie, the browser overwrites the original cookie information with the new information, including the updated expiration time. If you specify a time relative to the current time, that will change the expiration time of the cookie.
To delete a cookie, just set the expiration time to a time value in the past:
setcookie("test1", "", time() – 1);
When you set the expiration time to one second earlier than the current time, the browser will immediately expire the cookie.
Follow these steps to test setting and removing a cookie:
<?php
if (!isset($_COOKIE['test1'])) {
setcookie("test1", "This is a test cookie", time() + 600);
} else {
setcookie("test1", "", time() - 1);
}
?>
<!DOCTYPE html>
<html>
<head>
<title>Deleting a Cookie</title>
</head>
<body>
<h1>Cookie status:</h1>
<?php
if (isset($_COOKIE['test1'])) {
$data = $_COOKIE['test1'];
echo "<p>Cookie set: $data<p>\n";
} else {
echo "<p>Cookie not set</p>\n";
}
?>
<a href="cookietest3.php">Click to try again</a>
</body>
</html>
cookietest3.php
in the DocumentRoot
folder for your web server.http://localhost:8080/cookietest3.php
Note if the cookie has been set or not, then click the Click to Try Again link in the web page to reload the page.
You can continue clicking the link to toggle the cookie on and off.
In the cookietest3.php
code, each time you visit the page the PHP code checks if the cookie exists. If the cookie exists, the code deletes it by setting the expiration time back one second. If the cookie doesn’t exist, it creates the cookie. You can continue going back and forth by clicking the link to reload the page each time.
PHP handles sessions and session cookies a little differently from persistent cookies. Instead of storing session cookies in the client browser as separate data files, PHP assigns a unique session ID to each site visitor session and stores that as a session cookie in the client browser.
PHP then stores any data associated with the session in a temporary file located on the actual PHP server. This helps protect the session data, because it’s not being stored in the client browser at any time. When the session ends, PHP automatically deletes the temporary session file on the server.
This feature alone makes using sessions to store data more attractive than using persistent cookies. The only data sent between the client browser and the server is the session ID value assigned to the session. All the data stays local on the server.
The following sections describe how to use sessions in your PHP applications.
Before you can set or read any session data, you must start the session. PHP provides an easy way for you to declare sessions in your web pages. The PHP session_start()
function automatically sends the required HTTP code to the remote client browser to create a session cookie. PHP assigns the session cookie a unique ID value to identify the session.
In the PHP file (the code for your web page), the session_start()
function must come before any HTML code, including the <!DOCTYPE>
tag. The session PHP code then looks like this:
<?php
session_start();
?>
<!DOCTYPE html>
<html>
You must add the session_start()
function at the start of every web page that needs to access the session data. If the session_start()
function is not present, PHP doesn't look for the session ID, and your application can’t access any of the session data.
After you initialize the session using the session_start()
function, you can use the $_SESSION[]
array variable to both set and retrieve session data in your application. To set a new value, just define it in an assignment statement:
$_SESSION['item'] = "computer";
Use the session cookie name as the associative array key. When you set a session cookie name/value pair, you can access it at any time in any web page that's part of the same session:
echo "You purchased a " . $_SESSION['item'];
Follow these steps to test out setting and reading session cookie data:
<?php
session_start();
?>
<!DOCTYPE html>
<html>
<head>
<title>Testing Session Cookies</title>
</head>
<body>
<h1>Setting a session cookie</h1>
<?php
$_SESSION['test2'] = "Second test cookie";
?>
<a href="sessiontest2.php">Click to continue</a>
</body>
</html>
sessiontest1.php
in the DocumentRoot
folder for your web server.<?php
session_start();
?>
<!DOCTYPE html>
<html>
<head>
<title>Testing Session Cookies</title>
</head>
<body>
<h1>Retrieving the session cookie</h1>
<?php
if (isset($_SESSION['test2'])) {
$data = $_SESSION['test2'];
echo "<p>Session cookie: $data</p>\n";
} else {
echo "<p>Error accessing the session
cookie</p>\n";
}
?>
<a href="sessiontest1.php">Go back to start</a>
</body>
</html>
sessiontest2.php
in the DocumentRoot
folder for your web server.http://localhost:8080/sessiontest1.php
http://localhost:8080/sessiontest2.php
When you open the sessiontest1.php
web page, the PHP code starts a session and then saves the test session cookie and value. If you use the Developer Tools in your browser, you can see that the web page doesn't create a test2
cookie, but instead creates a cookie named PHPSESSID
with a long hexadecimal value, as shown in Figure 6-3.
FIGURE 6-3: Looking for the PHP session cookie using the Developer Tools.
This is the unique session ID that the PHP server assigned to the browser session.
When you click the link, the browser requests the sessiontest2.php
web page from the server, passing the session ID cookie that was set in the sessiontest1.php
web page code. This tells PHP that the second page is part of the same browsing session and allows the PHP code access to any session cookie data set in that session. Figure 6-4 shows the output that you should see from the sessiontest2.php
file, along with the PHPSESSID
cookie value shown in the Developer Tools.
FIGURE 6-4: The output from the sessiontest2.php
file.
When you close the browser window, that deletes the session ID session cookie. When you reopen the browser window and attempt to go directly to the sessiontest2.php
file, the original session ID is not present, so PHP creates a new session for the connection. That new session doesn't have access to the data set in the original session, so you’ll get an error message, as shown in Figure 6-5.
FIGURE 6-5: The error message generated from trying to access data in an expired session.
If you take a look at the PHPSESSID
value using the Developer Tools, it has a different value than before, because the new browser window is a new session.
There are three ways to remove session cookie data:
To remove individual session values, use the unset()
function, along with the session array variable to remove:
unset($_SESSION['item']);
This removes the session name/value pair from the session data in the temp file on the server, but maintains the temp file and the session ID session cookie in the client browser.
To remove all the session name/value pairs from the session data, but maintain the session ID session cookie, use the session_unset()
function:
session_unset();
You can terminate an entire session by using the session_destroy()
function anywhere in your PHP application:
session_destroy();
This removes all session name/value pairs associated with the session, as well as the session ID value assigned to the client browser's session cookie. If the site visitor continues on to another web page in the application, the session_start()
function will set a new session ID session cookie, along with a new temporary session file on the server associated with the session.
Quite possibly one of the most common uses of session cookies is the ability to track items customers intend to purchase while browsing through an online store. Just like old-fashioned shopping carts, the online shopping cart should allow customers to place one or more of an item into the cart, view the cart contents at any time, and remove any item from the cart — all with the benefit of not having to listen to a squeaky cart wheel!
This section shows you how to use session cookies to implement simple shopping carts in your own dynamic web applications.
To create an online shopping cart, you just need to use two PHP features: session cookies and arrays. The idea is to create a session cookie as an empty array variable. As shoppers place new items into the cart, the code adds a new element to the array, setting the quantity of the item selected as the array value.
You do that by creating a multidimensional array session cookie. That sounds like a mouthful, but it’s actually very easy to create:
$_SESSION['cart'] = array();
This single line of code creates a session cookie named cart
and defines it as an array variable. That's the start to your shopping cart.
When you create the shopping cart session cookie, you’re ready to start placing items into it. To place an item into the cart, you’ll create a new array element and pair it with a value. The array element key will be the name of the product placed in the cart, and the array element value will be the quantity of the product to purchase. That looks like this:
$_SESSION['cart']['apples'] = 10;
This statement creates an array element in the $_SESSION['cart']
session cookie with the name apples
and assigns it a value of 10.
You can create as many array elements as you want to add into the session cookie array variable.
Now that you have a multidimensional session cookie array that contains the products you placed in the cart, all you need to do is extract the values stored in the array to see what's there. However, that can be a little tricky.
Because the array is an associative array, you can’t just loop through the array element using a simple for
or while
statement because you don't know what key names are in the array. This is where the foreach
statement comes in handy! It allows you to iterate through all the array keys without having to know what they are:
foreach($_SESSION['cart'] as $key => $value) {
echo "<p>$key - $value</p>\n";
}
The foreach
statement iterates through the array, extracting each key and value pair in each iteration. You can then use the individual key and value pairs in your code to list the items and their quantities.
Because each product in the cart is a separate array element of the session cookie, you can handle each product individually, as long as you know the product name that you used for the array key. To remove an individual product, just specify it in the unset()
function:
unset($_SESSION['cart']['apples']);
This statement removes just the apples
array key and its value from the array, leaving any other items still in the array. If you want to remove the entire shopping cart, you'd use the following:
session_unset($_SESSION['cart']);
This statement removes the entire cart
session cookie. To start a new cart, your code would need to create a new cart session cookie and make it an array variable.
As you can tell, working with a shopping cart is a multistep process, and it can get somewhat complicated. Let’s take a look at an example of using a shopping cart on a web page. Listing 6-1 shows the code.
LISTING 6-1 The carttest.php Program
<?php
session_start();
?>
<!DOCTYPE html>
<html>
<head>
<title>Shopping Cart Test</title>
</head>
<body>
<h1>Items available</h1>
<form action="carttest.php" method="post">
<table>
<tr><th>Item</th><th>Quantity</th></tr>
<tr><td>Apples</td><td><input type="text" name="apples" size="2"></td></tr>
<tr><td>Bananas</td><td><input type="text" name="bananas" size="2"></td></tr>
</table>
<input type="submit" value="Click to add to cart">
</form>
<br>
<?php
if (isset($_POST['apples'])) {
if (is_numeric($_POST['apples'])) {
$_SESSION['cart']['apples'] = $_POST['apples'];
} elseif ($_POST['apples'] == "Remove") {
unset($_SESSION['cart']['apples']);
}
}
if (isset($_POST['bananas'])) {
if (is_numeric($_POST['bananas'])) {
$_SESSION['cart']['bananas'] = $_POST['bananas'];
} elseif ($_POST['bananas'] == "Remove") {
unset($_SESSION['cart']['bananas']);
}
}
?>
<fieldset style="width:300px">
<legend>Your Shopping Cart</legend>
<?php
if (!isset($_SESSION['cart'])) {
$_SESSION['cart'] = array();
echo "Your shopping cart is empty\n";
} else {
echo "<form action=\"carttest.php\" method=\"post\">\n";
echo "<table>\n";
echo "<tr><th>Item</th><th>Quantity</th><th/></tr>\n";
foreach($_SESSION['cart'] as $key => $value) {
echo "<tr><td>$key</td><td>$value</td>\n";
echo "<td><input type=\"submit\" name=\"$key\" value=\"Remove\"></td></tr>\n";
}
echo "</table>\n";
echo "</form>\n";
}
?>
</fieldset>
</body>
</html>
Listing 6-1 shows the carttest.php
program, which I'll walk through to demonstrate using a shopping cart. The first part of the program creates a simple form for selecting the products to purchase. The code lists two products — apples and bananas — and provides a text box to indicate the quantity of each you want to place in the shopping cart.
The next section uses PHP code to check whether the form has already been submitted. If the site visitor has submitted the form, the PHP code checks to see which (if any) of the products had been selected for purchase. If either one had been selected, the PHP code stores the new quantity number in the cart session cookie for that product:
if (isset($_POST['apples'])) {
if (is_numeric($_POST['apples'])) {
$_SESSION['cart']['apples'] = $_POST['apples'];
Next, the code shows the shopping cart status. If there isn’t a shopping cart session cookie, one is created:
$_SESSION['cart'] = array();
If a shopping cart session cookie exists, the program creates a form containing the shopping cart items, along with a Remove button. The foreach
statement is used to iterate through each of the items in the shopping cart:
foreach($_SESSION['cart'] as $key => $value) {
echo "<tr><td>$key</td><td>$value</td>\n";
echo "<td><input type=\"submit\" name=\"$key\" value=\"Remove\"></td></tr>\n";
}
Because there are two forms on the web page, you need to add some more code to check if a Remove button has been clicked by the shopper. That was added to the code that checks for the other form data:
} elseif ($_POST['apples'] == "Remove") {
unset($_SESSION['cart']['apples']);
}
Follow these steps to test the carttest.php
program:
Save the file as carttest.php
in the DocumentRoot
folder for your web server.
It's important that you use this exact filename because the forms use that as the action attribute.
http://localhost:8080/carttest.php
When you first open the carttest.php
file, the shopping cart should show that it’s empty, as shown in Figure 6-6.
FIGURE 6-6: The initial shopping cart web page.
When you enter a quantity for a product and then click the button to submit it, the product and quantity appear in the shopping cart, as shown in Figure 6-7.
FIGURE 6-7: The shopping cart after selecting products.
Click the Remove button to remove a product from the shopping cart, or add more quantity of a product to change the value shown in the shopping cart. Congratulations! You’ve just created a simple shopping cart!