HYVOR DEVELOPER
php
Apr 11, 2018 15 mins 72

Input Validation with PHP

Of course, validating user input is really important for dynamic websites. Invalid user input can make errors in processing. Therefore, validating inputs is a must. The awesome language, PHP has numerous in-built functions to validate user inputs.

In this tutorial, you will learn about 4 major tasks.

Validating the Request Method

Before creating a HTML form you have to decide a HTTP method to use in your HTTP request. Among bunch of HTTP request methods, developers normally use GET and POST methods for forms. So... GET or POST?

GET Method

  • Should be used to get (request) data from a resource
  • Sends data with the URL as key-value pairs
  • Should be used to retrieve data from a resource
  • Never used to send sensitive data
  • Less secure than POST but faster
  • Different data creates different URLs
  • Can be cached in the browser. However, random data (timestamp) can be used to bypass cache
  • Remains in the browser history
  • Has length limitations
  • Only ASCII data

POST method

  • Should be used to post data to the server
  • Should be used to send sensitive data
  • Slower than GET, but more secure
  • Sends data with body of the HTTP message
  • Does not remain in the browser history
  • No length limitations
  • Any kind of data can be sent

If you are sending sensitive data such as passwords, emails with HTTP request you must use POST. If you are retrieving data from the server, you can use GET method.

Let's create the HTML form. Here I have chosen POST method and the action script, act.php


Browser will send the form data to act.php after submitting the form. I have created act.php as following. First, it will validate the request method.


<?php
	
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
	
		// the request method is fine

} else {

	exit('Invalid Request');

}


You can change 'POST' with your selected HTTP method. So, if act.php is requested with any other method, it will show an error. That's how the request method validation is done.

Checking User Inputs

Next, we have to check the user inputs to avoid processing errors. Let's see how an error can occur. Assume that you have php code to assign POST variable to a local variable as following.


<?php
	
$email = $_POST['email'];


If email variable is not set, PHP will throw following error.

( ! ) Notice: Undefined index: email in C:\Users\HP\Desktop\HTML\testing\pre.php on line 4
Call Stack
#TimeMemoryFunctionLocation
10.0014233832{main}( )...\pre.php:0

Therefore we have to check whether the inputs variables are set.

For NON-BOOLEAN Inputs

The empty function in PHP is really important in this case. It checks whether the argument is empty or not. It will return true in following cases.

  • "" - an empty string
  • 0 - 0 as an integer
  • 0.0 - 0 as a float
  • "0" - 0 as a string
  • NULL
  • FALSE
  • array() - an empty array

<?php
	
if (!empty($_POST['email'])) {
		
	$email = $_POST['email'];	

}


In the above example, $email variable is declared if $_POST['email'] is not empty. So, the error mentioned earlier won't trigger. But, if the email is compulsory, we have to throw an error if it's empty. The last subtopic of this tutorial will explain you to do that in an object oriented way.

For BOOLEAN Inputs

The isset function is better to use for boolean values because empty function returns true on false. Isset function checks whether the variable is set (or declared) and not null.


<?php
	
if (isset($_POST['boolean'])) {
		
	$email = $_POST['boolean'];	

}


Validating Inputs

Prevent XSS Attacks

First, we have to prevent XSS attacks (Cross-Site Scripting). Assume that we have following code in our HTML page to let users to input their username.


Now assume an attacker inputs following HTML code as the username.
<script>location.href='https://www.attacker.com'</script>
Then he submits the form. We save his username in the database without any validation. Then, we make a page to show usernames of the users. So, PHP will echo out above HTML code as his username. So, every user who visits this page will be redirected to https://www.attacker.com. Simply, this is called as XSS attacks.

It's pretty simple to protect a website from XSS attacks using PHP. The htmlspecialchars() function escapes HTML codes. So,

<script>location.href='https://www.attacker.com'</script>
will be changed to
&lt;script&gt;location.href='https://www.attacker.com'&lt;/script&gt;

Let's see an example:


<?php

if (!empty($_POST['username']) && !empty($_POST['email'])) {

	$username = htmlspecialchars($_POST['username']);
	$email = htmlspecialchars($_POST['email']);

}


There is one more thing to do with user inputs. We need to remove extra spaces and padding. So that extra spaces won't take space in your database if you are saving those inputs in a database. trim() function removes extra spaces.


<?php

if (!empty($_POST['username']) && !empty($_POST['email'])) {

	$username = trim(htmlspecialchars($_POST['username']));
	$email = trim(htmlspecialchars($_POST['email']));

}


Note: We will create a function to do both at once in the last part of this tutorial.

Validating Emails, URLs, Integers, , etc.

PHP has filter_var() function to validate variables. We can set it's second parameter to different values and use it to validate emails, URLs, integers, booleans, etc. This function returns false on failure or invalid input.

1. Validating Emails

We can simply validate an email using filter_var() function and FILTER_VALIDATE_EMAIL flag. It returns false if the email is invalid.


<?php

if (!empty($_POST['email'])) {

	$email = trim(htmlspecialchars($_POST['email']));
	$email = filter_var($email, FILTER_VALIDATE_EMAIL);

	if ($email === false) {
		exit('Invalid Email');
	}

}


2. Validating URLs

Here we use FILTER_VALIDATE_URL flag with filter_var() function. It returns false if the URL is not in the correct format and returns the URL on success.


<?php

if (!empty($_POST['url'])) {

	$url = trim(htmlspecialchars($_POST['url']));
	$url = filter_var($url, FILTER_VALIDATE_URL);

	if ($url === false) {
		exit('Invalid URL');
	}

}


3. Validating Integers

Here we use FILTER_VALIDATE_INT flag with filter_var() function. This method can be used to validate any integer value such as a primary integer key (userId, groupId, etc.) in database, timestamp, etc. The advantage of using this function is, it converts string numbers ("25") to actual integers (25). So that we can treat integer inputs as integer without any hesitation after sending the input through this function.


<?php

if (!empty($_POST['number'])) {
	
	$number = $_POST['number'];
	$number = filter_var($number, FILTER_VALIDATE_INT);

	if ($number === false) {
		exit('Invalid Integer');
	}

}


When sending an input through the function,

  • 25 (Integer) won't be changed
  • "25" (string) will be converted to 25 (Integer)
  • 25.11 (Float) will return false as they are not integers
  • true (Boolean) will return 1 (Integer)
  • false (Boolean) will return false (Boolean)
  • Arrays, Objects and String (that contains non-numeric characters) will return false (Boolean)

Note: All false values means that they are not integers.

4. Validating Booleans

Here we use FILTER_VALIDATE_BOOLEAN flag with filter_var() function. This flag enables some amazing attributes to the function. It returns true on strings like 'on', 'yes', 'true' (Case-Insensitive), on boolean true. All other inputs will return false.

Many browsers send string "on" if a checkbox is ticked by user. This string is hard to work with. Let's see an example how to convert it to a boolean.


<?php

if (!empty($_POST['check'])) {

	$check = $_POST['check'];
	$check = filter_var($check, FILTER_VALIDATE_BOOLEAN);
	
}


After sending the input through filter_var() function with FILTER_VALIDATE_BOOLEAN flag, "on" (string) will be converted to true. Thereafter, we can treat the input as a boolean.

We have discussed many functions to validate inputs. But, writing them all over and over again is not a good practice. So, in the next step we will be creating a class to validate inputs in a more convenient way.

Creating Your Own Class To Validate Inputs

I assume that you have basic knowledge on Object Oriented Programming. Our class must prevent XSS attacks and validate inputs. I have named the class as Input.


<?php

class Input {
	

}


I have used static functions for each case as they make it easy to call. It has following functions.

  • check() To check whether the inputs are empty or not
  • int() To validate integers
  • str() To escape html characters and trim a string
  • bool() To convert any variable to boolean
  • email() To validate emails
  • url() To validate URLs

So, the full code will be like following.


<?php

class  Input {
	static $errors = true;

	static function check($arr, $on = false) {
		if ($on === false) {
			$on = $_REQUEST;
		}
		foreach ($arr as $value) {	
			if (empty($on[$value])) {
				self::throwError('Data is missing', 900);
			}
		}
	}

	static function int($val) {
		$val = filter_var($val, FILTER_VALIDATE_INT);
		if ($val === false) {
			self::throwError('Invalid Integer', 901);
		}
		return $val;
	}

	static function str($val) {
		if (!is_string($val)) {
			self::throwError('Invalid String', 902);
		}
		$val = trim(htmlspecialchars($val));
		return $val;
	}

	static function bool($val) {
		$val = filter_var($val, FILTER_VALIDATE_BOOLEAN);
		return $val;
	}

	static function email($val) {
		$val = filter_var($val, FILTER_VALIDATE_EMAIL);
		if ($val === false) {
			self::throwError('Invalid Email', 903);
		}
		return $val;
	}

	static function url($val) {
		$val = filter_var($val, FILTER_VALIDATE_URL);
		if ($val === false) {
			self::throwError('Invalid URL', 904);
		}
		return $val;
	}

	static function throwError($error = 'Error In Processing', $errorCode = 0) {
		if (self::$errors === true) {
			throw new Exception($error, $errorCode);
		}
	}
}


Let's see some examples of usage of our class.

Initiating the Class

You can copy the above code to a new file and include that file in your script. If you are interested in autoloading classes, you can check our tutorial.

Error Handling

As in the above code, I have created the method throwError to throw errors. It throws error if the static variable error is true. If you don't need errors to be thrown, you can set error to false.


Input::$error = false;


Checking Inputs

I have created check function to check inputs. There are two arguments in the function. First one is an array of elements that is needed to be checked. Second one is the Super Global Array that holds the Inputs. ($_POST for POST method, $_GET for GET method. Default is $_REQUEST)


Input::check(['email', 'password'], $_POST);


This code will check whether email and password are in $_POST and they are not empty. If they are empty it will throw an error.

Validation

You can use other functions in the class to validate followings.


	// validate an integer
$number = Input::int($_POST['number']);

	// validate a string
$name = Input::str($_POST['name']);

	// convert to boolean
$bool = Input::bool($_POST['boolean']);

	// validate an email
$email = Input::email($_POST['email']);

	// validate a URL
$url = Input::url($_POST['url']);


Conclusion

This tutorial showed you how to check and validate user inputs and prevent XSS attacks. The filter_var() function was described with it's filters with examples. This tutorial gained your knowledge on validating emails, URLs, integers, booleans and more. Finally we created a class to make validating more convenient. You can improve that class with your knowledge and make it more functional according to your needs.

If you have any kind of question to ask, comment below. Thank you for reading.

Author SupunKavinda