CommonLounge Archive

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:

  1. 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.
  2. The trim() function removes whitespace and other predefined characters from both sides of a string.
  3. 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.

  1. Do all mandatory input fields have some value or are they empty?
  2. Does the email id match the format xxx@yyy.zzz?
  3. 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 using filter_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 calls session_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!


© 2016-2022. All rights reserved.