W3docs

PHP Form Validation

Form validation is an essential part of website development, ensuring that the data entered by users is accurate and complete before it is processed. PHP is a

Form validation is the process of checking that the data a user submits through an HTML form is present, correctly formatted, and safe to use before your script acts on it. In PHP, validation runs on the server after the form is submitted, so it cannot be bypassed by disabling JavaScript or sending a request directly.

This chapter covers the full validation workflow: why server-side validation matters, the difference between sanitizing and validating, the PHP functions you'll reach for, and a complete, secure example you can adapt. If you're new to receiving form input, read PHP Form Handling first.

Why Server-Side Validation Matters

Client-side validation (HTML5 required, type="email", JavaScript) improves the user experience by catching mistakes instantly — but it is only a convenience. A determined or malicious user can disable JavaScript or send a crafted HTTP request that skips the browser entirely. The server is the only place validation can be trusted. Server-side PHP validation lets you:

  • Guarantee required fields are actually present and non-empty.
  • Confirm values match the expected format (a real email, a number in range).
  • Neutralize dangerous input before it reaches a database or an HTML page, preventing SQL injection and cross-site scripting (XSS).

Treat every value in $_POST, $_GET, and $_REQUEST as untrusted until you have checked it. These arrays come from PHP's superglobals.

Sanitizing vs. Validating

These two terms are often confused, but they do different jobs:

  • Sanitizing cleans a value — it removes or escapes unwanted characters. trim() strips surrounding whitespace; htmlspecialchars() converts <, >, &, and quotes into HTML entities so they render as text instead of executing.
  • Validating checks a value against a rule and tells you pass or fail — it does not change the value. filter_var($email, FILTER_VALIDATE_EMAIL) returns the email if it looks valid, or false if it doesn't.

A typical flow is: sanitize first (trim whitespace), then validate, and finally escape on output (when echoing back into HTML). For deeper coverage of PHP's filtering system, see PHP Filters and filter_var().

Validation Steps

A server-side validation routine usually follows the same four steps:

  1. Build the HTML form and point its action at the PHP script.
  2. Detect a POST submission with $_SERVER["REQUEST_METHOD"].
  3. For each field: read the value, sanitize it, then validate it — collecting any error messages.
  4. If every field passed, process the data; otherwise re-render the form with the error messages and the values the user already typed.

Useful PHP Validation Functions

FunctionPurpose
trim()Removes whitespace from the start and end of a string.
empty()Checks whether a value is missing or an empty string.
filter_var()Validates or sanitizes using a built-in filter (e.g. FILTER_VALIDATE_EMAIL, FILTER_VALIDATE_INT).
is_numeric()Returns true if the value is a number or numeric string.
htmlspecialchars()Escapes HTML special characters to prevent XSS on output.
preg_match()Validates against a custom regular expression pattern.

A Minimal Example

Before the full database example below, here is the smallest validation that captures the core pattern — sanitize, then validate, then collect errors:

<?php
$email = trim($_POST["email"] ?? "");
$errors = [];

if ($email === "") {
    $errors["email"] = "Please enter your email.";
} elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
    $errors["email"] = "Please enter a valid email address.";
}

if (empty($errors)) {
    echo "Valid email: " . htmlspecialchars($email);
} else {
    echo $errors["email"];
}
?>

If $_POST["email"] is " [email protected] ", the surrounding spaces are trimmed, the value validates, and the script prints Valid email: [email protected]. An entry like "not-an-email" produces Please enter a valid email address.

Full Example: Validating and Storing a Form

The example below validates a name, email, gender, and comment, then inserts the row using a prepared statement — the prepared-statement approach (with mysqli) is what protects you from SQL injection, because user input is sent separately from the SQL text and is never interpreted as code.

Update the database credentials and ensure your database contains a users table with name, email, gender, and comment columns before running this example.

<?php
// Database connection setup
$link = mysqli_connect("localhost", "username", "password", "database");
if (!$link) {
    die("Connection failed: " . mysqli_connect_error());
}

// Define variables and initialize with empty values
$name = $email = $gender = $comment = $website = "";
$name_err = $email_err = $gender_err = $comment_err = "";
 
// Processing form data when form is submitted
if($_SERVER["REQUEST_METHOD"] == "POST"){
    // Validate name
    if(empty(trim($_POST["name"] ?? ""))){
        $name_err = "Please enter your name.";
    } else{
        $name = trim($_POST["name"]);
    }
    
    // Validate email
    if(empty(trim($_POST["email"] ?? ""))){
        $email_err = "Please enter your email.";
    } elseif(!filter_var(trim($_POST["email"] ?? ""), FILTER_VALIDATE_EMAIL)) {
        $email_err = "Please enter a valid email address.";
    } else{
        $email = trim($_POST["email"]);
    }
    
    // Validate gender
    if(!isset($_POST["gender"]) || empty($_POST["gender"])){
        $gender_err = "Please select your gender.";
    } else{
        $gender = $_POST["gender"];
    }
    
    // Validate comment
    if(empty(trim($_POST["comment"] ?? ""))){
        $comment_err = "Please enter your comment.";
    } else{
        $comment = trim($_POST["comment"]);
    }
    
    // Check input errors before inserting in database
    if(empty($name_err) && empty($email_err) && empty($gender_err) && empty($comment_err)){
        // Prepare an insert statement
        $sql = "INSERT INTO users (name, email, gender, comment) VALUES (?, ?, ?, ?)";
         
        if($stmt = mysqli_prepare($link, $sql)){
            // Bind variables to the prepared statement as parameters
            mysqli_stmt_bind_param($stmt, "ssss", $param_name, $param_email, $param_gender, $param_comment);
            
            // Set parameters
            $param_name = $name;
            $param_email = $email;
            $param_gender = $gender;
            $param_comment = $comment;
            
            // Attempt to execute the prepared statement
            if(mysqli_stmt_execute($stmt)){
                // Records created successfully. Redirect to landing page
                header("location: index.php");
                exit();
            } else{
                echo "Something went wrong. Please try again later.";
            }
        }
         
        // Close statement
        mysqli_stmt_close($stmt);
    }
}

// Close connection
mysqli_close($link);
?>
<!DOCTYPE html>
<html>
<head><title>PHP Form Validation</title></head>
<body>
<form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>">
    Name: <input type="text" name="name" value="<?php echo htmlspecialchars($name); ?>">
    <span class="error"><?php echo $name_err; ?></span><br><br>
    Email: <input type="text" name="email" value="<?php echo htmlspecialchars($email); ?>">
    <span class="error"><?php echo $email_err; ?></span><br><br>
    Gender:
    <input type="radio" name="gender" value="female"> Female
    <input type="radio" name="gender" value="male"> Male
    <span class="error"><?php echo $gender_err; ?></span><br><br>
    Comment: <textarea name="comment"><?php echo htmlspecialchars($comment); ?></textarea>
    <span class="error"><?php echo $comment_err; ?></span><br><br>
    <input type="submit" value="Submit">
</form>
</body>
</html>

Showing Errors and Keeping User Input

Notice three details in the example that make for good form UX:

  • Each error variable ($name_err, $email_err, …) is printed in a <span class="error"> next to its field, so the user knows exactly which input to fix.
  • The form action echoes htmlspecialchars($_SERVER["PHP_SELF"]). Without escaping, PHP_SELF can be exploited to inject script through the URL, so escaping it is a security measure, not just a formatting one.
  • Every value re-displayed in the form is passed through htmlspecialchars(). This both prevents XSS and lets the user keep what they already typed instead of re-entering everything after one invalid field.

Common Gotchas

  • empty() treats "0" as empty. A field whose value is the string "0" will fail an empty() check. For fields where 0 is valid, compare explicitly: if ($value === "").
  • Validate before you trust the type. $_POST values are always strings. Use filter_var($n, FILTER_VALIDATE_INT) or is_numeric() rather than assuming a number arrived.
  • Escape on output, not on storage. Store the raw (validated) value in the database and apply htmlspecialchars() only when echoing into HTML. Escaping before storage corrupts the data for non-HTML uses.
  • Use the null-coalescing operator. $_POST["x"] ?? "" avoids "Undefined array key" warnings when a field is missing.

Validating Other Field Types

The same pattern extends to any field — only the validation rule changes:

<?php
// Age: an integer between 18 and 120
$age = filter_var($_POST["age"] ?? "", FILTER_VALIDATE_INT, [
    "options" => ["min_range" => 18, "max_range" => 120],
]);
if ($age === false) {
    echo "Please enter an age between 18 and 120.";
}

// Username: 3-16 letters, digits, or underscores
$username = trim($_POST["username"] ?? "");
if (!preg_match('/^[A-Za-z0-9_]{3,16}$/', $username)) {
    echo "Username must be 3-16 letters, digits, or underscores.";
}
?>

For URL and email-specific rules, see PHP Form URL & E-mail; for marking fields mandatory, see PHP Form Required Fields; and to see all the pieces assembled, see PHP Complete Form.

Conclusion

Server-side validation in PHP is what makes a form trustworthy: it confirms data is present and correctly formatted, and — paired with htmlspecialchars() on output and prepared statements on storage — it shuts down XSS and SQL injection. The core recipe is always the same: sanitize, validate, collect errors, and re-render the form with helpful messages when something is wrong. Master that loop and you can validate any field by swapping in a different rule.

Practice

Practice
What are some key elements in PHP form validation?
What are some key elements in PHP form validation?
Was this page helpful?