PHP

Customer Management

In 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.

Customer Validation

Example 10-1 lists the customer.1 script. It is based on Example 8-4 and has the same structure with two exceptions:

  • It validates a superset of customer fields, that is, all the fields listed in Chapter 1.

  • It manages the encryption of passwords and user account allocation.

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.