PHP Security Basics
PHP applications sit at the boundary between untrusted user input and trusted server resources — databases, the filesystem, shell commands, and other users' sessions. Because PHP historically made it easy to interpolate raw input directly into queries, HTML, and file paths, an entire generation of vulnerabilities (SQL injection, XSS, path traversal, session fixation) grew out of convenience functions used carelessly. Modern PHP security is less about exotic attacks and more about consistently applying a small number of disciplines: never trust input, always escape output for its destination context, and never build a query or command by string concatenation.
Cricket analogy: A stadium sits at the boundary between the public crowd and the secure pitch and dressing rooms; just as stewards never let a fan wander onto the pitch unchecked, PHP code must never trust raw user input before it touches a database, filesystem, or another user's session data.
Injection: SQL, command, and beyond
Injection vulnerabilities occur whenever untrusted data is interpreted as code or syntax rather than as inert data. SQL injection is the best known, but the same class of bug applies to shell commands (exec, shell_exec), file paths (include, fopen), and even PHP's own eval(). The fix is structurally the same in every case: keep data and code separate. For SQL, that means parameterized queries via PDO; for shell commands, it means escapeshellarg() and avoiding string-built commands wherever possible; for file access, it means validating paths against an allow-list rather than trusting user-supplied filenames.
Cricket analogy: SQL injection happens when a scorer lets a spectator scribble directly onto the official scoresheet instead of filling in a controlled form; parameterized queries via PDO are the controlled scoresheet form, keeping data separate from the scoring 'syntax' just as escapeshellarg() keeps a shell command's structure safe.
Cross-site scripting (XSS) and output escaping
XSS happens when untrusted data is rendered into HTML, JavaScript, or a URL without escaping for that context. htmlspecialchars() with ENT_QUOTES and an explicit UTF-8 encoding is the baseline defense for HTML output; template engines like Blade and Twig escape by default, which is one of the strongest security arguments for using them instead of raw echo in view files. Escaping must match the output context — HTML-escaping alone does not protect a value inserted into a <script> block or a URL query string.
Cricket analogy: XSS happens when a fan's live-chat comment on a match page is rendered as raw HTML instead of escaped text, letting it inject a script; htmlspecialchars() with ENT_QUOTES is the baseline defense, and a templating engine like Blade escaping by default is why teams prefer it over raw echo in scorecard views.
Session and password security
Sessions should be regenerated on privilege change (session_regenerate_id(true)) to prevent session fixation, and session cookies should be flagged HttpOnly, Secure, and SameSite to reduce theft via XSS or cross-site requests. Passwords must never be stored in plain text or with a fast general-purpose hash like MD5 or SHA-1; PHP's built-in password_hash() (bcrypt/Argon2) is purpose-built for this, automatically salting and allowing cost tuning as hardware gets faster.
Cricket analogy: Regenerating a session ID after a scorer logs in with elevated privileges (session_regenerate_id(true)) is like the stadium issuing a fresh credential badge after promoting a volunteer to official scorer, preventing a fixed old badge from being reused; password_hash() with bcrypt is like a tamper-proof seal on the official scorebook, far stronger than a simple signature (MD5).
// Safe query, safe output, safe password check
$stmt = $pdo->prepare('SELECT id, name, password_hash FROM users WHERE email = ?');
$stmt->execute([$email]);
$user = $stmt->fetch();
if ($user && password_verify($submittedPassword, $user['password_hash'])) {
session_regenerate_id(true);
$_SESSION['user_id'] = $user['id'];
}
// Escaping output for HTML context
printf('<p>Welcome, %s</p>', htmlspecialchars($user['name'], ENT_QUOTES, 'UTF-8'));A helpful framing: treat every byte that entered your application from outside (query strings, form fields, cookies, HTTP headers, uploaded file contents, even database rows populated by another untrusted source) as hostile until proven otherwise by validation, and treat every byte leaving your application as needing context-appropriate escaping. Security bugs cluster at the places developers forget one of those two rules.
addslashes() and manual quote-escaping are not a substitute for parameterized queries or password_hash(). They handle a narrow set of characters and miss encoding-based bypasses; treat them as legacy anti-patterns, not defenses.
- Never build SQL, shell commands, or file paths by concatenating untrusted input — use parameterization or allow-lists instead.
- Escape output for its destination context: HTML, JavaScript, and URLs each require different escaping.
- Use
password_hash()/password_verify()for credentials; never MD5, SHA-1, or plain text. - Regenerate the session ID on login/privilege change to prevent session fixation.
- Set
HttpOnly,Secure, andSameSiteflags on session cookies. - Treat all external input as untrusted and validate it before use, regardless of source.
Practice what you learned
1. What is the most reliable defense against SQL injection in PHP?
2. Which PHP function should be used to hash passwords before storing them?
3. Why is `session_regenerate_id(true)` called after a successful login?
4. Escaping output with `htmlspecialchars()` protects against XSS in which context?
5. Which session cookie flags help reduce the risk of theft via XSS and cross-site requests?
Was this page helpful?
You May Also Like
Prepared Statements and SQL Injection
Understand how SQL injection attacks work and how parameterized prepared statements in PDO eliminate them by separating SQL structure from user data.
Sessions and Cookies
Learn how PHP maintains state across stateless HTTP requests using cookies for client-side storage and sessions for server-side storage keyed by a session identifier.
Form Handling and Validation
Learn a reliable pattern for processing submitted HTML forms in PHP: reading input safely, validating and sanitizing each field, and reporting errors back to the user.
Superglobals and Request Data
Explore PHP's built-in superglobal arrays that expose incoming HTTP request data, server information, and environment variables to every scope without needing to be passed or imported.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics