PHPInput Sanitization & Filtering

Input Sanitization & Filtering

"Sanitization" and "validation" get used almost interchangeably in casual conversation, but they solve two different problems. Validation asks "is this value acceptable?" and rejects it if not. Sanitization asks "how do I make this value safe to use in a particular context?" and transforms it rather than rejecting it. Keeping the two mental models separate is what prevents the most common security mistakes in form-heavy PHP code.

htmlspecialchars() escapes for output

htmlspecialchars() converts characters that have special meaning in HTML — <, >, &, quotes — into their entity equivalents, so a string is displayed as literal text instead of being interpreted as markup. This is an output concern: it matters at the moment you are about to print a value into an HTML document, regardless of where that value came from.

Escaping user input at output time

PHP
<?php
$comment = '<script>alert("hi")</script>';

echo htmlspecialchars($comment, ENT_QUOTES, 'UTF-8');
&lt;script&gt;alert(&quot;hi&quot;)&lt;/script&gt;
filter_var() with FILTER_SANITIZE_* transforms input

filter_var() can also run in "sanitize" mode, using filters such as FILTER_SANITIZE_FULL_SPECIAL_CHARS or FILTER_SANITIZE_NUMBER_INT to strip or encode characters that do not belong in a given context. Sanitize filters do not tell you whether a value is valid — they reshape it, silently dropping or encoding characters along the way, which is a different job from FILTER_VALIDATE_EMAIL rejecting a bad address outright.

Sanitizing versus validating the same input

PHP
<?php
$raw = 'phone: (555) 123-4567 ext. 9';

$digitsOnly = filter_var($raw, FILTER_SANITIZE_NUMBER_INT);
echo $digitsOnly;
5551234567 9
Trimming and normalizing

Beyond escaping and filtering, small normalization steps make later comparisons and storage more reliable: trim() removes stray leading/trailing whitespace a visitor might paste in, and mb_strtolower() normalizes case for values like email addresses where case should not matter for comparison.

Trimming and normalizing before storing

PHP
<?php
$email = $_POST['email'] ?? '';
$normalizedEmail = mb_strtolower(trim($email));

echo $normalizedEmail;
aisha@example.com
Sanitize on output, validate on input

The mental model that keeps this straight: validate data as it enters your application, deciding whether to accept or reject it based on the rules of your domain (a valid email, a positive integer). Sanitize/escape data as it leaves your application into a specific context — HTML, a SQL query, a shell command — using the escaping mechanism appropriate to that exact context.

  • On the way in: validate with filter_var(..., FILTER_VALIDATE_*), reject or re-prompt on failure.

  • On the way out to HTML: escape with htmlspecialchars().

  • On the way out to a SQL query: use prepared statements with bound parameters, never string concatenation.

  • Never rely on a single sanitize step performed once at input time to protect every later use of that value.

Sanitizing on input is not a substitute for escaping on output
Running a value through a `FILTER_SANITIZE_*` filter once when it arrives does not make it permanently "safe." The same string might need to be escaped differently depending on whether it ends up in an HTML attribute, a URL, or a JSON payload. Always escape immediately before output, for the specific context you are writing into.
Tip
Store data close to how the visitor typed it (after trimming and basic normalization), and apply the correct escaping function at each output site. This keeps your stored data reusable across different contexts — an admin dashboard, an API response, an email — without baking in assumptions about a single destination.