<?php
/**
 * Method to validate and sanitize user input
 *
 * William Eldridge
 * Version 1.0
 * Created February 20, 2008
 * Modified June 12, 2010
 */

// This file processes the user input from either get or post, checks and purifies any exploit code and stores appropriate data. Before
// this method is called, an array called $expected must be created, consisting of the name of the variable, the input method, the name
// of the input field and the value expected. The format is $expected[] = array('name' => name_of_variable, 'method' => input_method,
// 'field' => input_field_name, 'type' => type_of_data, 'size' => optional_length_of_data);
//
// Types of data are as follows:
//		string, which allow alphanumeric characters and most punctuation
//		html, which allows html tags;
//		alnum, which allows alphanumeric characters;
//		alnums, which allows alphanumeric characters and spaces;
//		alnumsd, which allows alphanumeric characters and spaces and dashes;
//		num, which allows numbers;
//		phone, which allows telephone numbers, after removing spaces and dashes
//		email, which allows e-mail addresses.
//		test, which returns true if the field was set with any value
//
//	The size field is optional, anc can be used to specify either a definite number of characters, a range of numbers of characters
//	a maximum number of characters or a minimum number of characters.
//	To specify an absolute number of characters:
//		For example, when validating US Zip Codes, there must be 7 digits, you would just enter the mandatory number '7'
//	To specify both a minimum and maximum number of characters:
//		For example, credit cards may be between 13 and 17 digits, seperate the minimum and maximum values with a comma '13,17'
//	To specify a minimum number of digits:
//		Follow the number with a comma '5,'
//	To specify a maximum number of characters:
//		Preceed the number with a comma ',5'
//
// For error management purposes, the system will create an associative array called input_errors. The key will contain the name of any
// variable that was submitted with bad data, and the value will be a friendly error message describing the error. To check for input
// errors, simply check if the input_errors array has any elements.

// Check that an array of expected variables was created
if (!isset($expected)) $expected = array();
if (!is_array($expected)) $expected = array();

// Create an array to store any input errors
$input_errors = array();

// Loop through the expected variables and store the data
for ($i = 0; $i < count($expected); $i++) {
	$temp = FALSE;
	$error_message = '';
	// Check the input method for this value
	if ($expected[$i]['method'] == 'post') {
		if (isset($_POST[$expected[$i]['field']])) {
			$temp = $_POST[$expected[$i]['field']];
		}
	} elseif ($expected[$i]['method'] == 'get') {
		if (isset($_GET[$expected[$i]['field']])) {
			$temp = $_GET[$expected[$i]['field']];
		}
	} elseif ($expected[$i]['method'] == 'either') {
		if (isset($_POST[$expected[$i]['field']])) {
			$temp = $_POST[$expected[$i]['field']];
		} elseif (isset($_GET[$expected[$i]['field']])) {
			$temp = $_GET[$expected[$i]['field']];
		}
	}
	
	// Based on the expected type of data, test and parse or reject the passed data
	if ($temp) {
		if ($expected[$i]['type'] == 'string') {
			// Strings do not allow html tags (< or >) or .. ` " ' ;
			$temp = stripslashes(trim($temp));
			$temp = preg_replace('/</', '', $temp);
			$temp = preg_replace('/>/', '', $temp);
			$temp = preg_replace('/`/', '', $temp);
			$temp = preg_replace('/"/', '', $temp);
			$temp = preg_replace('/\'/', '', $temp);
			$temp = preg_replace('/\.\./', '', $temp);
			$temp = preg_replace('/;/', '', $temp);
		} elseif ($expected[$i]['type'] == 'query') {
			// For database lookups, remove only characters that could be dangerous to the search - HTML, and change quotes
			$temp = stripslashes(trim($temp));
			$temp = preg_replace("/</", '', $temp);
			$temp = preg_replace("/>/", '', $temp);
			$temp = preg_replace("/`/", '', $temp);
			$temp = preg_replace("/\"/", '_', $temp);
			$temp = preg_replace("/'/", "_", $temp);
			$temp = preg_replace("/\.\./", '', $temp);
			$temp = preg_replace("/;/", '_', $temp);
		} elseif ($expected[$i]['type'] == 'html') {
			// Same as string but allows html tags and quotes
			$temp = stripslashes(trim($temp));
			$temp = preg_replace("/`/", '', $temp);
			$temp = preg_replace("/\.\./", '', $temp);
			$temp = preg_replace("/;/", '', $temp);
		} elseif ($expected[$i]['type'] == 'alnum') {
			// Only allows letters and numbers
			$temp = stripslashes(trim($temp));
			if (preg_match("/^[A-Za-z0-9]+$/", $temp) != 1) {
				$temp = FALSE;
				$error_message = 'Invalid characters. This field can only contain letters and numbers.';
			}
		} elseif ($expected[$i]['type'] == 'alnumd') {
			// Alnumd is for event and venue names passed as part of the url. It allows letters, numbers and dashes
			$temp = stripslashes(trim($temp));
			if (preg_match("/^[A-Za-z0-9_\-]+$/", $temp) != 1) {
				$temp = FALSE;
				$error_message = 'Invalid characters. This field can only contain letters, numbers and dashes.';
			}
		} elseif ($expected[$i]['type'] == 'alnums') {
			// Alnums allows letters numbers and spaces
			$temp = stripslashes(trim($temp));
			if (preg_match("/^[A-Za-z0-9 ]+$/", $temp) != 1) {
				$temp = FALSE;
				$error_message = 'Invalid characters. This field can only contain letters, numbers and spaces.';
			}
		} elseif ($expected[$i]['type'] == 'alnumsd') {
			// Alnums allows letters numbers spaces and dashes
			$temp = stripslashes(trim($temp));
			if (preg_match("/^[A-Za-z0-9 \-]+$/", $temp) != 1) {
				$temp = FALSE;
				$error_message = 'Invalid characters. This field can only contain letters, numbers, spaces and dashes.';
			}
		} elseif ($expected[$i]['type'] == 'num') {
			// Num only allows numbers
			$temp = stripslashes(trim($temp));
			if (preg_match("/^[0-9]+$/", $temp) != 1) {
				$temp = FALSE;
				$error_message = 'Invalid characters. This field can only contain numbers.';
			}
		} elseif ($expected[$i]['type'] == 'phone') {
			// Phone allows only numbers. Spaces, dashes and parenthases that may be used for formatting are allowed but removed
			$temp = stripslashes(trim($temp));
			$temp = preg_replace("/\(/", '', $temp);
			$temp = preg_replace("/\)/", '', $temp);
			$temp = preg_replace("/ /", '', $temp);
			$temp = preg_replace("/-/", '', $temp);
			if (preg_match("/^[0-9]+$/", $temp) != 1) {
				$temp = FALSE;
				$error_message = 'Invalid characters. This field can only contain numbers, in the form of a telephone number.';
			}
		} elseif ($expected[$i]['type'] == 'email') {
			// E-mail allows only characters that are in a properly formatted e-mail addresses. Formatting is checked
			$temp = stripslashes(trim($temp));
			if (preg_match("/^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,5}$/", $temp) != 1) {
				$temp = FALSE;
				$error_message = 'This field can only contain a properly formatted e-mail address.';
			}
		} elseif ($expected[$i]['type'] == 'test') {
			// Boolean test - if the value exists, set the variable to true.
			$temp = TRUE;
		}
	}
	
	// If the value is still true, check the length
	if ($temp) {
		$min = 0;
		$max = 254;
		if (isset($expected[$i]['size'])) {
			$lengthparam = $expected[$i]['size'];
			if (ereg("^[0-9,]+$", $lengthparam) && ereg("[,]{1}", $lengthparam)) {
				// The user specified a range of valid lengths
				$nums = explode(',', $expected[$i]['size']);
				if ($nums[0] >=0) {
					$min = $nums[0];
				}
				if ($nums[1] >=0) {
					$max = $nums[1];
				}
			} elseif (ereg("^[0-9]+$", $lengthparam)) {
				$max = $lengthparam;
				$min = $lengthparam;
			}
		}
		if ($min != $max) {
			if (!($min < strlen($temp)) || !(strlen($temp) < $max)) {
				//echo "<!-- $min < " . strlen($temp) . " < $max -->";
				$temp = FALSE;
				$error_message = 'This field can only contain ' . $min . ' to ' . $max . ' characters.';
			}
		} else {
			if ($min != strlen($temp)) {
				$temp = FALSE;
				$error_message = 'This field must contain ' . $min . ' characters.';
			}
		}
	}
	
	// If the value has survived, create the variable
	if ($temp === FALSE) {
		${$expected[$i]['name']} = FALSE;
		$input_errors[$expected[$i]['name']] = $error_message;
	} else {
		${$expected[$i]['name']} = $temp;
	}
}

// Finally, purge the get and post variables
unset($_GET);
unset($_POST);
unset($_REQUEST);
unset($expected);
?>
