PHP Form Validation

sa sahaya jerish Updated 17 Oct 2026
7 min read ·Lesson 90 of 248
In this post

What Is Form Validation? In simple terms: Validation checks whether submitted data is acceptable before your application uses it — for example, that an email address looks like an email address, an ag

What Is Form Validation?

In simple terms: Validation checks whether submitted data is acceptable before your application uses it — for example, that an email address looks like an email address, an age is a whole number in a sensible range, and a password is long enough.

Technically: Validation applies rules to each input value and either accepts it (often converting it to the right type) or rejects it with an error message. In PHP, validation is built from comparisons, string functions, regular expressions, and the filter extension (filter_var() and related functions).

Why Server-Side Validation Is Mandatory

HTML attributes such as required, type="email", min, and maxlength improve the user experience, but they run in the browser, which the user controls. Anyone can remove them in developer tools or send requests directly with tools such as curl. Only validation on the server protects your data:

Client-Side (HTML/JavaScript)Server-Side (PHP)
Instant feedback while typingRuns after submission
Can be bypassedCannot be bypassed
Optional, for convenienceRequired, for correctness and security

Kinds of Validation Rules

Rule TypeExampleTypical Tool
PresenceName must not be emptytrim($value) !== '' (see PHP Form Required)
TypeAge must be an integerfilter_var(..., FILTER_VALIDATE_INT)
FormatEmail, URL, PIN codeFILTER_VALIDATE_EMAIL, preg_match()
LengthPassword at least 8 charactersmb_strlen()
RangeRating from 1 to 5Filter options min_range/max_range
Allowed valuesPlan is free or proin_array(..., true)
ConsistencyPassword confirmation matches=== comparison
UniquenessEmail not already registeredDatabase query

The Filter Extension: filter_var()

Syntax

filter_var(mixed $value, int $filter = FILTER_DEFAULT, array|int $options = 0): mixed

Validation filters return the converted value on success and false on failure.

Validating Integers

<?php
var_dump(filter_var('42', FILTER_VALIDATE_INT));
var_dump(filter_var(' 42 ', FILTER_VALIDATE_INT));
var_dump(filter_var('42abc', FILTER_VALIDATE_INT));
var_dump(filter_var('4.2', FILTER_VALIDATE_INT));
var_dump(filter_var('150', FILTER_VALIDATE_INT, ['options' => ['min_range' => 1, 'max_range' => 120]]));

Output

int(42)
int(42)
bool(false)
bool(false)
bool(false)
  • A valid value is returned as a real int, ready to use.
  • Leading and trailing whitespace is ignored.
  • Partial numbers (42abc) and decimals are rejected — unlike (int), which would silently convert '42abc' to 42.
  • min_range and max_range enforce a range in the same step.

Watch out for 0: A valid input of '0' returns int(0), which is falsy. Always compare with === false, never with if (!$result).

Validating Floats and Booleans

<?php
var_dump(filter_var('3.14', FILTER_VALIDATE_FLOAT));
var_dump(filter_var('3,14', FILTER_VALIDATE_FLOAT, ['options' => ['decimal' => ',']]));

var_dump(filter_var('yes', FILTER_VALIDATE_BOOL));
var_dump(filter_var('off', FILTER_VALIDATE_BOOL));
var_dump(filter_var('maybe', FILTER_VALIDATE_BOOL, FILTER_NULL_ON_FAILURE));

Output

float(3.14)
float(3.14)
bool(true)
bool(false)
NULL
  • The decimal option accepts a comma as the decimal separator.
  • FILTER_VALIDATE_BOOL (an alias of FILTER_VALIDATE_BOOLEAN, PHP 8.0+) accepts 1, true, on, yes as true and 0, false, off, no, '' as false.
  • Because false is both a valid result and the failure value, add FILTER_NULL_ON_FAILURE to get null for invalid input such as 'maybe'.

Other Validation Filters

FilterValidates
FILTER_VALIDATE_EMAILEmail addresses (see PHP Form URL/E-mail)
FILTER_VALIDATE_URLURLs
FILTER_VALIDATE_IPIPv4/IPv6 addresses (flags for private/reserved ranges)
FILTER_VALIDATE_DOMAINDomain names (with FILTER_FLAG_HOSTNAME)
FILTER_VALIDATE_MACMAC addresses
FILTER_VALIDATE_REGEXPA custom regular expression ('options' => ['regexp' => '/.../'])

Validating Many Fields at Once: filter_var_array()

<?php
$input = ['age' => '25', 'email' => 'asha@example', 'newsletter' => 'yes', 'rating' => '7'];

$definition = [
    'age' => ['filter' => FILTER_VALIDATE_INT, 'options' => ['min_range' => 13, 'max_range' => 120]],
    'email' => FILTER_VALIDATE_EMAIL,
    'newsletter' => ['filter' => FILTER_VALIDATE_BOOL, 'flags' => FILTER_NULL_ON_FAILURE],
    'rating' => ['filter' => FILTER_VALIDATE_INT, 'options' => ['min_range' => 1, 'max_range' => 5]],
];

var_dump(filter_var_array($input, $definition));

Output

array(4) {
  ["age"]=>
  int(25)
  ["email"]=>
  bool(false)
  ["newsletter"]=>
  bool(true)
  ["rating"]=>
  bool(false)
}

Each field gets its own filter and options. Fields listed in the definition but missing from the input are returned as null, which lets you distinguish "missing" (null) from "invalid" (false). filter_input_array(INPUT_POST, $definition) does the same directly on the request data.


Building a Reusable Validator

Real forms combine several rules per field and need readable error messages. A small rule-based validator keeps form code short and consistent:

<?php
function validate(array $input, array $rules): array
{
    $errors = [];

    foreach ($rules as $field => $fieldRules) {
        $raw = $input[$field] ?? '';
        $value = is_string($raw) ? trim($raw) : '';
        $label = str_replace('_', ' ', $field);

        foreach ($fieldRules as $rule) {
            [$name, $a, $b] = array_pad(explode(':', $rule), 3, null);

            $error = match ($name) {
                'required' => $value === '' ? "The $label field is required." : null,
                'email' => $value !== '' && filter_var($value, FILTER_VALIDATE_EMAIL) === false
                    ? "The $label must be a valid email address." : null,
                'min' => $value !== '' && mb_strlen($value) < (int) $a
                    ? "The $label must be at least $a characters." : null,
                'max' => mb_strlen($value) > (int) $a
                    ? "The $label may not be longer than $a characters." : null,
                'int' => $value !== '' && filter_var($value, FILTER_VALIDATE_INT, [
                        'options' => ['min_range' => (int) $a, 'max_range' => (int) $b],
                    ]) === false
                    ? "The $label must be a whole number between $a and $b." : null,
                'same' => $value !== (is_string($input[$a] ?? null) ? trim($input[$a]) : '')
                    ? "The $label must match the $a." : null,
                default => throw new InvalidArgumentException("Unknown rule: $name"),
            };

            if ($error !== null) {
                $errors[$field] = $error;
                break;
            }
        }
    }

    return $errors;
}

$rules = [
    'name' => ['required', 'max:50'],
    'email' => ['required', 'email'],
    'age' => ['required', 'int:18:100'],
    'password' => ['required', 'min:8'],
    'password_confirm' => ['required', 'same:password'],
];

print_r(validate([
    'name' => '',
    'email' => 'asha@',
    'age' => '15',
    'password' => 'short',
    'password_confirm' => 'shorter',
], $rules));

$valid = validate([
    'name' => 'Asha',
    'email' => 'asha@example.com',
    'age' => '24',
    'password' => 'Secure#2026',
    'password_confirm' => 'Secure#2026',
], $rules);

echo $valid === [] ? "No errors\n" : "Errors found\n";

Output

Array
(
    [name] => The name field is required.
    [email] => The email must be a valid email address.
    [age] => The age must be a whole number between 18 and 100.
    [password] => The password must be at least 8 characters.
    [password_confirm] => The password confirm must match the password.
)
No errors

How It Works

  1. Rules are written as short strings ('int:18:100'); explode(':', ...) splits the rule name from its parameters, and array_pad() guarantees three elements for destructuring.
  2. Every value is read safely: non-string input (for example, an array sent as name[]) is treated as empty.
  3. A match expression maps each rule to its check. Most rules skip empty values, so required alone decides whether a field may be empty — optional fields can still have format rules.
  4. Only the first failing rule per field is reported (break), giving one clear message per field.
  5. Unknown rule names throw an exception, so typos in rule definitions are noticed immediately.

Note: This simplified validator trims every value. In a real application, do not trim passwords — leading or trailing spaces may be intentional. Frameworks provide complete validators (Laravel's $request->validate(), Symfony Validator) built on the same ideas.


Where Validation Fits

read input → validate → (if errors) re-display form with messages
                      → (if valid) process with the validated, typed values
  • Validate all fields and show all errors together.
  • Use the converted values from validation (for example, the integer returned by filter_var()) for further processing.
  • Validation does not replace output escaping (htmlspecialchars()) or prepared statements for SQL; each protects a different step.

Common Mistakes

Relying on HTML Validation

Effect: Invalid or malicious data reaches the server.

Fix: Validate every field in PHP.

Using Casts Instead of Validation

Effect: (int) 'abc' silently becomes 0; (int) '42abc' becomes 42.

Fix: filter_var(..., FILTER_VALIDATE_INT) and check for false.

Checking Filter Results Loosely

Effect: Valid values 0 or false are treated as failures.

Fix: Compare with === false (or use FILTER_NULL_ON_FAILURE for booleans).

Validating Without Allow-Lists

Effect: Unexpected values for plans, roles, or sort orders are accepted.

Fix: in_array($value, $allowed, true).

Stopping at the First Error

Effect: Users fix one problem, resubmit, and discover the next.

Fix: Collect errors for all fields.


Best Practices

  • Validate on the server, using HTML validation only for convenience.
  • Use filter_var() for types and standard formats, and regular expressions for custom formats.
  • Keep validation rules in one place and return field-specific error messages.
  • Work with the converted, validated values afterwards.
  • Combine validation with output escaping, prepared statements, and CSRF protection.

Official reference: https://www.php.net/manual/en/book.filter.php

0 Comments

Reviewed before they appear

No comments yet.

PHP
PHP Home PHP Switch PHP Match Alternative Syntax PHP Loops While Loop Do While Loop For Loop Foreach Loop Nested Loops Break Statement PHP Intro PHP Install PHP Built-in Web Server PHP Syntax PHP Tags PHP and HTML PHP Comments PHP Multiline Comments PHP Variables Variables Scope PHP Casting Logical Operators Null Coalescing Operator Spaceship Operator Operator Precedence Continue Statement Modify Strings PHP If...Else...Elseif PHP If Modify Strings PHP If Operators PHP Functions Concatenate Strings PHP If...Else User-defined Functions Slicing Strings Function Arguments PHP Shorthand if Escape Characters Default Argument Values PHP Nested if Pass by Reference String Interpolation Named Arguments PHP File Upload Variadic Functions Return Values Search in Strings Multibyte Strings Type Declarations in Functions PHP Numbers PHP Math PHP Floats PHP Random Numbers PHP Constants PHP Properties PHP Methods PHP Constructor Constructor Property Promotion PHP Cookies PHP Destructor PHP Access Modifiers Readonly Properties PHP Sessions PHP Inheritance Method Overriding PHP Filters The final Keyword CSRF Protection PHP Filters Advanced Session Security Secure Cookies PHP Magic Constants File Upload Security PHP Callback Functions PHP Operators Filesystem Security PHP JSON Arithmetic Operators Error Reporting in Production Hiding PHP Assignment Operators PHP Configuration (php.ini) Comparison Operators PHP Command Line (CLI) PHP Exceptions Increment / Decrement Operators Migrating to PHP 8 PHP Form Validation PHP Form Required PHP Form URL/E-mail Error Handling Form Input Sanitizing Escaping Output (htmlspecialchars) Custom Error Handler Checkbox, Radio and Select Inputs Sticky Forms PHP Form Complete PHP Date and Time Date Formatting Error Logging HTTP Headers and Redirects Output Buffering Sending Email PHP cURL Consuming REST APIs PHP Generators AJAX PHP AJAX Database AJAX XML AJAX Live Search AJAX Poll AJAX with JSON Security Introduction Password Hashing SQL Injection Prevention XSS Prevention Garbage Collection Project: Simple Blog PHP What is OOP PHP Classes/Objects The $this Keyword Access Array Items Update Array Items Add Array Items Remove Array Items Sorting Arrays Multidimensional Arrays Array Destructuring Array Spread Operator Search in Arrays Merge Arrays PHP Abstract Classes PHP Interfaces Polymorphism PHP Traits PHP Static Methods PHP Static Properties Late Static Binding Magic Methods Object Cloning MySQL Database MySQL Connect MySQL Create DB MySQL Create Table MySQL Insert Data MySQL Get Last ID MySQL Insert Multiple MySQL Prepared MySQL Select Data MySQL Where Debugging PHP Project: Image Upload Gallery $_SESSION $_ENV PHP RegEx RegEx Patterns Heredoc and Nowdoc RegEx Modifiers preg_match preg_replace preg_split PHP RegEx Functions Nullable Types Mixed and Never Types Nullsafe Operator PHP Attributes PHP Fibers Readonly Classes Property Hooks (PHP 8.4) Asymmetric Visibility (PHP 8.4) Reflection API SPL Data Structures Composer PHP Form Handling PDO Transactions PDO Error Handling PHP XML Parsers PHP SimpleXML Parser PHP SimpleXML - Get PHP XML Expat Parser PHP DOM Parser PHP XMLReader PHP XMLWriter AJAX Intro PHP Class Constants Encryption with Sodium Recursive Functions Variable Functions Anonymous Functions Closures Arrow Functions First-class Callable Syntax PHP Arrays Indexed Arrays Associative Arrays Create Arrays Variables Scope Static Variables Variable Variables PHP Echo / Print PHP printf / sprintf PHP Data Types PHP Booleans PHP NULL PHP Strings String Functions array_map / array_filter / array_reduce Array Functions PHP Superglobals $GLOBALS What Is `$_SERVER` ? $_REQUEST $_POST $_GET $_FILES $_COOKIE PHP Type Juggling MySQL Order By MySQL Delete Data MySQL Update Data MySQL Limit Data MySQL Joins with PHP Pagination with PHP PDO Introduction PDO Connect PDO Prepared Statements PDO Fetch Modes PSR-4 Autoloading Installing Extensions (PECL / PIE) OPcache & Performance PHP-FPM Project: Contact Form with Email Project: Login & Registration System Project: CRUD App with MySQL Project: Shopping Cart with Sessions Project: REST API with PHP DateTime Class Timezones PHP Include Include vs Require PHP File Handling PHP File Open/Read PHP File Create/Write File Delete / Rename / Copy PHP Directories PHP CSV Files
Ask about this post
AI Ask about this post

Ask questions about PHP Form Validation and get answers drawn from it.

Signed-in readers only.