web php
Form Validation
Form validation is the process of checking submitted values before the application trusts or stores them. Browser-side validation helps users, but PHP must still validate on the server because clients can send any request they want.
Good validation has three jobs: normalise harmless formatting, reject invalid values, and return useful field-specific errors so the user can fix the form without starting again.
Normalise before validating
Normalisation cleans input into the shape you want to validate. Common examples are trimming whitespace, converting empty strings to null, and limiting string length before display.
<?php
declare(strict_types=1);
$submitted = [
'name' => ' Sam ',
'email' => 'sam@example.com',
];
$name = trim((string) ($submitted['name'] ?? ''));
$email = trim((string) ($submitted['email'] ?? ''));
echo $name . ' <' . $email . '>' . PHP_EOL;
// Prints:
// Sam <sam@example.com>
Trimming is not validation. It only prepares the value for validation.
Collect field errors
Field-specific errors are easier to render beside the right form control and easier to test.
<?php
declare(strict_types=1);
/**
* @return array{values: array{name: string, email: string}, errors: array<string, string>}
*/
function validateSignup(array $submitted): array
{
$values = [
'name' => trim((string) ($submitted['name'] ?? '')),
'email' => trim((string) ($submitted['email'] ?? '')),
];
$errors = [];
if ($values['name'] === '') {
$errors['name'] = 'Name is required.';
}
if (filter_var($values['email'], FILTER_VALIDATE_EMAIL) === false) {
$errors['email'] = 'Enter a valid email address.';
}
return ['values' => $values, 'errors' => $errors];
}
$result = validateSignup(['name' => ' Sam ', 'email' => 'sam@example.com']);
echo $result['errors'] === [] ? 'Form is valid' : implode(', ', $result['errors']);
echo PHP_EOL;
// Prints:
// Form is valid
Keep the cleaned values separate from the raw request. The raw request is what the browser sent. The cleaned values are what the application may use after validation succeeds.
Validate rules that matter to the business
Validation is not only type checking. It includes product rules:
- required fields
- maximum length
- allowed values from a known list
- valid email shape
- date ranges
- password length
- file size and type
- uniqueness checks when creating accounts or slugs
- permission checks for IDs submitted in hidden fields
Hidden fields are not secure. If a form includes <input type="hidden" name="role" value="user">, a client can change it to admin. Treat hidden values as request input, not proof.
Render errors and old input safely
When validation fails, return the form with errors and safe old input. Escape values before printing them into HTML.
<?php
declare(strict_types=1);
function e(string $value): string
{
return htmlspecialchars($value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
}
$values = ['name' => 'Sam <script>', 'email' => 'bad-email'];
$errors = ['email' => 'Enter a valid email address.'];
echo '<input name="name" value="' . e($values['name']) . '">' . PHP_EOL;
echo '<p>' . e($errors['email'] ?? '') . '</p>' . PHP_EOL;
// Prints:
// <input name="name" value="Sam &lt;script&gt;">
// <p>Enter a valid email address.</p>
Validation and escaping solve different problems. Validation decides whether a value is acceptable. Escaping makes a value safe for the output context.
Common mistakes
- Relying only on HTML attributes such as
requiredortype="email". - Returning one vague error instead of field-specific messages.
- Losing all user input after one validation error.
- Trusting hidden fields for prices, roles, ownership, or permissions.
- Validating only the happy path and not testing empty or malformed input.
- Escaping input once and assuming it is safe everywhere later.
What you should be able to do
After this lesson, you should be able to normalise submitted form values, validate required fields and email addresses, collect field errors, preserve old input safely, and explain why validation must happen on the server.
Practice
Task: Validate A Signup Form
Create a PHP function that validates submitted signup form values.
Requirements
- Accept an array of submitted values.
- Normalise
nameandemailby trimming whitespace. - Require a non-empty name.
- Require a valid email address.
- Return cleaned values and field-specific errors.
- Show one valid case and one invalid case.
- Add a short note explaining why browser validation is not enough.
Check your work
The result should keep raw submitted data separate from cleaned values and should make each field error easy to render beside the matching form input.
Show solution
<?php
declare(strict_types=1);
/**
* @return array{values: array{name: string, email: string}, errors: array<string, string>}
*/
function validateSignup(array $submitted): array
{
$values = [
'name' => trim((string) ($submitted['name'] ?? '')),
'email' => trim((string) ($submitted['email'] ?? '')),
];
$errors = [];
if ($values['name'] === '') {
$errors['name'] = 'Name is required.';
}
if (filter_var($values['email'], FILTER_VALIDATE_EMAIL) === false) {
$errors['email'] = 'Enter a valid email address.';
}
return ['values' => $values, 'errors' => $errors];
}
$examples = [
['name' => ' Ada ', 'email' => 'ada@example.com'],
['name' => ' ', 'email' => 'not-an-email'],
];
foreach ($examples as $example) {
$result = validateSignup($example);
echo $result['errors'] === []
? 'valid'
: implode(' | ', $result['errors']);
echo PHP_EOL;
}
// Prints:
// valid
// Name is required. | Enter a valid email address.
Browser validation can improve the user experience, but it is not a security boundary. A client can send an empty name, malformed email, or completely different fields directly to the server, so PHP must validate before using or storing the values.