PHP: Form Validation
September 19, 2018
Previously in the course, you learnt about forms in PHP: Superglobals and Forms. In this tutorial you are going to learn about (a) how to make sure your website remains safe and secure from hackers when you accept form input and (b) how to provide a user helpful messages when they fill a form incorrectly.
PHP Form Security
Let’s quickly create a simple form in PHP:
<!-- form.php -->
<?php
if (isset($_POST['signup'])) {
$username = $_POST['username'];
$password = $_POST['password'];
$email = $_POST['email'];
}
?>
<form method="post">
<h3>Form</h3>
<input type="text" name="username" placeholder="Username"/>
<input type="email" name="email" placeholder="Email"/>
<input type="password" name="password" placeholder="Password"/>
<input type="submit" name="signup" Value="Signup">
</form>
The above forms allows a user to enter a username, email ID and password.
Now, the first thing you must do anytime you accept input from the user is to check is the validity of the inputs. Why?
Accepting form data without performing any checks on it can lead to a website being susceptible to attacks. This is because a hacker might submit things you did not expect them to. In fact, they can even submit HTML or JavaScript code in a way so that it gets executed when you are processing their submission. Hence, we want to ensure that the values entered in the form are “clean” or “valid” - i.e. the user entered what we expect them to enter.
In earlier versions of PHP, a hacker could redirect a user to a file on another server or submit the form to another address. All this could be done just by injecting HTML tags or Javascript code in the input fields of a form! This type of a vulnerability is called Cross-site scripting (XSS). Latest versions of PHP are much less vulnerable to XSS.
Hence, we prefer to remove special characters, extra spaces and backslashes from the input before we use the user submitted data in any way. Let’s write a function checkInput()
to do so.
function checkInput($var) {
$var = htmlspecialchars($var);
$var = trim($var);
$var = stripslashes($var);
return $var;
}
The checkInput()
function uses three inbuilt PHP functions:
- The
htmlspecialchars()
function makes sure any characters that are special in HTML are properly encoded so a person can’t inject HTML tags or Javascript into our page. - The
trim()
function removes whitespace and other predefined characters from both sides of a string. - The
stripslashes()
function removes backslashes.
Then, we need to call the checkInput()
function for all the input data in a form. This is what the updated form.php
looks like:
<!-- form.php -->
<?php
function checkInput($var) {
$var = htmlspecialchars($var);
$var = trim($var);
$var = stripslashes($var);
return $var;
}
if (isset($_POST['signup'])) {
$username = $_POST['username'];
$password = $_POST['password'];
$email = $_POST['email'];
$email = checkInput($email);
$username = checkInput($username);
$password = checkInput($password);
}
?>
<form method="post">
<h3>Form</h3>
<input type="text" name="username" placeholder="Username"/>
<input type="email" name="email" placeholder="Email"/>
<input type="password" name="password" placeholder="Password"/>
<input type="submit" name="signup" Value="Signup">
</form>
Great! Now we can be sure that the user submitted information does not have any special characters, extra spaces or backslashes.
Form Validation
Apart from the general check that should be performed on all inputs, what other specific checks might we want to do? Here are some other important checks.
- Do all mandatory input fields have some value or are they empty?
- Does the email id match the format
xxx@yyy.zzz
? - What about the length of the inputs? Is the username too long or the password too short?
For each of the above case, we should also display helpful error messages to the user. This is called form validation.
Let’s tackle these questions one by one.
Check for empty input
We declare an $error
variable which will store a description of any violations that happen when we perform form validation. Initially, $error
variable will be initialized to an empty string.
if (isset($_POST['signup'])) {
$username = $_POST['username'];
$password = $_POST['password'];
$email = $_POST['email'];
$error = "";
if (empty($username) || empty($password) || empty($email)) {
$error = 'All fields are required';
} else {
$email = checkInput($email);
$username = checkInput($username);
$password = checkInput($password);
}
}
We use the empty()
function to check if a variable is empty or not. If any of the three variables are empty, we set the $error
variable. Otherwise, we call the checkInput()
function for each of the input.
To display the error, we add a PHP tag inside the form
element as shown:
<form method="post">
<h3>Form</h3>
<input type="text" name="username" placeholder="Username"/>
<input type="email" name="email" placeholder="Email"/>
<input type="password" name="password" placeholder="Password"/>
<input type="submit" name="signup" Value="Signup">
<?php
if (isset($error)) {
echo '<p>' . $error . '</p>';
}
?>
</form>
If you now click on the Signup
button without filling the input fields, you will see this message:
All fields are required
Check for email validity
The easiest and safest way to check whether an email address is well-formed (like xxx@yyy.zzz
) is to use PHP’s filter_var()
function. The code below stores an error message if the e-mail address is not well-formed:
if (isset($_POST['signup'])) {
$username = $_POST['username'];
$password = $_POST['password'];
$email = $_POST['email'];
$error = "";
if (empty($username) || empty($password) || empty($email)) {
$error = 'All fields are required';
} else {
$email = checkInput($email);
$username = checkInput($username);
$password = checkInput($password);
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$error = "Invalid email format";
}
}
}
Note: In HTML,
<input type="email" />
only checks if there is an @ sign with characters before and after it. So email of the form xxx@yyy is a valid as far as HTML is concerned. Thus, PHP validation usingfilter_var()
is a better way to check for well-formed email addresses.
FILTER_VALIDATE_EMAIL
is used to check if the email has a valid format or not. Similarly, there are constants like FILTER_VALIDATE_INT
, FILTER_VALIDATE_IP
, FILTER_VALIDATE_URL
, etc. You can find a list of all validation filters here: Validate filters.
Instead of validate, it is also possible to sanitize values. Validating checks for whether or not the input is as expected, sanitizing cleans it. For example, if there is a special character in an input which only accepts numbers, sanitizing will remove the special characters. You can use FILTER_SANITIZE_EMAIL
, FILTER_SANITIZE_INT
, etc, exactly the same way. You can find a list of all sanitization filters here: Sanitize filters.
Check for length of input
You have already looked at strlen()
function to get the length of a string. Let’s use it to display an error if the username is more than 20 characters or the password less than 6 characters:
if (isset($_POST['signup'])) {
$username = $_POST['username'];
$password = $_POST['password'];
$email = $_POST['email'];
$error = "";
if (empty($username) || empty($password) || empty($email)) {
$error = 'All fields are required';
} else {
$email = checkInput($email);
$username = checkInput($username);
$password = checkInput($password);
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$error = "Invalid email format";
} elseif (strlen($username) > 20) {
$error = "Username must be below 20 characters";
} elseif (strlen($password) < 6) {
$error = "Password too short";
}
}
}
Header
We now know how to show appropriate errors for different invalid inputs. Once we check all the input is valid, we usually want the user to be redirected to a another page, say home.php
. Let’s create the home.php
file:
<!-- home.php -->
<?php
session_start();
echo $_SESSION["username"];
?>
Then, use the header()
function to redirect the user to it:
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$error = "Invalid email format";
} elseif (strlen($username) > 20) {
$error = "Username must be below 20 characters";
} elseif (strlen($password) < 5) {
$error = "Password too short";
} else {
$_SESSION["username"] = $username;
header("Location: home.php");
}
}
"Location: home.php"
means we want to redirect the user to home.php
.
Note:
home.php
also callssession_start()
at the beginning of the file. This is to record the fact that the user has successfully logged in.
The header()
function can also be used to prompt a dialog box to download and save a file (for example: a generated PDF file) to your computer.
Summary
Great! You just learnt how to ensure your website forms are secure from hackers, how to validate input fields and display helpful error messages, and how to successfully redirect the user to a home page once they successfully log-in.
This is what the final version of form.php
looks like:
<!-- form.php -->
<?php
session_start();
function checkInput($var) {
$var = htmlspecialchars($var);
$var = trim($var);
$var = stripslashes($var);
return $var;
}
if (isset($_POST['signup'])) {
$username = $_POST['username'];
$password = $_POST['password'];
$email = $_POST['email'];
$error = "";
if (empty($username) || empty($password) || empty($email)) {
$error = 'All fields are required';
} else {
$email = checkInput($email);
$username = checkInput($username);
$password = checkInput($password);
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$error = "Invalid email format";
} elseif (strlen($username) > 20) {
$error = "Username must be below 20 characters";
} elseif (strlen($password) < 5) {
$error = "Password too short";
} else {
$_SESSION["username"] = $username;
header("Location: home.php");
}
}
}
?>
<form method="post">
<h3>Form</h3>
<input type="text" name="username" placeholder="Username"/>
<input type="email" name="email" placeholder="Email"/>
<input type="password" name="password" placeholder="Password"/>
<input type="submit" name="signup" Value="Signup">
<?php
if (isset($error)) {
echo '<p>' . $error . '</p>';
}
?>
</form>
This above flow is very common and used in every application where a user can sign-up or log-in. You’re another step closer to making really cool websites with PHP!