Form Processing

Contact Us or call 1-877-932-8228
Form Processing

Form Processing

Processing forms generally involves the following tasks:

  1. Writing the HTML code to output the form.
  2. Writing validation code to validate the form entries after the form is submitted.
  3. Writing code to output errors if there are any.
  4. Writing code to process the form entries if they are all valid.

Although these tasks are all separate, some are dependent on others. For example, if errors are found when the form is submitted, it is nice to re-output the form, but the HTML code may be different from the original form as you will likely want to include error messages and also echo the values that the user entered. It's very easy to get your code all tangled up resulting in what is known as spaghetti code. We will now examine one approach for organizing code using functions and includes to make it easier to maintain.

Code Organization

Application Flow

The application we are building works like this:

  1. When the user first visits, she is presented with a form to fill out.
  2. If she fills out the form...
    • Correctly
      • She is presented with another form to confirm her entries.
      • After confirming her entries, the data will be processed (e.g, entered into a database or emailed to someone).
    • Incorrectly
      • She is presented with the same form with her entries in tact and appropriate error messages displayed.

Application Files

To make our code easier to maintain, we will organize it as follows:

  1. Includes/init.php - Initializes and sets some variables.
  2. AddEmployee.php - Contains code that defines the flow of the application.
  3. Includes/EmployeeForm.php - Contains code to display entry form.
  4. Includes/ProcessEmployee.php - Contains code to process the original form entry. If there are errors, they will be displayed on the page. If there are no errors, the user's entries will be displayed with a "Confirm" button.
  5. Includes/InsertEmployee.php - Contains code to insert the employee into a database. (This file is currently empty.)
  6. Includes/fnFormPresentation.php - Contains a library of functions for presenting form fields.
  7. Includes/fnFormValidation.php - Contains a library of functions for validating form entries.
  8. Includes/fnStrings.php - Contains a couple of useful string functions.
  9. Includes/fnDates.php - Contains a useful date function.

We will examine each of these files.

Code Sample:

ReusingCode/Demos/Includes/init.php
<?php
	$showForm = true;

	$mgrEntries = array();
	$mgrEntries[1]='Nancy Davolio';
	$mgrEntries[2]='Andrew Fuller';
	$mgrEntries[3]='Janet Leverling';
	$mgrEntries[4]='Margaret Peacock';
	$mgrEntries[5]='Steven Buchanan';
	$mgrEntries[6]='Michael Suyama';
	$mgrEntries[7]='Robert King';
	$mgrEntries[8]='Laura Callahan';
	$mgrEntries[9]='Anne Dodsworth';

	$errors = array();
	$dbEntries = array(	'FirstName'=>',
						'LastName'=>',
						'Email'=>',
						'Title'=>',
						'TitleOfCourtesy'=>',
						'Address'=>',
						'City'=>',
						'Region'=>',
						'PostalCode'=>',
						'Country'=>',
						'HomePhone'=>',
						'Extension'=>',
						'Notes'=>',
						'ReportsTo'=>',
						'Password'=>',
						'Email'=>',
						'BirthMonth'=>1,
						'BirthDay'=>1,
						'BirthYear'=>date('Y'),
						'HireMonth'=>1,
						'HireDay'=>1,
						'HireYear'=>date('Y'));	
	$browserEntries = array();
?>

This file sets several variables used throughout the application.

Code Sample:

ReusingCode/Demos/AddEmployee.php
<?php
	require 'Includes/fnFormValidation.php';
	require 'Includes/fnFormPresentation.php';
	require 'Includes/fnStrings.php';
	require 'Includes/fnDates.php';
	require 'Includes/init.php';
?>
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Add Employee</title>
<style type="text/css">
	.Error {color:red; font-size:smaller;}
</style>
</head>
<body>
<?php
	require 'Includes/Header.php';

	if (array_key_exists('Submitted',$_POST))
	{
		require 'Includes/ProcessEmployee.php';
	}
	elseif (array_key_exists('Confirmed',$_POST))
	{
		require 'Includes/InsertEmployee.php';
	}

	if ($showForm)
	{
		require 'Includes/EmployeeForm.php';
	}

	require 'Includes/Footer.php';
?>
</body>
</html>

The code is relatively easy to read. Things to note:

  1. At the very top, we include several files we will need for the application.
  2. In the body, we include:
    • our header and footer files.
    • code that checks which, if either, form was submitted and includes the appropriate file.
    • code that checks whether or not to show the main form. The form will be shown if:
      • it has not yet been submitted.
      • it has been submitted with errors.

Code Sample:

ReusingCode/Demos/Includes/fnDates.php
<?php
/********* DATE FUNCTIONS *********/

/*
	Function Name: monthAsString
	Arguments: $m
	Returns:
		month as string
*/
function monthAsString($m)
{
	$months = array();
	$months[] = 'January';
	$months[] = 'February';
	$months[] = 'March';
	$months[] = 'April';
	$months[] = 'May';
	$months[] = 'June';
	$months[] = 'July';
	$months[] = 'August';
	$months[] = 'September';
	$months[] = 'October';
	$months[] = 'November';
	$months[] = 'December';
	
	return $months[$m-1];
}
?>

This file includes a simple function for getting the name of a month (e.g, February) given the month number (e.g, 2).

Code Sample:

ReusingCode/Demos/Includes/fnStrings.php
<?php
/********** STRING FUNCTIONS *********/
/*
	Function Name: browserString
	Arguments: $string
	Returns:
		trimmed and escaped string for browser output
*/
function browserString($string)
{
	return nl2br(trim(htmlentities($string)));
}

/*
	Function Name: dbString
	Arguments: $string
	Returns:
		trimmed and escaped string for database entry
*/
function dbString($email)
{
	if (get_magic_quotes_gpc())
	{
		return trim ($email);
	}
	else
	{
		return addslashes(trim($email));
	}
}

?>

This file includes functions for cleaning up strings for browser and database output.

Code Sample:

ReusingCode/Demos/Includes/fnFormPresentation.php
<?php
/********* FORM PRESENTATION FUNCTIONS *********/

/*
	Function Name: textEntry
	Arguments: $display,$name,$entries,$errors,$size?
	Returns:
		one table row as string
*/
function textEntry($display,$name,$entries,$errors,$size=15)
{
	$returnVal = "
	<tr>
		<td>$display:</td>
		<td>
			<input type='text' name='$name' size='$size'
			value=\"" . browserString($entries[$name]) . "\">";

	if (array_key_exists($name,$errors))
	{
		$returnVal .= '<span class="Error" style="white-space:nowrap">* ' .
				$errors[$name] .
			'</span>';
	}

	$returnVal .= "</td>
	</tr>";

	return $returnVal;
}

/*
	Function Name: pwEntry
	Arguments: $pw1,$pw2,$errors,$size?
	Returns:
		table rows as string
*/
function pwEntry($pw1,$pw2,$errors,$size=10)
{
	$returnVal = "
	<tr>
		<td>Password:</td>
		<td>
			<input type='password' name='$pw1' size='$size'>
		</td>
	</tr>
	<tr>
		<td>Repeat Password:</td>
		<td>
			<input type='password' name='$pw2' size='$size'>
		</td>
	</tr>";

	if (array_key_exists('Password',$errors))
	{
		$returnVal .= addErrorRow('Password',$errors);
	}
	return $returnVal;
}

/*
	Function Name: textAreaEntry
	Arguments: $display,$name,$entries,$errors,$cols?,$rows?
	Returns:
		table rows as string
*/
function textAreaEntry($display,$name,$entries,$errors,$cols=45,$rows=5)
{
	$returnVal = "
	<tr>
		<td colspan='2'>$display:</td>
	</tr>
	<tr>
		<td colspan='2'>
			<textarea name='$name' cols='$cols' rows='$rows'>";
			$returnVal .= $entries[$name];
			$returnVal .= "</textarea>
		</td>
	</tr>";

	if (array_key_exists($name,$errors))
	{
		$returnVal .= addErrorRow($name,$errors);
	}
	return $returnVal;
}

/*
	Function Name: radioEntry
	Arguments: $display,$name,$entries,$errors,$values
	Returns:
		table rows as string
*/
function radioEntry($display,$name,$entries,$errors,$values)
{
	$returnVal = "
	<tr>
		<td>$display:</td>
		<td>$name</td>
	</tr>";

	return $returnVal;
}

/*
	Function Name: selectEntry
	Arguments: $display,$name,$entries,$errors,$selected?
	Returns:
		table rows as string
*/
function selectEntry($display,$name,$options,$errors,$selected=0)
{
	$returnVal = "<tr>
		<td>$display:</td>
		<td>
			<select name='$name'>
			<option value='0'>Choose one...</option>";
			$returnVal .= "</select>
		</td>
		</tr>";
	return $returnVal;
}

/*
	Function Name: selectDateEntry
	Arguments: $display,$namePre,$month,$day,$year
	Returns:
		table rows as string
*/
function selectDateEntry($display,$namePre,$month,$day,$year,$errors)
{
	$returnVal = "<tr>
		<td>$display:</td>
		<td>
			<select name='$namePre" . "Month'>";
			for ($i=1; $i<=12; $i++)
			{
				if ($i == $month)
				{
					$returnVal .= "<option value='$i' selected>";
				}
				else
				{
					$returnVal .= "<option value='$i'>";
				}
				$returnVal .= monthAsString($i) . '</option>';
			}
			$returnVal .= "</select>
			<select name='$namePre" . "Day'>";
			for ($i=1; $i<=31; $i++)
			{
				if ($i == $day)
				{
					$returnVal .= "<option value='$i' selected>";
				}
				else
				{
					$returnVal .= "<option value='$i'>";
				}
				$returnVal .= "$i</option>";
			}
			$returnVal .= "</select>
			<select name='$namePre" . "Year'>";
			for ($i=date('Y'); $i>=1900; $i=$i-1)
			{
				if ($i == $year)
				{
					$returnVal .= "<option value='$i' selected>";
				}
				else
				{
					$returnVal .= "<option value='$i'>$i</option>";
				}
				$returnVal .= "$i</option>";
			}
			$returnVal .= '</select>
		</td>
	</tr>';

	if (array_key_exists($namePre . 'Date',$errors))
	{
		$returnVal .= addErrorRow($namePre . 'Date',$errors);
	}
	return $returnVal;
}

/*
	Function Name: addErrorRow
	Arguments: $name
	Returns:
		table row as string
*/
function addErrorRow($name,$errors)
{
	$errorRow = '<tr><td colspan="2" class="Error">* ' .
					$errors[$name] .
				'</td></tr>';
	return $errorRow;
}
?>

This file contains functions for presenting form entries. Several of these functions are complete, but there are a couple that need to be finished. This will be part of the next exercise.

Code Sample:

ReusingCode/Demos/Includes/fnFormValidation.php
<?php
/********* FORM VALIDATION FUNCTIONS *********/

/*
	Function Name: checkLength
	Arguments: $text,$min?,$max?,$trim?
	Returns:
		false if $text has fewer than $min characters
		false if $text has more than $max characters
		true otherwise
*/
function checkLength($text,$min=1,$max=10000,$trim=true)
{
	if ($trim)
	{
		$text = trim($text);
	}
	if (strlen($text) < $min || strlen($text) > $max)
	{
		return false;
	}
	return true;
}

/*
	Function Name: checkEmail
	Arguments: $email
	Returns:
		false if $email has fewer than 6 characters
		false if $email does not contain @ symbol 
		false if $email does not contain a period (.)
		false if the last @ symbol comes after the last period (.)
		true otherwise
*/
function checkEmail($email)
{
	return true;
}

/*
	Function Name: checkPassword
	Arguments: $pw1,$pw2
	Returns:
		false if $pw1 has fewer than 6 characters
		false if $pw1 has more than 12 characters
		false if $pw1 and $pw2 do not match
		true otherwise
*/
function checkPassword($pw1,$pw2)
{
	return true;
}
?>

This file contains functions for validating form entries. One of these functions is complete, but there are a couple that need to be finished. This will also be part of the next exercise.

Code Sample:

ReusingCode/Demos/Includes/EmployeeForm.php
<h1 align="center">Add Employee</h1>
<form method="post" action="AddEmployee.php">
<input type="hidden" name="Submitted" value="true">
<table align="center" border="1" width="500">
	<?php 
		echo textEntry('First name','FirstName',$dbEntries,$errors,15);
		echo textEntry('Last name','LastName',$dbEntries,$errors,15);
		echo textEntry('Email','Email',$dbEntries,$errors,25);
		echo textEntry('Title','Title',$dbEntries,$errors,30);
		echo radioEntry('Title of Courtesy','TitleOfCourtesy',
			$dbEntries,$errors,
			array('Dr.','Mr.','Mrs.','Ms.'));
		echo selectDateEntry('Birth date','Birth',
							$dbEntries['BirthMonth'],
							$dbEntries['BirthDay'],
							$dbEntries['BirthYear'],
							$errors);
		echo selectDateEntry('Hire date','Hire',
							$dbEntries['HireMonth'],
							$dbEntries['HireDay'],
							$dbEntries['HireYear'],
							$errors);
		echo textEntry('Address','Address',$dbEntries,$errors,50);
		echo textEntry('City','City',$dbEntries,$errors,30);
		echo textEntry('Region','Region',$dbEntries,$errors,2);
		echo textEntry('Postal Code','PostalCode',$dbEntries,$errors,10);
		echo textEntry('Country','Country',$dbEntries,$errors,5);
		echo textEntry('Home phone','HomePhone',$dbEntries,$errors,15);
		echo textEntry('Extension','Extension',$dbEntries,$errors,5);
		echo textAreaEntry('Notes','Notes',$dbEntries,$errors,50,3);
		echo selectEntry('Manager','ReportsTo',$mgrEntries,
									$errors,$dbEntries['ReportsTo']);
		echo pwEntry('Password1','Password2',$errors,10);
	?>
	<tr>
		<td colspan="2"><input type="submit" value="Add Employee"></td>
	</tr>
</table>
</form>

This file creates the entry form. Notice that it creates entry rows through calls to functions in the fnFormPresentation.php file. This allows us to easily incorporate error handling and error messages into the form entries without making the HTML form itself difficult to maintain.

Code Sample:

ReusingCode/Demos/Includes/ProcessEmployee.php
<?php
	$dbEntries['FirstName'] = dbString($_POST['FirstName']);
	$dbEntries['LastName'] = dbString($_POST['LastName']);
	$dbEntries['Title'] = ucwords(dbString($_POST['Title']));
	$dbEntries['Address'] = dbString($_POST['Address']);
	$dbEntries['City'] = dbString($_POST['City']);
	$dbEntries['Region'] = dbString($_POST['Region']);
	$dbEntries['PostalCode'] = dbString($_POST['PostalCode']);
	$dbEntries['Country'] = dbString($_POST['Country']);
	$dbEntries['HomePhone'] = dbString($_POST['HomePhone']);
	$dbEntries['Extension'] = dbString($_POST['Extension']);
	$dbEntries['Notes'] = dbString($_POST['Notes']);
	$dbEntries['ReportsTo'] = $_POST['ReportsTo'];
	$dbEntries['Password'] = dbString($_POST['Password1']);
	$dbEntries['Email'] = dbString($_POST['Email']);
	$dbEntries['BirthMonth'] = dbString($_POST['BirthMonth']);
	$dbEntries['BirthDay'] = dbString($_POST['BirthDay']);
	$dbEntries['BirthYear'] = dbString($_POST['BirthYear']);
	$dbEntries['HireMonth'] = dbString($_POST['HireMonth']);
	$dbEntries['HireDay'] = dbString($_POST['HireDay']);
	$dbEntries['HireYear'] = dbString($_POST['HireYear']);

	if (!checkLength($_POST['FirstName']))
	{
		$errors['FirstName'] = 'First name omitted.';
	}
	else
	{
		$browserEntries['FirstName'] = browserString($_POST['FirstName']);
	}

	if (!checkLength($_POST['LastName']))
	{
		$errors['LastName'] = 'Last name omitted.';
	}
	else
	{
		$browserEntries['LastName'] = browserString($_POST['LastName']);
	}

	if (!checkLength($_POST['Title']))
	{
		$errors['Title'] = 'Title omitted.';
	}
	else
	{
		$browserEntries['Title'] = ucwords(browserString($_POST['Title']));
	}

	if ( array_key_exists('TitleOfCourtesy',$_POST) )
	{
		$browserEntries['TitleOfCourtesy'] = browserString($_POST['TitleOfCourtesy']);
		$dbEntries['TitleOfCourtesy'] = dbString($_POST['TitleOfCourtesy']);
	}
	else
	{
		$errors['TitleOfCourtesy'] = 'Title of Courtesy not selected.';
	}

	if (!checkdate($_POST['BirthMonth'],$_POST['BirthDay'],$_POST['BirthYear']))
	{
		$errors['BirthDate'] = 'Birth date is not a valid date.';
	}

	if (!checkdate($_POST['HireMonth'],$_POST['HireDay'],$_POST['HireYear']))
	{
		$errors['HireDate'] = 'Hire date is not a valid date.';
	}

	if (!checkLength($_POST['Address'],5,200))
	{
		$errors['Address'] = 'Address omitted.';
	}
	else
	{
		$browserEntries['Address'] = browserString($_POST['Address']);
	}

	if (!checkLength($_POST['City'],1,100))
	{
		$errors['City'] = 'City omitted.';
	}
	else
	{
		$browserEntries['City'] = browserString($_POST['City']);
	}

	if (!checkLength($_POST['Region'],2,2) && !checkLength($_POST['Region'],0,0))
	{
		$errors['Region'] = 'Region name must be two characters.';
	}
	else
	{
		$browserEntries['Region'] = browserString($_POST['Region']);
	}

	if (!checkLength($_POST['PostalCode']))
	{
		$errors['PostalCode'] = 'Postal Code omitted.';
	}
	else
	{
		$browserEntries['PostalCode'] = browserString($_POST['PostalCode']);
	}

	if (!checkLength($_POST['Country']))
	{
		$errors['Country'] = 'Country omitted.';
	}
	else
	{
		$browserEntries['Country'] = browserString($_POST['Country']);
	}

	if (!checkLength($_POST['HomePhone'],10,15))
	{
		$errors['HomePhone'] = 'Home phone must be between 10 and 15 characters.';
	}
	else
	{
		$browserEntries['HomePhone'] = browserString($_POST['HomePhone']);
	}

	if (!checkLength($_POST['Extension'],3,5))
	{
		$errors['Extension'] = 'Extension must be between 3 and 5 characters.';
	}
	else
	{
		$browserEntries['Extension'] = browserString($_POST['Extension']);
	}

	if (!checkLength($_POST['Notes'],0,100))
	{
		$errors['Notes'] = 'Notes must be fewer than 100 characters:<br>
			<span style="color:blue; font-weight:normal">' .
			browserString(substr($_POST['Notes'],0,100)) .
			'</span><span style="color:red; font-weight:normal;
			text-decoration:line-through;">' .
			browserString(substr($_POST['Notes'],100)) .
			'</span>';
	}
	else
	{
		$browserEntries['Notes'] = browserString($_POST['Notes']);
	}

	if ($_POST['ReportsTo'] == 0)
	{
		$errors['ReportsTo'] = 'Manager not selected.';
	}
	else
	{
		$browserEntries['ReportsTo'] = $_POST['ReportsTo'];
	}

	if ( !checkPassword($_POST['Password1'],$_POST['Password2']) )
	{
		$errors['Password'] = 'Passwords do not match or are not the right length.';
	}
	else
	{
		$browserEntries['Password'] = browserString($_POST['Password1']);
	}

	if ( !checkEmail($_POST['Email']) )
	{
		$errors['Email'] = 'Email is invalid.';
	}
	else
	{
		$browserEntries['Email'] = browserString($_POST['Email']);
	}
?>
<?php
	if (!count($errors))
	{
		$showForm = false;
?>
	<form method="post" action="AddEmployee.php">
	<input type="hidden" name="Confirmed" value="true">
	<?php
		echo '<h2>Confirm Entries</h2>';
		echo '<ol>';
		foreach ($browserEntries as $key=>$entry)
		{
			if ($key=='ReportsTo')
			{
				echo "<li><b>Manager:</b> $mgrEntries[$entry]</li>";
			}
			else
			{
				echo "<li><b>$key:</b> $entry</li>";
			}
		}
		echo '</ol>';

		foreach ($dbEntries as $key=>$entry)
		{
	?>
		<input type="hidden" name="<?php echo $key ?>"
			value="<?php echo $entry ?>">
	<?php
		}
	?>
		<input type="submit" value="Confirm">
	</form>
<?php
	}
	else
	{
		$dbEntries = $_POST;
	}
?>

This file contains code for processing the form entries. It makes use of functions in the fnFormValidation.php file for validating entries. If no errors are found, it sets the boolean $showForm to false, so that the original form will not be displayed and it outputs all the entries (made browser-safe) to the browser for confirmation. If errors are found, it adds them to the $errors array, which is passed into the form presentation functions, so that they can return code for displaying the errors. If there are errors, the boolean $showForm is left as true, so that the original form is redisplayed.

Code Sample:

ReusingCode/Demos/Includes/InsertEmployee.php
TO DO LATER

This file will eventually contain code for inserting the employee information into the database.

Next