PHP
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Functions
-
Section 4: Object-Oriented PHP
-
Section 5: Working with Data
-
Section 6: Modern PHP (PHP 8)
-
Section 7: Working with Files and Networking
-
Section 8: Common PHP Frameworks Overview
-
Section 9: Tooling and Ecosystem
-
Section 10: Practical Projects
-
Section 11: Interview Practice
-
Section 12: More Standard Library
-
Section 13: Data Structures and Algorithms in PHP
-
Section 14: More Practice Exercises
-
Section 15: More Security and Best Practices
-
Section 16: More Testing and Tooling
-
Section 17: WordPress-Style CMS Concepts
-
Section 18: Advanced OOP Practice
-
Section 19: More Web Fundamentals
-
Section 20: Database Practice
-
Section 21: PHP Manual: Array Functions
-
Section 22: PHP Manual: Date and Calendar Functions
-
Section 23: PHP Manual: Filesystem and Directory Functions
-
Section 24: PHP Manual: Filter and Var Handling
-
Section 25: PHP Manual: Math Functions
-
Section 26: PHP Manual: JSON and XML
-
Section 27: PHP Manual: Network and Stream Functions
-
Section 28: PHP Manual: Error and Exception Handling
-
Section 29: PHP Manual: Output Control and Misc
-
Section 30: PHP Manual: FTP, Zip, and Mail
-
Section 31: Modern PHP Frameworks Deep Dive
-
Section 32: PHP Design Patterns
-
Section 33: More Practice Exercises
-
Section 34: PHP Performance and Deployment
-
Section 35: More Interview Practice
-
Section 36: More PHP Standard Library
-
Section 37: PHP Concurrency and Async
-
Section 38: More Web Development Practice
-
Section 39: PHP Testing Deep Dive
-
Section 40: Composer and Package Development
-
Section 41: PHP Security Deep Dive
-
Section 42: More Practical Projects
-
Section 43: Legacy PHP Maintenance
-
Section 44: More Algorithm Practice
-
Section 45: Final Practice and Review
-
Section 46: PHP for E-Commerce Patterns
-
Section 47: PHP API Design Deep Dive
-
Section 48: PHP Caching Strategies
-
Section 49: PHP Queue and Background Jobs
-
Section 50: PHP Multi-Tenancy Patterns
-
Section 51: PHP Real-Time Features
-
Section 52: PHP CMS and Content Modeling
-
Section 53: PHP Internationalization
-
Section 54: More Framework-Specific Practice
-
Section 55: PHP Legacy Code Refactoring
-
Section 56: More Practice Projects Round 2
-
Section 57: PHP Command-Line Applications
-
Section 58: PHP and Microservices
-
Section 59: More Interview and Review Round 2
67: Input Sanitization and Validation Patterns
I've spent a lot of time reviewing PRs from junior devs, and there is one pattern that pops up constantly: the belief that strip_tags() is a magic shield that makes any user input "safe." It's a dangerous assumption. I remember a project early in my career where we used a similar "just clean it" approach, and we spent an entire weekend scrubbing the database because a user found a way to bypass our filter and inject garbage into our profile fields.
// The "Naive" Approach: Don't do this
$username = strip_tags($_POST['username']);
$age = $_POST['age'];
// Imagine this goes straight into a database update
$query = "UPDATE users SET username = '$username', age = $age WHERE id = 1";
At first glance, it looks fine. We stripped the HTML tags, right? But look closer. What happens if a user sends -5 as their age? Or what if they send a username that is 10,000 characters long, blowing up our database column? Or worse, what if they send a string that strip_tags doesn't catch but still breaks our SQL query? This code is "cleaning" the data, but it isn't validating it. Cleaning is about format; validation is about truth.
The "Clean it and Hope" Fallacy
The biggest mistake you can make is treating sanitization and validation as the same thing. Sanitization is the process of cleaning input so it doesn't break your system (like removing null bytes or escaping HTML). Validation is the process of ensuring the data actually makes sense for your business logic.
In the broken example above, we sanitized the username (poorly) but completely ignored the age. If $_POST['age'] is the string "twenty", the SQL query will crash. If it's "25; DROP TABLE users;", you have a massive security hole. You can't just scrub the data; you have to prove the data is what it claims to be before it ever touches your logic.
Implementing a Validate-First Pattern
The professional way to handle this is a strict pipeline: Filter $\rightarrow$ Validate $\rightarrow$ Sanitize. I always recommend using PHP's filter_var() because it's more expressive than writing a dozen if statements and regex patterns.
// The Professional Approach
$rawUsername = $_POST['username'] ?? '';
$rawAge = $_POST['age'] ?? '';
// 1. Validation: Does the data meet our rules?
$isValidAge = filter_var($rawAge, FILTER_VALIDATE_INT, [
"options" => ["min_range" => 1, "max_range" => 120]
]);
$isValidUsername = (strlen($rawUsername) >= 3 && strlen($rawUsername) <= 20);
if (!$isValidAge || !$isValidUsername) {
die("Invalid input provided. Please check your age and username.");
}
// 2. Sanitization: Prepare the validated data for its destination
// Since we know $rawAge is an int, we can cast it.
$cleanAge = (int)$rawAge;
// For the username, we trim whitespace and prepare it for HTML output later
$cleanUsername = htmlspecialchars(trim($rawUsername), ENT_QUOTES, 'UTF-8');
Notice the difference here. We didn't just "strip" things. We asked: "Is this actually an integer between 1 and 120?" and "Is the length of this string reasonable?" Only after the data passed those tests did we bother cleaning it for storage. I find that by failing fast (the die() or returning an error), you prevent the rest of your application from having to deal with "impossible" data states.
Choosing the Right Tool for the Job
You'll find a lot of old tutorials mentioning FILTER_SANITIZE_STRING. Just a heads-up: that was deprecated in PHP 8.1. Don't use it. Instead, use a combination of trim() and htmlspecialchars() when outputting to the browser, or use prepared statements (which we've covered) when sending to a database.
- For Integers: Use
FILTER_VALIDATE_INT. It's far more reliable thanis_numeric(), which allows floats and scientific notation. - For Emails: Use
FILTER_VALIDATE_EMAIL. Don't try to write your own email regex; it's a rabbit hole of pain. - For Booleans: Use
FILTER_VALIDATE_BOOLEAN. This is great because it recognizes "1", "true", "on", and "yes" as true.
My rule of thumb: Trust nothing. Treat every single piece of data coming from $_GET, $_POST, or $_COOKIE as potentially malicious or, at the very least, completely wrong.
📋 Practical Task
Build a Robust User Registration Validator
You are tasked with creating a registration processing script. Instead of just accepting the data, you must implement a validation pipeline that rejects the request if any of the following criteria are not met:
- Username: Must be between 5 and 15 characters, alphanumeric only (no special characters).
- Age: Must be a valid integer between 18 and 99.
- Email: Must be a syntactically valid email address.
- Newsletter Opt-in: Must be a boolean value.
Requirements:
1. Create a PHP script that simulates receiving these values via $_POST.
2. Use filter_var() for the email, age, and newsletter checks.
3. Use a regular expression (preg_match) for the alphanumeric username check.
4. If any validation fails, the script should output a specific error message for that field.
5. If all validations pass, output a success message and the "sanitized" versions of the data (trimmed and escaped for HTML output).
There are no comments for now.