Validating User Input

What is validation and why do we need to do it? We validate because users input all kinds of weird things or they don't input anything at all. There many different strategies to validate. One thing that you absolutely need to be aware of is that you MUST validate your input on the server side.

Thankfully, we already have validation for XSS and SQL Injection. We don't need to worry about that here. But, we do need to worry about clean data.

> Strategy 1 - Rejecting Input. If you find input that is bad, you just send an error back to the user to clean up their act. Nothing get's put into the database.

> Strategy 2 - Filtering Input. If you find input that is bad, you filter the bad input out and leave only the good input. Data is inserted into the database and saved.

Each strategy has it's place. For example, when users add phone numbers, they tend to type them in all kinds of different formats. In this case, we would want to Filter input as opposed to rejecting. We'd like to normalize our data before inserting it into the database.

For example, if user 1 typed, (555)-555-5555, we'd want to filter out the parentheses. If user 2 typed, 555.555.5555, we'd want to filter out the dots and replace them with dashes.

If user 3 typed, I have a baby kitten into our phone number field, we'd want to reject that.

I'll leave this as an exercise to the user to filter phone numbers into a common format.

Let's add some simple user validation to our saveNewEmployee controller. Why do we add it to the controller and not the model? Basically, it's easier to respond to errors from the controller.

This code should be put into index.php in your webroot directory.

<?php

require_once "indexmodels.php";
use \IndexModels\IndexModels;

require_once "indexviews.php";
use \IndexViews\IndexViews;

if ( isset($_POST["do"]) == true) {
	if ($_POST["do"] == "saveNewEmployee") {
		
		// define a default
		$lastName = "";
		if (isset($_POST["lastName"]) == true && $_POST["lastName"] != "") {
			$lastName = $_POST["lastName"];
			// trim whitespace from both ends
			$lastName = trim($lastName);
			// filter out everything, except letters and dashes via a "regular expression"
			$lastName = preg_replace("/[^A-Za-z\-]/", "", $lastName);
			// uppercase first letter
			$lastName = ucfirst($lastName);
		}
		
		// define a default
		$firstName = "";
		if (isset($_POST["firstName"]) == true && $_POST["firstName"] != "") {
			$firstName = $_POST["firstName"];
			// trim whitespace from both ends
			$firstName = trim($firstName);
			// filter out everything, except letters and dashes via a "regular expression"
			$firstName = preg_replace("/[^A-Za-z\-]/", "", $firstName);
			// uppercase first letter
			$firstName = ucfirst($firstName);
		}
		
		// first and last name must be filled in
		if ($lastName != "" && $firstName != "") {
			IndexModels::saveNewEmployee($lastName, $firstName);
		}
		
		// after we've saved, forward the user back to our default screen
		header("Location: /");
		exit;
	}
} else {
	// show the default screen, which is a list of employees
	$results = IndexModels::index();
	IndexViews::index($results);
}

The filtering seems redundant. Let's create a new class that holds the filtering for us.

This code should be put into filter.php in your webroot directory.

<?php

namespace filter;

class filter {
	static public function names($in) {
		
		// trim whitespace from both ends
		$out = trim($in);
		// filter out everything, except letters and dashes via a "regular expression"
		$out = preg_replace("/[^A-Za-z\-]/", "", $out);
		// uppercase first letter
		$out = ucfirst($out);
		
		return $out;
	}
}

And, finally, the changes to make in our controller, adding the include for our filter class and changing out the code to do the filtering.

This code should be put into index.php in your webroot directory

<?php

require_once "filter.php";
use \filter\filter;

require_once "indexmodels.php";
use \IndexModels\IndexModels;

require_once "indexviews.php";
use \IndexViews\IndexViews;

if ( isset($_POST["do"]) == true) {
	if ($_POST["do"] == "saveNewEmployee") {
		
		// define a default
		$lastName = "";
		if (isset($_POST["lastName"]) == true && $_POST["lastName"] != "") {
			$lastName = filter::names($_POST["lastName"]);
		}
		
		// define a default
		$firstName = "";
		if (isset($_POST["firstName"]) == true && $_POST["firstName"] != "") {
			$firstName = filter::names($_POST["firstName"]);
		}
		
		if ($lastName != "" && $firstName != "") {
			IndexModels::saveNewEmployee($lastName, $firstName);
		}
		
		// after we've saved, forward the user back to our default screen
		// we do this so that if they click back or forward or reload,
		// it won't show that stupid confirm page resubmission.
		header("Location: /");
		exit;
	}
} else {
	// show the default screen, which is a list of employees
	$results = IndexModels::index();
	IndexViews::index($results);
}