100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
PHP

PHP Security Basics

Core security practices every PHP developer must apply — input validation, output escaping, safe database access, and secure session handling.

Testing & EcosystemIntermediate10 min readJul 9, 2026
Analogies

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).

php
// 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, and SameSite flags on session cookies.
  • Treat all external input as untrusted and validate it before use, regardless of source.

Practice what you learned

Was this page helpful?

Topics covered

#PHP#PHPProgrammingStudyNotes#Programming#PHPSecurityBasics#Security#Injection#SQL#Command#StudyNotes#SkillVeris