PHP

Authenticating Users

Example 10-4 shows the order.1 script that is used for logging into the winestore application. The script is based on Example 9-8 and Example 9-9 from Chapter 9. If the user isn't logged in-which should always be the case unless the script is unexpectedly called-and no credentials have been provided from a previous login attempt, the script displays a login <form> to the user. When the user successfully logs in, the script redirects to the calling page that's stored in the session variable referer; if referer isn't set, it redirects to the home page.

When the user provides credentials-a username and a password-the script is re-requested through the <form> submission process. The script encrypts the password provided by the user and checks if this matches the password stored in the users table. If it matches, the user is logged in by registering the session variable loginUsername and unregistering any session variables associated with failed attempts to update customer details. The session variable loginUsername stores the user's email address, which, as discussed earlier, is the same as his username. If the password is incorrect, an error is generated, and the login <form> is redisplayed so the user can try again.

The framework used here is typical of authentication in a web database application. However, possible improvements to the process can include limiting the number of failed login attempts, a password changing feature, a password reminder module-where the user is sent a password hint such as "What is your mother's maiden name?"-and security restrictions such as requiring that a password contain a mixture of uppercase, lowercase, numeric, and special characters.

Example 10-4. The order.1 login script for logging into the winestore application
<?php
// This script manages the login process.
// It should only be called when the user is not
// logged in.
// If the user is logged in, it will redirect back
// to the calling page.
// If the user is not logged in, it will show a login
// <form>
include 'include.inc';
set_error_handler("errorHandler");
function check_login($loginUsername, $loginPassword)
{
  global $referer;
  global $username;
  global $password;
  global $hostName;
  global $databaseName;
  global $message;
  // Get the two character salt from the
  // user-name collected from the challenge
  $salt = substr($loginUsername, 0, 2);
  // Encrypt the loginPassword collected from
  // the challenge
  $crypted_password = crypt($loginPassword, $salt);
  // Formulate the SQL find the user
  $query = "SELECT password FROM users
               WHERE user_name = '$loginUsername'
               AND password = '$crypted_password'";
  // Open a connection to the DBMS
  if (!($connection = @ mysql_pconnect($hostName,
                                      $username,
                                      $password)))
     showerror(  );
  if (!mysql_select_db($databaseName, $connection))
     showerror(  );
  // Execute the query
  if (!($result = @ mysql_query($query, $connection)))
     showerror(  );
  // exactly one row? then we have found the user
  if (mysql_num_rows($result) == 1)
  {
     // Register the loginUsername to show the user
     // is logged in
     session_register("loginUsername");
     // Clear any other session variables
     if (session_is_registered("errors"))
        // Delete the form errors session variable
        session_unregister("errors");
     if (session_is_registered("formVars"))
        // Delete the formVars session variable
        session_unregister("formVars");
     // Do we need to redirect to a calling page?
     if (session_is_registered("referer"))
     {
        // Delete the referer session variable
        session_unregister("referer");
        // Then, use it to redirect
        header("Location: $referer");
        exit;
     }
     else
     {
        header("Location: example.cart.1.php");
        exit;
     }
  }
  else
  {
     // Ensure loginUsername is not registered, so
     // the user is not logged in
     if (session_is_registered("loginUsername"))
        session_unregister("loginUsername");
     // Register an error message
     session_register("message");
     $message = "Username or password incorrect. " .
                "Login failed.";
     // Show the login page
     // so the user can have another go!
     login_page(  );
     exit;
  }
}
// Function that shows the HTML <form> that is
// used to collect the username and password
function login_page(  )
{
  global $message;
  ?>
<!DOCTYPE HTML PUBLIC
    "-//W3C//DTD HTML 4.0 Transitional//EN"
    "http://www.w3.org/TR/html4/loose.dtd" >
<html>
  <head>
     <title>Winestore Login Page</title>
  </head>
<body bgcolor="white">
<?php
  // Show login status (should be logged out!)
  showLogin(  );
?>
    <h2>Winestore Login Page</h2>
    <form method="POST" action="example.order.1.php">
<?php
  // Show messages
  showMessage(  );
  ?>
<table>
<tr>
    <td>Enter your username:</td>
    <td><input type="text" size=15
         maxlength=30
         name="loginUsername"></td>
</tr>
<tr><td>Enter your password:</td>
    <td><input type="password" size=15
         maxlength=8
         name="loginPassword"></td>
</tr>
<tr>
    <td><input type="submit" value="Log in"></td>
</tr>
</table>
<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>
</form>
</body>
</html>
<?php
}
// ------------------
// Initialise the session
session_start(  );
if (isset($HTTP_POST_VARS["loginUsername"]))
   $loginUsername =
      clean($HTTP_POST_VARS["loginUsername"], 30);
if (isset($HTTP_POST_VARS["loginPassword"]))
   $loginPassword =
      clean($HTTP_POST_VARS["loginPassword"], 8);
// Check if the user is already logged in
if (session_is_registered("loginUsername"))
{
  // If they are, then just bounce them back where
  // they came from
  if (session_is_registered("referer"))
  {
     session_unregister("referer");
     header("Location: $referer");
     exit;
  }
  else
  {
     header("Location: example.cart.1.php");
     exit;
  }
}
// Have they provided only one of a username and
// password?
if ((empty($HTTP_POST_VARS["loginUsername"]) &&
    !empty($HTTP_POST_VARS["loginPassword"])) ||
    (!empty($HTTP_POST_VARS["loginUsername"]) &&
    empty($HTTP_POST_VARS["loginPassword"])))
{
     // Register an error message
     session_register("message");
     $message = "Both a username and password must " .
                "be supplied.";
}
// Have they not provided a username/password,
// or was there an error?
if (!isset($loginUsername) ||
    !isset($loginPassword) ||
     session_is_registered("message"))
  login_page(  );
else
  // They have provided a login. Is it valid?
  check_login($loginUsername, $loginPassword);
?>

Example 10-5 lists the winestore order.2 logout script. The script is simple: if the session variable loginUsername is registered-this variable indicates the user is logged in-it's unregistered; if it isn't registered, the script has been unexpectedly called, and an error message is generated. In either case, the script then redirects back to the calling page stored in the session variable referer, or to the home page if referer isn't set. The script is a one-component script; that is, it carries out a function, produces no output, and redirects back to the calling page.

Example 10-5. The order.2 logout script for logging out of the winestore application
<?php
  // This script logs a user out and redirects
  // to the calling page.
  include 'include.inc';
  set_error_handler("errorHandler");
  // Restore the session
  session_start(  );
  // Is the user logged in?
  if (session_is_registered("loginUsername"))
     session_unregister("loginUsername");
  else
  {
     // Register a message to show the user
     session_register("message");
     $message = "Error: you are not logged in!";
  }
  // Redirect the browser back to the calling page
  if (session_is_registered("referer"))
  {
     // Delete the redirection session variable
     session_unregister("referer");
     // Then, use it to redirect to the calling page
     header("Location: $referer");
     exit;
  }
  else
     header("Location: example.cart.1.php");
?>