How to Prevent SQL Injection in PHP
What is SQL Injection?
SQL Injection is a type of cyberattack where a malicious user can inject harmful SQL statements into a query by manipulating user inputs.
Example:
$username = $_GET['user'];
$password = $_GET['pass'];
$query = "SELECT * FROM users WHERE username='$username' AND password='$password'";
If a hacker inputs:
username: admin' --
password: anything
The query becomes:
SELECT * FROM users WHERE username='admin' -- ' AND password='anything'
The -- makes everything after it a comment, allowing the attacker to bypass authentication.
How SQL Injection Works (Real Examples)
Classic Injection
$sql = "SELECT * FROM users WHERE id = '$id'";
If the attacker inputs 1 OR 1=1, the query becomes:
SELECT * FROM users WHERE id = '1 OR 1=1'
This returns all users, breaking data confidentiality.
Dangers of SQL Injection Attacks
- Unauthorized data access
- User impersonation
- Database deletion
- Server compromise
- Financial loss
SQL injection remains in the OWASP Top 10 threats.
Why SQL Injection Happens in PHP
- Directly inserting user input into SQL queries
- Not using prepared statements
- Failing to validate and sanitize inputs
- Poor coding practices and lack of awareness
Top 10 Ways to Prevent SQL Injection in PHP
- Use Prepared Statements (MySQLi or PDO)
- Sanitize user input with filter_var()
- Validate data types (integers, emails, etc.)
- Use parameterized queries only
- Hide SQL errors (disable display_errors in production)
- Use stored procedures when needed
- Use strong DB privileges (LIMIT user access)
- Perform regular code audits
- Escape output (not just input)
- Never trust user input — always verify
Prevent SQL Injection in PHP Using MySQLi
Vulnerable Code (DON'T do this)
$id = $_GET['id'];
$result = $conn->query("SELECT * FROM users WHERE id = $id");
Secure Code Using MySQLi (Object-Oriented)
$stmt = $conn->prepare("SELECT * FROM users WHERE id = ?");
$stmt->bind_param("i", $id); // "i" means integer
$stmt->execute();
$result = $stmt->get_result();
Prevent SQL Injection in PHP Using PDO
Vulnerable Code (DON'T do this)
$sql = "SELECT * FROM users WHERE name = '$name'";
Secure Code Using PDO
$stmt = $pdo->prepare("SELECT * FROM users WHERE name = ?");
$stmt->execute([$name]);
Or with named parameters:
$stmt = $pdo->prepare("SELECT * FROM users WHERE name = :name");
$stmt->bindParam(':name', $name, PDO::PARAM_STR);
$stmt->execute();
MySQLi vs PDO - SQL Injection Safe Examples
Operation | MySQLi Secure Code | PDO Secure Code |
---|---|---|
Insert | $stmt = $conn->prepare("INSERT INTO ...") | $stmt = $pdo->prepare("INSERT INTO ...") |
Select | $stmt->bind_param("i", $id); | $stmt->bindParam(':id', $id, PDO::PARAM_INT); |
Update | $stmt = $conn->prepare("UPDATE ...") | $stmt->execute([$name, $id]); |
Delete | $stmt = $conn->prepare("DELETE FROM ...") | $stmt = $pdo->prepare("DELETE FROM ...") |
Input Validation and Sanitization in PHP
Use filter_input() or filter_var() to sanitize inputs:
$name = filter_input(INPUT_POST, 'name', FILTER_SANITIZE_STRING);
$email = filter_var($_POST['email'], FILTER_SANITIZE_EMAIL);
$age = filter_var($_POST['age'], FILTER_VALIDATE_INT);
Never rely on front-end validation alone — always validate again on the server.
Use Stored Procedures for Extra Protection
Stored procedures are SQL functions stored in the database. They're harder to inject into.
CREATE PROCEDURE GetUserById(IN uid INT)
BEGIN
SELECT * FROM users WHERE id = uid;
END;
Call from PHP:
$stmt = $pdo->prepare("CALL GetUserById(?)");
$stmt->execute([$id]);
SQL Injection Testing Tools
- SQLMap (penetration testing tool)
- Burp Suite (intercept input/output)
- Hackbar (browser extension)
- Wapiti / OWASP ZAP
Test your apps regularly to detect vulnerabilities.
Preventing SQL Injection in PHP Login Systems
Login systems are primary targets for SQLi attacks.
Unsafe Login Code
$query = "SELECT * FROM users WHERE username = '$user' AND password = '$pass'";
Secure Login Code with PDO
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ? AND password = ?");
$stmt->execute([$user, $pass]);
Better yet — hash passwords:
$password = password_hash($pass, PASSWORD_DEFAULT);
// And use password_verify() during login
Common Mistakes That Lead to SQL Injection
- Using string concatenation in queries
- Skipping prepared statements for simple queries
- Trusting $_GET or $_POST blindly
- Echoing raw SQL errors
- Relying only on client-side validation
FAQs About Preventing SQL Injection in PHP
Q1. Is prepared statement 100% safe from SQL injection?
Yes, if used correctly. It separates query logic from user data completely.
Q2. What is the best way to prevent SQL injection in PHP?
Use prepared statements with PDO or MySQLi, along with input validation.
Q3. Can SQL injection happen with PDO?
Only if you build dynamic queries using string concatenation. Otherwise, PDO with placeholders is safe.
Q4. Should I use mysqli_real_escape_string()?
It's better than nothing, but it's not foolproof. Prepared statements are superior.
Q5. Can stored procedures be injected?
Yes, if you're passing unvalidated inputs. But they're harder to exploit.
Final Thoughts & Best Practices
SQL injection can destroy your entire application. By following these best practices:
- Always use prepared statements
- Validate and sanitize every input
- Avoid displaying raw database errors
- Never trust user input
- Test regularly for vulnerabilities