10.3 Case Study: Using Sessions in Validation

In this section, we use sessions to improve the user interaction with the phonebook details form developed in Chapter 8. The improvements focus on the interaction when the form is submitted and fields fail validation. We modify the scripts to:

  • Display error messages interleaved with the phonebook's entry form widgets.

  • Use session variables to pass back the submitted fields to the form generation script, saving the user the trouble of re-keying the data to correct the errors.

10.3.1 Improving the Phonebook Details Form

We designed several phonebook scripts in Chapter 8. In Example 8-7, the form generated by the script collects values to create a new entry. The script shown in Example 8-9 performs simple server-side validation of the form data, and inserts a row in the phonebook table if there are no errors. We improve these scripts in this section, but the techniques we show you can be easily adapted to the other phonebook scripts or to any form pages you've authored.

If validation fails, the script shown in Example 8-9 generates a page to display the errors to the user, and the user then follows a hypertext link back to the phonebook entry form to reenter the fields. The solution provided by Example 8-7 and Example 8-9 has three problems:

  • The user is forced to reenter the entire phonebook entry form from scratch when an error is encountered during validation

  • Example 8-9 displays all the errors in a stand-alone page with no connection to the form page, so the user cannot easily see the relation between errors and the original input fields.

  • The error page generated by Example 8-9 isn't safe from the reload problem described in Chapter 8.

In this section we develop scripts that make use of session variables to solve these problems. Rather than displaying the error messages on a page generated by the validation script, we show you how to display the errors in red above the appropriate input fields on the data entry form, as shown in Figure 10-3 (the red text appears as a light gray in the figure).

Figure 10-3. The phonebook entry form showing error messages
figs/wda2_1003.gif


Figure 10-4 shows how the improved form and the validate scripts interact with session management to communicate errors and submitted fields.

Figure 10-4. Phonebook entry form and validation
figs/wda2_1004.gif


Because the validation script processes the fields collected in the phonebook form and generates any associated errors, we look at the changes required for that script first.

10.3.2 The Validation Script

We begin the improvements to the validation script with the changes required to support an error message session variable and then discuss how to record the values to pass back to the phonebook entry form generation code. We then show you the complete structure of the modified validation script.

10.3.2.1 Improving error messages

The validation script checks each variable submitted from the phonebook form to make sure data has been entered. The script shown in Example 8-9 builds up a template by adding blocks as errors are found. In the modified script we use in this case study, an associative array is registered instead to hold error messages associated with each field, providing greater flexibility when displaying the error messages.

First, we need to initialize the session with a call to session_start( ) and set up $errors to hold an array of errors:

// Initialize a session

session_start( );

  

// Set-up an empty $errors array to hold errors

$errors = array( );

The script then checks each variable and adds an error message to the associative array $errors if an error is encountered. The error message array is indexed by the name of the field being checked. For example, the validation of the surname is coded as:

// Validate the Surname

if (empty($surname))

    $errors["surname"] = "The surname field cannot be blank.";

Once all the fields have been validated, the size of the $errors array is tested to determine if any errors were encountered. If the size of the array is zero, we create or update the row as before, otherwise we carry out several steps as shown in the following fragment:

// Now the script has finished the validation, check if

// there were any errors

if (count($errors))

{

  // Set up a $lastformVars array to store the previously-entered data

  $lastformVars = array( );

  $lastFormVars["surname"] = $surname;

  $lastFormVars["firstname"] = $firstname;

  $lastFormVars["phone"] = $phone;



  // Save the array as a session variable

  $_SESSION["lastFormVars"] = $lastFormVars;



  // Store the $errors array as a session variable

  $_SESSION["errors"] = $errors;



  //  Relocate to the phonebook form

  header("Location: example.10-5.php");

  exit;

}

The setup and use of the lastFormVars array is discussed in the next section. The remainder of the fragment saves the $errors array as a session variable and relocates to the phonebook entry form script.

In Example 8-9, the script itself displays any errors, and because the request contains variables in a POST method request, the error page suffers from the reload problem discussed in Chapter 8. The script has to display the errors immediately, in isolation, because without sessions there is no convenient way to save the errors and retrieve them again when displaying the form. In the validation script developed here, we relocate to the phonebook entry form (shown later in Example 10-5) and let it display the errors held in the session variable $_SESSION["errors"].

10.3.2.2 Saving last-entered values as a session variable

We now show you how to pass the field data from the validation script back to the phonebook entry form, so the user does not have to re-key data after an error occurs. The fields are passed back the session array variable lastFormVars.

The following code fragment saves each value entered into the form into a $lastFormVars array, indexed by the name of the variable. The $lastFormVars array is then saved as the session variable $_SESSION["lastFormVars"].

// Set up a $lastformVars array to store the previously-entered data

$lastformVars = array( );

$lastFormVars["surname"] = $surname;

$lastFormVars["firstname"] = $firstname;

$lastFormVars["phone"] = $phone;



// Save the array as a session variable

$_SESSION["lastFormVars"] = $lastFormVars;

When the modified form is run, the most recent values entered from the session variable $_SESSION["lastFormVars"] are shown.

The final change needed is to destroy the session when the script successfully saves a row in the phonebook table:

// Destroy the session 

session_destroy( );

However, your application may make use of the session for other purposes and you may not want to destroy the session at this point. If this is the case then you should unset the variables used in these scripts.

// Clean up the lastFormVars from the session store

unset($_SESSION["lastFormVars"]);

10.3.2.3 The final validation script

Example 10-4 shows the final validation script derived from Example 8-9.

Example 10-4. The complete validation script derived from Example 8-9
<?php

require 'db.inc';



if (!($connection = @ mysql_pconnect("localhost", "fred", "shhh")))

   die("Could not connect to database");



$firstname = mysqlclean($_POST, "firstname", 50, $connection);

$surname = mysqlclean($_POST, "surname", 50, $connection);

$phone = mysqlclean($_POST, "phone", 20, $connection);



// Initialize a session

session_start( );



// Set-up an empty $errors array to hold errors

$errors = array( );



// Validate the Firstname

if (empty($firstname))

  $errors["firstname"] = "The firstname field cannot be blank.";



// Validate the Surname

if (empty($surname))

  $errors["surname"] = "The surname field cannot be blank.";



// Validate the Phone number. It must have the correct format

$validPhoneExpr = "^([0-9]{2,3}[ ]?)?[0-9]{4}[ ]?[0-9]{4}$";



if (empty($phone) || !ereg($validPhoneExpr, $phone))

  $errors["phone"] = "The phone number must be 8 digits in length,.

                       with an optional 2 or 3 digit area code";



// Now the script has finished the validation, check if

// there were any errors

if (count($errors))

{

  // Set up a $lastformVars array to store

  // the previously-entered data

  $lastformVars = array( );

  $lastFormVars["surname"] = $surname;

  $lastFormVars["firstname"] = $firstname;

  $lastFormVars["phone"] = $phone;



  // Save the array as a session variable

  $_SESSION["lastFormVars"] = $lastFormVars;



  // Store the $errors array as a session variable

  $_SESSION["errors"] = $errors;



  //  Relocate to the phonebook form

  header("Location: example.10-5.php");

  exit;

}



// If we made it here, then the data is valid

if (!mysql_select_db("telephone", $connection))

  showerror( );



// Insert the new phonebook entry

$query = "INSERT INTO phonebook VALUES

          (NULL, '{$surname}', '{$firstname}', '{$phone}')";



if (!(@ mysql_query ($query, $connection)))

   showerror( );



// Find out the phonebook_id of the new entry

$phonebook_id = mysql_insert_id( );



// Destroy the session

session_destroy( );



// Show the phonebook receipt

header("Location: example.8-5.php?status=T&phonebook_id={$phonebook_id}");

?>

10.3.3 The Phonebook Entry Form Script

Now let's turn to the changes required for the script that generates the phonebook entry form shown in Example 8-7. In the last section, we set up two session variables: $_SESSION["errors"] to hold an associative array of error messages found by the validation script, and $_SESSION["lastFormVars"] to hold an associative array filled with the form values. Both session variables are read and incorporated into a new form in this section.

10.3.3.1 Displaying previously entered form values

In our update phonebook details form in Example 8-11, we read data from the phonebook table and display it in the input widgets so that the user can amend it. The form uses the array $row to populate the data entry fields from a phonebook row when editing an existing entry in the database. In this section, we adapt this approach to displaying previously-entered data that has failed validation.

Adapting the approach from Example 8-11 to our sessions-based script is straightforward. Consider the following fragment:

$row = array( );



// Has previous data been entered?

// If so, initialize $row from $_SESSION["lastFormVars"]

if (isset($_SESSION["lastFormVars"]))

{

  $row = $_SESSION["lastFormVars"];

  $template->setVariable("MESSAGE",

                         "Please correct the errors shown below");

  $template->setVariable("SUBMITVALUE", "Try again");

}

If the $_SESSION["lastFormVars"] variable is set, $row is set to $_SESSION["lastFormVars"], and a message and submit button value set to inform the user that errors have occurred. Then, for each widget in the form, the script displays the value the user previously entered (or an empty widget if no previous value was supplied):

if (!empty($row))

  $template->setVariable("MINPUTVALUE", $row["firstname"]);

else

  $template->setVariable("MINPUTVALUE", "");

10.3.3.2 Displaying error messages

To display the error messages above the input widgets, we've modified our phonebook template; the phonebook template is discussed in more detail in Chapter 8. It now includes the following fragment:

<!-- BEGIN mandatoryinput -->

<tr>

<!-- BEGIN mandatoryerror -->

  <td>

  <td><font color="red">{MINPUTERROR}</font>

</tr>

<tr>

<!-- END mandatoryerror -->

  <td><font color="red">{MINPUTTEXT}:</font></td>

  <td>

  <input type="text" name="{MINPUTNAME}" value="{MINPUTVALUE}"

         size={MINPUTSIZE}>

  </td>

</tr>

<!-- END mandatoryinput -->

The mandatoryerror block is an optional block that's included before the input element and is used to show an error message in a red font using the placeholder MINPUTERROR. If no error occurs, we don't set MINPUTERROR and don't use the mandatoryerror block.

To decide whether to display an error message or not, we check the contents of the $_SESSION["errors"] array. If there's an entry for the input name in the associative array of error messages, we use the mandatoryerror block and display the message. Here's an example for the firstname element:

if (!empty($_SESSION["errors"]["firstname"]))

{

  $template->setCurrentBlock("mandatoryerror");

  $template->setVariable("MINPUTERROR", $_SESSION["errors"]["firstname"]);

  $template->parseCurrentBlock("mandatoryerror");

}

Figure 10-4 shows the final results: a form with error messages placed over the corresponding fields.

10.3.3.3 The final phonebook entry script

Example 10-5 shows the complete data entry script, derived from Example 8-7, that displays the previous form values and the error messages held in session variables. Example 10-6 shows the template.

Example 10-5. Phonebook entry form derived from Example 8-7
<?php

require 'db.inc';

require_once "HTML/Template/ITX.php";



if (!($connection = @ mysql_connect("localhost", "fred", "shhh")))

   die("Could not connect to database");



session_start( );



$template = new HTML_Template_ITX("./templates");

$template->loadTemplatefile("example.10-6.tpl", true, true);



$row = array( );



// Has previous data been entered?

// If so, initialize $row from $_SESSION["lastFormVars"]

if (isset($_SESSION["lastFormVars"]))

{

  $row = $_SESSION["lastFormVars"];

  $template->setVariable("MESSAGE",

                         "Please correct the errors shown below");

  $template->setVariable("SUBMITVALUE", "Try again");

}

else

{

  // If they're not correcting an error show a

  // "fill in the details" message

  $template->setVariable("MESSAGE",

                      "Please fill in the details below to add an entry");

  $template->setVariable("SUBMITVALUE", "Add Now!");

}



$template->setCurrentBlock("mandatoryinput");

$template->setVariable("MINPUTTEXT", "First name");

$template->setVariable("MINPUTNAME", "firstname");

if (!empty($row))

  $template->setVariable("MINPUTVALUE", $row["firstname"]);

else

  $template->setVariable("MINPUTVALUE", "");

if (!empty($_SESSION["errors"]["firstname"]))

{

  $template->setCurrentBlock("mandatoryerror");

  $template->setVariable("MINPUTERROR", $_SESSION["errors"]["firstname"]);

  $template->parseCurrentBlock("mandatoryerror");

}

$template->setCurrentBlock("mandatoryinput");

$template->setVariable("MINPUTSIZE", 50);

$template->parseCurrentBlock("mandatoryinput");



$template->setCurrentBlock("mandatoryinput");

$template->setVariable("MINPUTTEXT", "Surname");

$template->setVariable("MINPUTNAME", "surname");

if (!empty($row))

  $template->setVariable("MINPUTVALUE", $row["surname"]);

else

  $template->setVariable("MINPUTVALUE", "");

if (!empty($_SESSION["errors"]["surname"]))

{

  $template->setCurrentBlock("mandatoryerror");

  $template->setVariable("MINPUTERROR", $_SESSION["errors"]["surname"]);

  $template->parseCurrentBlock("mandatoryerror");

}

$template->setCurrentBlock("mandatoryinput");

$template->setVariable("MINPUTSIZE", 50);

$template->parseCurrentBlock("mandatoryinput");



$template->setCurrentBlock("mandatoryinput");

$template->setVariable("MINPUTTEXT", "Phone");

$template->setVariable("MINPUTNAME", "phone");

if (!empty($row))

  $template->setVariable("MINPUTVALUE", $row["phone"]);

else

  $template->setVariable("MINPUTVALUE", "");

if (!empty($_SESSION["errors"]["phone"]))

{

  $template->setCurrentBlock("mandatoryerror");

  $template->setVariable("MINPUTERROR", $_SESSION["errors"]["phone"]);

  $template->parseCurrentBlock("mandatoryerror");

}

$template->setCurrentBlock("mandatoryinput");

$template->setVariable("MINPUTSIZE", 20);

$template->parseCurrentBlock("mandatoryinput");



$template->setCurrentBlock( );

$template->parseCurrentBlock( );

$template->show( );

?>

Example 10-6. The template to display the phonebook form
<!DOCTYPE HTML PUBLIC

                 "-//W3C//DTD HTML 4.01 Transitional//EN"

                 "http://www.w3.org/TR/html401/loose.dtd">

<html>

<head>

  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">

  <title>Phonebook Details</title>

</head>

<body bgcolor="white">

<form method="post" action="example.10-4.php">

<h1>Phonebook Details</h1>

<h2>{MESSAGE}.

    Fields shown in <font color="red">red</font> are mandatory.</h2>

<table>

<!-- BEGIN mandatoryinput -->

<tr>

<!-- BEGIN mandatoryerror -->

  <td>

  <td><font color="red">{MINPUTERROR}</font>

</tr>

<tr>

<!-- END mandatoryerror -->

  <td><font color="red">{MINPUTTEXT}:</font></td>

  <td>

  <input type="text" name="{MINPUTNAME}" value="{MINPUTVALUE}"

         size={MINPUTSIZE}>

  </td>

</tr>

<!-- END mandatoryinput -->

<tr>

   <td><input type="submit" value="{SUBMITVALUE}"></td>

</tr>

</table>

</form>

</body>

</html>



     
    ASPTreeView.com
     
    Evaluation has ВµЅУФ»БёЅexpired.
    Info...