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
$comment = '<script>alert("hi")</script>';
echo htmlspecialchars($comment, ENT_QUOTES, 'UTF-8');<script>alert("hi")</script>
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 $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 $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.