PHP Form Validation
The Forms & User Input page already covers sticky forms, CSRF, and PRG.
This page goes deeper into validation itself: using filter_var() with specific filters,
checking numeric ranges, writing a reusable validation function, and showing field-specific errors.
1) filter_var() With Specific Filters
filter_var() validates a value against a built-in filter and returns the cleaned value,
or false if it fails.
<?php
filter_var('a@b.com', FILTER_VALIDATE_EMAIL); // 'a@b.com'
filter_var('42', FILTER_VALIDATE_INT); // 42
filter_var('not-a-number', FILTER_VALIDATE_INT); // false
filter_var('https://example.com', FILTER_VALIDATE_URL); // the URL string
?>
2) Validating a Numeric Range
Pass an options array with min_range/max_range to
FILTER_VALIDATE_INT to enforce a range in one call.
<?php
$age = filter_var($_POST['age'], FILTER_VALIDATE_INT, [
'options' => ['min_range' => 1, 'max_range' => 120]
]);
if ($age === false) {
$errors['age'] = 'Age must be between 1 and 120.';
}
?>
3) Required-Field Checking With empty()
Always check a field is present and non-empty before running a format check on it, so you can show a clearer "required" message instead of a confusing format error.
<?php
$coupon = trim($_POST['coupon'] ?? '');
if (empty($coupon)) {
$errors['coupon'] = 'Discount code is required.';
}
?>
4) A Regex Pattern: Exactly 6 Uppercase Letters/Digits
Some fields need a custom shape that no built-in filter covers — that's where preg_match() comes in.
<?php
if (!preg_match('/^[A-Z0-9]{6}$/', $coupon)) {
$errors['coupon'] = 'Code must be exactly 6 uppercase letters/digits.';
}
?>
5) A Reusable Validation Function
Instead of scattering validation checks through the page, group them into one function that returns
[$clean, $errors] — easy to reuse and to unit-test.
<?php
function validate_demo_form(array $post): array {
$errors = [];
$clean = ['age' => '', 'website' => '', 'coupon' => ''];
// ...validate each field, fill $clean and $errors...
return [$clean, $errors];
}
?>
6) Working Demo: Age, Website & Discount Code
7) Best Practices
| Issue | Problem | Fix |
|---|---|---|
| Trusting client-side validation | Can be bypassed with dev tools/curl | Always re-validate on the server |
| One generic error message | User doesn't know which field is wrong | Keep an $errors array keyed by field |
Loose == comparisons on validated values | Type-juggling surprises | Use ===/!== after filtering |
| Re-checking format before required | Confusing "invalid format" on an empty field | Check empty() first |