security
Validation And Normalisation
Validation decides whether input is acceptable. Normalisation converts an accepted representation into the consistent shape the application uses internally.
What Matters
- Normalise deliberately: trim surrounding whitespace, standardise case where appropriate, and parse typed values.
- Validate after the transformation that matters to the business rule.
- Do not silently repair ambiguous input when rejecting it would be safer.
- Keep normalisation rules consistent across forms, APIs, imports, and background jobs.
- Do not normalise secrets such as passwords unless the authentication design explicitly requires it.
Practical Example
<?php
declare(strict_types=1);
function normaliseEmail(string $email): string
{
return strtolower(trim($email));
}
function isValidEmail(string $email): bool
{
return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
}
$email = normaliseEmail(' AMO@Example.COM ');
echo $email . PHP_EOL;
echo isValidEmail($email) ? 'valid' : 'invalid';
echo PHP_EOL;
// Prints:
// amo@example.com
// valid
In Application Work
A common maintenance bug is applying different rules in registration, profile editing, and CSV import. Central domain-level input helpers reduce those inconsistencies.
Order Matters
Validate the value that the application will actually use. If surrounding whitespace is irrelevant, trim before checking whether a required value is empty. If email comparison is case-insensitive for your product, normalise before checking for duplicates.
Do not over-normalise. Rewriting punctuation, silently truncating values, or changing user text can hide mistakes and create collisions. Reject input when the intended correction is ambiguous.
Passwords Are Different
Passwords should normally be treated as opaque strings. Do not trim them or lowercase them automatically. A leading space may be intentional, and changing it would mean the application hashes a value the user did not submit.
<?php
declare(strict_types=1);
$submittedPassword = ' leading-space-is-part-of-this-password';
echo strlen($submittedPassword) . PHP_EOL;
// Prints:
// 39
Validate password policy separately, then pass the original accepted password to password_hash().
Keep Raw Values When Auditing Matters
An import pipeline may need the original row for diagnostics and the cleaned value for application use. Keeping both makes support work easier without forcing the rest of the application to handle messy external representations.
What To Check
Before moving on, make sure you can:
- describe the difference between validation and normalisation;
- normalise values only when the rule is deliberate;
- reject ambiguous invalid input;
- keep the same domain rules across entry points;
- explain why secrets such as passwords need special handling.
Practice
Practice: Normalise A Profile Update
Build a profile-input helper for display name, email address, and newsletter preference.
Requirements
- Trim display name and email address.
- Lowercase the email address.
- Validate email and require a non-empty display name.
- Convert the newsletter value to a boolean only when it is recognised.
Show solution
The helper returns one consistent internal shape.
<?php
declare(strict_types=1);
function normaliseProfile(string $name, string $email, mixed $newsletter): array
{
$name = trim($name);
$email = strtolower(trim($email));
$allowedNewsletterValues = ['0' => false, '1' => true];
$errors = [];
if ($name === '') {
$errors[] = 'display name is required';
}
if (filter_var($email, FILTER_VALIDATE_EMAIL) === false) {
$errors[] = 'email address is invalid';
}
if (!is_string($newsletter) || !array_key_exists($newsletter, $allowedNewsletterValues)) {
$errors[] = 'newsletter preference is invalid';
}
return $errors === []
? ['valid' => true, 'name' => $name, 'email' => $email, 'newsletter' => $allowedNewsletterValues[$newsletter]]
: ['valid' => false, 'errors' => $errors];
}
$profile = normaliseProfile(' Amo ', ' AMO@Example.COM ', '1');
echo $profile['name'] . PHP_EOL;
echo $profile['email'] . PHP_EOL;
echo $profile['newsletter'] ? 'subscribed' : 'not subscribed';
echo PHP_EOL;
// Prints:
// Amo
// amo@example.com
// subscribed
Normalisation makes later code simpler because later code receives one expected representation.