10.2. Customer ManagementIn this section, we outline the customer management scripts customer.1, customer.2, and customer.3. The customer.2 script is for data entry of customer details and reporting errors and is based on the customer <form> case study from Chapter 6 and Chapter 8. The customer.1 script performs data validation and writes the customer details to the winestore database. It is also based on the case study examples from Chapter 6 and Chapter 8. The customer.3 receipt is designed to avoid the reload problem after writing to the database. 10.2.1. Customer ValidationExample 10-1 lists the customer.1 script. It is based on Example 8-4 and has the same structure with two exceptions:
The validation techniques used for the additional fields—such as the telephone and fax numbers, email address, zip code, and so on—are discussed in Chapter 7. Example 10-1. The complete winestore customer validation script, customer.2<?php // This script validates customer data entered into // example.customer.2.php. // If validation succeeds, it INSERTs or UPDATEs // a customer and redirect to a receipt page; if it // fails, it creates error messages and these are later // displayed by example.customer.2.php. include 'include.inc'; set_error_handler("errorHandler"); // Initialize a session session_start( ); // Register an error array - just in case! if (!session_is_registered("errors")) session_register("errors"); // Clear any errors that might have been // found previously $errors = array( ); // Set up a $formVars array with the POST variables // and register with the session. if (!session_is_registered("formVars")) session_register("formVars"); foreach($HTTP_POST_VARS as $varname => $value) $formVars[$varname] = trim(clean($value, 50)); // Validate the firstName if (empty($formVars["firstName"])) // First name cannot be a null string $errors["firstName"] = "The first name field cannot be blank."; elseif (!eregi("^[a-z'-]*$", $formVars["firstName"])) // First name cannot contain white space $errors["firstName"] = "The first name can only contain alphabetic " . "characters or \"-\" or \"'\""; elseif (strlen($formVars["firstName"]) > 50) $errors["firstName"] = "The first name can be no longer than 50 " . "characters"; // Validate the Surname if (empty($formVars["surname"])) // the user's surname cannot be a null string $errors["surname"] = "The surname field cannot be blank."; elseif (strlen($formVars["surname"]) > 50) $errors["surname"] = "The surname can be no longer than 50 " . "characters"; // Validate the Address if (empty($formVars["address1"]) && empty($formVars["address2"]) && empty($formVars["address3"])) // all the fields of the address cannot be null $errors["address"] = "You must supply at least one address line."; else { if (strlen($formVars["address1"]) > 50) $errors["address1"] = "The address line 1 can be no longer " . "than 50 characters"; if (strlen($formVars["address2"]) > 50) $errors["address2"] = "The address line 2 can be no longer " . "than 50 characters"; if (strlen($formVars["address3"]) > 50) $errors["address3"] = "The address line 3 can be no longer " . "than 50 characters"; } // Validate the user's Initial if (!empty($formVars["initial"]) && !eregi("^[a-z]{1}$", $formVars["initial"])) // If there is a middle initial, it must be // one character in length $errors["initial"] = "The initial field must be empty or one " . "character in length."; // Validate the City if (empty($formVars["city"])) // the user's city cannot be a null string $errors["city"] = "You must supply a city."; elseif (strlen($formVars["city"]) > 20) $errors["city"] = "The city can be no longer than 20 characters"; // Validate State - any string less than 21 characters if (strlen($formVars["state"]) > 20) $errors["state"] = "The state can be no longer than 20 characters"; // Validate Zipcode if (!ereg("^([0-9]{4,5})$", $formVars["zipcode"])) $errors["zipcode"] = "The zipcode must be 4 or 5 digits in length"; // Validate Country if (strlen($formVars["country"]) > 20) $errors["country"] = "The country can be no longer than 20 characters"; // Phone is optional, but if it is entered it must have // correct format $validPhoneExpr = "^([0-9]{2,3}[ ]?)?[0-9]{4}[ ]?[0-9]{4}$"; if (!empty($formVars["phone"]) && !ereg($validPhoneExpr, $formVars["phone"])) $errors["phone"] = "The phone number must be 8 digits in length, " . "with an optional 2 or 3 digit area code"; // Fax is optional, but if it is entered it must // have correct format if (!empty($formVars["fax"]) && !ereg($validPhoneExpr, $formVars["fax"])) $errors["fax"] = "The fax number must be 8 digits in length, with " . "an optional 2 or 3 digit area code"; // Validate Date of Birth if (empty($formVars["dob"])) // the user's date of birth cannot be a null string $errors["dob"] = "You must supply a date of birth."; elseif (!ereg("^([0-9]{2})/([0-9]{2})/([0-9]{4})$", $formVars["dob"], $parts)) // Check the format $errors["dob"] = "The date of birth is not a valid date in the " . "format DD/MM/YYYY"; elseif (!checkdate($parts[2],$parts[1],$parts[3])) $errors["dob"] = "The date of birth is invalid. Please check " . "that the month is between 1 and 12, and the " . "day is valid for that month."; elseif (intval($parts[3]) < 1890) // Make sure that the user has a reasonable birth year $errors["dob"] = "You must be alive to use this service!"; elseif // Check whether the user is 18 years old. // If all the following are NOT true, then report // an error. // Were they born more than 19 years ago? (!((intval($parts[3]) < (intval(date("Y") - 19))) || // No, so were they born exactly 18 years ago, and // has the month they were born in passed? (intval($parts[3]) == (intval(date("Y")) - 18) && (intval($parts[2]) < intval(date("m")))) || // No, so were they born exactly 18 years ago in this // month, and was the day today or earlier in the month? (intval($parts[3]) == (intval(date("Y")) - 18) && (intval($parts[2]) == intval(date("m"))) && (intval($parts[1]) <= intval(date("d")))))) $errors["dob"] = "You must be 18+ years of age to use this ". "service."; // Only validate email if this is an INSERT if (!session_is_registered("loginUsername")) { // Check syntax $validEmailExpr = "^[0-9a-z~`!#$%&_-]([.]?[0-9a-z~!#$%&_-])*" . "@[0-9a-z~!#$%&_-]([.]?[0-9a-z~!#$%&_-])*$"; if (empty($formVars["email"])) // the user's email cannot be a null string $errors["email"] = "You must supply an email address."; elseif (!eregi($validEmailExpr, $formVars["email"])) // The email must match the above regular // expression $errors["email"] = "The email address must be in the " . "name@domain format."; elseif (strlen($formVars["email"]) > 50) // The length cannot exceed 50 characters $errors["email"] = "The email address can be no longer than " . "50 characters."; elseif (!(getmxrr(substr(strstr($formVars["email"], '@'), 1), $temp)) || checkdnsrr(gethostbyname( substr(strstr($formVars["email"], '@'), 1)),"ANY")) // There must be a Domain Name Server (DNS) // record for the domain name $errors["email"] = "The domain does not exist."; else { // Check if the email address is already in use in // the winestore if (!($connection = @ mysql_pconnect($hostName, $username, $password))) showerror( ); if (!mysql_select_db($databaseName, $connection)) showerror( ); $query = "SELECT * FROM users WHERE user_name = '" . $formVars["email"] . "'"; if (!($result = @ mysql_query ($query, $connection))) showerror( ); // Is it taken? if (mysql_num_rows($result) == 1) $errors["email"] = "A customer already exists with this " . "login name."; } } // Only validate password if this is an INSERT // Validate password - between 6 and 8 characters if (!session_is_registered("loginUsername") && (strlen($formVars["loginPassword"]) < 6 || strlen($formVars["loginPassword"] > 8))) $errors["loginPassword"] = "The password must be between 6 and 8 " . "characters in length"; // Now the script has finished the validation, // check if there were any errors if (count($errors) > 0) { // There are errors. Relocate back to the // customer <form> header("Location: example.customer.2.php"); exit; } // If we made it here, then the data is valid if (!isset($connection)) { if (!($connection = @ mysql_pconnect($hostName, $username, $password))) showerror( ); if (!mysql_select_db($databaseName, $connection)) showerror( ); } // Reassemble the date of birth into database format $dob = "\"$parts[3]-$parts[2]-$parts[1]\""; // Is this an update? if (session_is_registered("loginUsername")) { $custID = getCustomerID($loginUsername, $connection); $query = "UPDATE customer SET ". "title = \"" . $formVars["title"] . "\", " . "surname = \"" . $formVars["surname"] . "\", " . "firstname = \"" . $formVars["firstName"] . "\", " . "initial = \"" . $formVars["initial"] . "\", " . "addressline1 = \"" . $formVars["address1"] . "\", " . "addressline2 = \"" . $formVars["address2"] . "\", " . "addressline3 = \"" . $formVars["address3"] . "\", " . "city = \"" . $formVars["city"] . "\", " . "state = \"" . $formVars["state"] . "\", " . "zipcode = \"" . $formVars["zipcode"] . "\", " . "country = \"" . $formVars["country"]. "\", " . "phone = \"" . $formVars["phone"] . "\", " . "fax = \"" . $formVars["fax"] . "\", " . "birth_date = " . $dob . " WHERE cust_id = $custID"; } else $query = "INSERT INTO customer VALUES (NULL, " . "\"" . $formVars["surname"] . "\", " . "\"" . $formVars["firstName"] . "\", " . "\"" . $formVars["initial"] . "\", " . "\"" . $formVars["title"] . "\", " . "\"" . $formVars["address1"] . "\", " . "\"" . $formVars["address2"] . "\", " . "\"" . $formVars["address3"] . "\", " . "\"" . $formVars["city"] . "\", " . "\"" . $formVars["state"] . "\", " . "\"" . $formVars["zipcode"] . "\", " . "\"" . $formVars["country"] . "\", " . "\"" . $formVars["phone"] . "\", " . "\"" . $formVars["fax"] . "\", " . "\"" . $formVars["email"] . "\", " . $dob . ", " . 0 . ")"; // Run the query on the customer table if (!(@ mysql_query ($query, $connection))) showerror( ); // If this was an INSERT, we need to INSERT // also into the users table if (!session_is_registered("loginUsername")) { // Get the customer id that was created $custID = @ mysql_insert_id($connection); // Use the first two characters of the // email as a salt for the password $salt = substr($formVars["email"], 0, 2); // Create the encrypted password $stored_password = crypt($formVars["loginPassword"], $salt); // Insert a new user into the user table $query = "INSERT INTO users SET cust_id = $custID, password = '$stored_password', user_name = '" . $formVars["email"] . "'"; if (!($result = @ mysql_query ($query, $connection))) showerror( ); // Log the user into their new account session_register("loginUsername"); $loginUsername = $formVars["email"]; } // Clear the formVars so a future <form> is blank session_unregister("formVars"); session_unregister("errors"); // Now show the customer receipt header("Location: example.customer.3.php?custID=$custID"); ?> The following fragment of Example 10-1 manages the creation of a new user account but only if this is a new customer: if (!session_is_registered("loginUsername")) { // Get the customer id that was created $custID = @ mysql_insert_id($connection); // Use the first two characters of the // email as a salt for the password $salt = substr($formVars["email"], 0, 2); // Create the encrypted password $stored_password = crypt($formVars["loginPassword"], $salt); // Insert a new user into the user table $query = "INSERT INTO users SET cust_id = $custID, password = '$stored_password', user_name = '" . $formVars["email"] . "'"; if (!($result = @ mysql_query ($query, $connection))) showerror( ); // Log the user into their new account session_register("loginUsername"); $loginUsername = $formVars["email"]; } The session variable loginUsername indicates whether or not the user is logged in. Therefore, the fragment adds a new row to the users table only if the user isn't logged in. To store the password, the techniques from Chapter 9 are applied, and the password is encrypted using crypt( ) with the first two characters of the email address as the seed. After adding the row, the user is logged in by registering the session variable loginUsername and assigning the email address value to it. For updates of customer details, the external function getCustomerID( ) is called prior to updating the row. The function returns the customer cust_id associated with the loginUsername session variable passed as a parameter. The function is defined in the include.inc file. If validation fails in Example 10-1, the script redirects to the customer.2 script shown in Example 10-2. Any validation error messages are recorded in the array errors and this array is used to display the messages interleaved with the customer <form> widgets. If validation and the database write succeed, the script redirects to the customer.3 script shown in Example 10-3. 10.2.2. The Customer <form>The script customer.2 is shown in Example 10-2. The script displays a <form> for customer data entry. If the user is logged in and validation has not previously failed, the customer data is retrieved from the customer table and used to populate the <form> widgets. If the user isn't logged in, and validation has not previously failed, a blank <form> is shown to collect new member details. If data has failed validation, the formVars array that is registered as a session variable is used to repopulate the <form>, and the error messages from the errors array are displayed. Two external functions from include.inc are used in Example 10-2:
The country widget has only three possible values: Australia, United States, and Zimbabwe, In a full implementation of our case study, a database table of country names would be maintained, and the function selectDistinct( ) would present the <select> list. The function selectDistinct( ) is discussed in Chapter 5. Example 10-2. The customer <form> script customer.1<?php // This script shows the user a customer <form>. // It can be used both for INSERTing a new customer and // for UPDATE-ing an existing customer. If the customer // is logged in, then it is an UPDATE; otherwise, an // INSERT. // The script also shows error messages above widgets // that contain erroneous data; errors are generated // by example.customer.1.php include 'include.inc'; set_error_handler("errorHandler"); // Show an error in a red font function fieldError($fieldName, $errors) { if (isset($errors[$fieldName])) echo "<font color=\"red\">" . $errors[$fieldName] . "</font><br>"; } // Connect to a session session_start( ); // Is the user logged in and were there no errors from // a previous validation? // If so, look up the customer for editing if (session_is_registered("loginUsername") && empty($errors)) { if (!($connection = @ mysql_pconnect($hostName, $username, $password))) showerror( ); if (!mysql_select_db($databaseName, $connection)) showerror( ); $custID = getCustomerID($loginUsername, $connection); $query = "SELECT * FROM customer WHERE cust_id = " . $custID; if (!($result = @ mysql_query($query, $connection))) showerror( ); $row = mysql_fetch_array($result); // Reset $formVars, since we're loading from // the customer table $formVars = array( ); // Reset the errors $errors = array( ); // Load all the form variables with customer data $formVars["title"] = $row["title"]; $formVars["surname"] = $row["surname"]; $formVars["firstName"] = $row["firstname"]; $formVars["initial"] = $row["initial"]; $formVars["address1"] = $row["addressline1"]; $formVars["address2"] = $row["addressline2"]; $formVars["address3"] = $row["addressline3"]; $formVars["city"] = $row["city"]; $formVars["state"] = $row["state"]; $formVars["zipcode"] = $row["zipcode"]; $formVars["country"] = $row["country"]; $formVars["phone"] = $row["phone"]; $formVars["fax"] = $row["fax"]; $formVars["email"] = $row["email"]; $formVars["dob"] = $row["birth_date"]; $formVars["dob"] = substr($formVars["dob"], 8, 2) . "/" . substr($formVars["dob"], 5, 2) . "/" . substr($formVars["dob"], 0, 4); } ?> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd" > <html> <head><title>Customer Details</title></head> <body bgcolor="white"> <?php // Show the user login status showLogin( ); ?> <form method="post" action="example.customer.1.php"> <h1>Customer Details</h1> <?php // Display any messages to the user showMessage( ); // Show meaningful instructions for UPDATE or INSERT if (session_is_registered("loginUsername")) echo "<h3>Please amend your details below as " . "required. Fields shown in " . "<font color=\"red\">red</font> are " . "mandatory.</h3>"; else echo "<h3>Please fill in the details below to " . "join. Fields shown in " . "<font color=\"red\">red</font> are ". "mandatory.</h3>"; ?> <table> <col span="1" align="right"> <tr><td><font color="red">Title:</font></td> <td><select name="title"> <option <?php if ($formVars["title"]=="Mr") echo "selected";?>>Mr <option <?php if ($formVars["title"]=="Mrs") echo "selected";?>>Mrs <option <?php if ($formVars["title"]=="Ms") echo "selected";?>>Ms <option <?php if ($formVars["title"]=="Dr") echo "selected";?>>Dr </select><br></td> </tr> <tr><td><font color="red">First name:</font></td> <td><? echo fieldError("firstName", $errors); ?> <input type="text" name="firstName" value="<? echo $formVars["firstName"]; ?>" size=50></td> </tr> <tr><td><font color="red">Surname:</font></td> <td><? echo fieldError("surname", $errors); ?> <input type="text" name="surname" value="<? echo $formVars["surname"]; ?>" size=50></td> </tr> <tr><td>Initial: </td> <td><? echo fieldError("initial", $errors); ?> <input type="text" name="initial" value="<? echo $formVars["initial"]; ?>" size=1></td> </tr> <tr><td><font color="red">Address:</font></td> <td><? echo fieldError("address", $errors); ?> <? echo fieldError("address1", $errors); ?> <input type="text" name="address1" value="<? echo $formVars["address1"]; ?>" size=50></td> </tr> <tr><td></td> <td><? echo fieldError("address2", $errors); ?> <input type="text" name="address2" value="<? echo $formVars["address2"]; ?>" size=50></td> </tr> <tr><td></td> <td><? echo fieldError("address3", $errors); ?> <input type="text" name="address3" value="<? echo $formVars["address3"]; ?>" size=50></td> </tr> <tr><td><font color="red">City:</font></td> <td><? echo fieldError("city", $errors); ?> <input type="text" name="city" value="<? echo $formVars["city"]; ?>" size=20></td> </tr> <tr><td>State: </td> <td><? echo fieldError("state", $errors); ?> <input type="text" name="state" value="<? echo $formVars["state"]; ?>" size=20></td> </tr> <tr><td><font color="red">Zipcode:</font></td> <td><? echo fieldError("zipcode", $errors); ?> <input type="text" name="zipcode" value="<? echo $formVars["zipcode"]; ?>" size=5></td> </tr> <tr><td>Country: </td> <td><? echo fieldError("country", $errors); ?> <select name="country"> <option <?php if ($formVars["country"]=="Australia") echo "selected";?>>Australia <option <?php if ($formVars["country"]=="United States") echo "selected";?>>United States <option <?php if ($formVars["country"]=="Zimbabwe") echo "selected";?>>Zimbabwe </select></td> </tr> <tr><td>Telephone: </td> <td><? echo fieldError("phone", $errors); ?> <input type="text" name="phone" value="<? echo $formVars["phone"]; ?>" size=15></td> </tr> <tr><td>Fax: </td> <td><? echo fieldError("fax", $errors); ?> <input type="text" name="fax" value="<? echo $formVars["fax"]; ?>" size=15></td> </tr> <tr><td><font color="red">Date of birth (dd/mm/yyyy):</font> </td> <td><? echo fieldError("dob", $errors); ?> <input type="text" name="dob" value="<? echo $formVars["dob"]; ?>" size=10></td> </tr> <?php // Only show the username/email and password // <input> widgets to new users if (!session_is_registered("loginUsername")) { ?> <tr><td><font color="red">Email/username:</font></td> <td><? echo fieldError("email", $errors); ?> <input type="text" name="email" value="<? echo $formVars["email"]; ?>" size=50></td> </tr> <tr><td><font color="red">Password:</font></td> <td><? echo fieldError("loginPassword", $errors); ?> <input type="password" name="loginPassword" value="<? echo $formVars["loginPassword"]; ?>" size=8></td> </tr> <?php } ?> <tr> <td><input type="submit" value="Submit"></td> </tr> </table> </form> <br><a href="http://validator.w3.org/check/referer"> <img src="http://www.w3.org/Icons/valid-html401" height="31" width="88" align="right" border="0" alt="Valid HTML 4.01!"></a> </body> </html> 10.2.3. The Customer Receipt PageExample 10-3 shows the customer receipt script, customer.3, that is called after a database write to insert or update a customer. The script is a receipt page that can be bookmarked—it expects a cust_id as a GET method parameter—and the script does nothing but read details from the database. Reloading of the page therefore has no undesirable side effects. Customer receipts can be viewed only when logged in, and a user is permitted to view only her own customer receipts; if the user attempts to retrieve another user's details, a warning message is shown to the user, and the cust_id is updated to be her own. Example 10-3. The customer.3 customer receipt page<?php // This script shows the user a receipt for their customer // UPDATE or INSERT. // It carries out no database actions and can be // bookmarked. The user must be logged in to view it. include 'include.inc'; set_error_handler("errorHandler"); // Show the user a customer INSERT or UPDATE receipt function show_HTML_receipt($custID, $connection) { $query = "SELECT * FROM customer WHERE cust_id = $custID"; if (!($result = @ mysql_query ($query, $connection))) showerror( ); // There is only one matching row $row = @ mysql_fetch_array($result); echo "\n<h1>Account details for " . "<font color=\"red\">" . $row["email"] . "</font></h1>\n"; echo "<p><i>Please record your password " . "somewhere safe for future use</i>\n"; echo "<p>Your shipping and billing details are " . "as follows:\n<br><b> " . $row["title"] . " " . $row["firstname"] . " " . $row["initial"] . " " . $row["surname"] . "\n<br>" . $row["addressline1"] . "\n"; if ($row["addressline2"] != "") echo "\n<br>" . $row["addressline2"]; if ($row["addressline3"] != "") echo "\n<br>" . $row["addressline3"]; echo "\n<br>" . $row["city"] . " " . $row["state"] . " " . $row["zipcode"] . "\n<br>" . $row["country"] . "</b><br>\n"; if ($row["phone"] != "") echo "\n<br><b>Telephone: " . $row["phone"] . "</b>"; if ($row["fax"] != "") echo "\n<br><b>Fax: " . $row["fax"] . "</b>"; $row["dob"] = substr($row["birth_date"], 8, 2) . "/" . substr($row["birth_date"], 5, 2) . "/" . substr($row["birth_date"], 0, 4); echo "\n<br><b>Date of Birth: " . $row["dob"] . "</b>\n<br>"; } // Main ---------- // Re-establish the existing session session_start( ); // Check if the user is logged in - this should never // fail unless the script is run incorrectly if (!session_is_registered("loginUsername")) { session_register("message"); $message = "You must login to view your " . "customer receipt."; header("Location: example.cart.1.php"); exit; } // Check the correct parameters have been passed if (!isset($custID)) { session_register("message"); $message = "Incorrect parameters to " . "example.customer.3.php"; // Redirect the browser back to the calling page, // using the HTTP response header "Location:" // and the PHP environment variable $HTTP_REFERER header("Location: $HTTP_REFERER"); exit; } // Check this customer matches the custID if ($custID != getCustomerID($loginUsername, NULL)) { session_register("message"); $message = "You can only view your own " . "customer receipt!"; $custID = getCustomerID($loginUsername, NULL); } // Open a connection to the DBMS if (!($connection = @ mysql_pconnect($hostName, $username, $password))) showerror( ); if (!mysql_select_db($databaseName, $connection)) showerror( ); ?> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html401/loose.dtd"> <html> <head> <title>Hugh and Dave's Online Wines</title> </head> <body bgcolor="white"> <?php // Show the user login status showLogin( ); // Show the user any messages showMessage( ); // Show the customer confirmation show_HTML_receipt($custID, $connection); // Show buttons echo "<form action=\"example.cart.5.php\"" . " method=\"GET\">"; echo "<table>"; echo "<td><input type=\"submit\" name=\"home\"" . " value=\"Home\"></td>"; ?> </table> </form> <br><a href="http://validator.w3.org/check/referer"><img src="http://www.w3.org/Icons/valid-html401" height="31" width="88" align="right" border="0" alt="Valid HTML 4.01!"></a> </body> </html> Copyright © 2003 O'Reilly & Associates. All rights reserved. |
|