SQL injection is one of the most dangerous web security vulnerabilities. Attackers can use it to steal, modify, or delete data from your database π±. But donβt worry! You can completely prevent SQL injection using prepared statements in PHP.
In this step-by-step guide, youβll learn:
β
What SQL injection is and how it works
β
How to prevent it using prepared statements (PDO & MySQLi)
β
Real-world examples and a mini-project
Letβs secure your PHP applications! ππ
π― What Is SQL Injection?
SQL Injection (SQLi) is a hacking technique where attackers inject malicious SQL code into input fields to manipulate the database.
β Example of a Vulnerable Query
<?php
$conn = new mysqli("localhost", "root", "", "zeroexp_dev");
$username = $_GET['username']; // Unsafe user input
$password = $_GET['password']; // Unsafe user input
$query = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";
$result = $conn->query($query);
?>
If a hacker enters:
username: ' OR 1=1 --
password: (anything)
The query becomes:
SELECT * FROM users WHERE username = '' OR 1=1 --' AND password = ''
π¨ What happens?
1=1
always evaluates to true.- The attacker logs in as ANY user without knowing the password!
1οΈβ£ Preventing SQL Injection Using PDO (Recommended)
The best way to prevent SQL injection is by using prepared statements with PDO (PHP Data Objects).
Safe Login Query (Using PDO)
<?php
$pdo = new PDO("mysql:host=localhost;dbname=zeroexp_dev;charset=utf8", "root", "");
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$username = $_POST['username'] ?? '';
$password = $_POST['password'] ?? '';
// Use prepared statement
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ? AND password = ?");
$stmt->execute([$username, $password]);
if ($stmt->rowCount() > 0) {
echo "Login successful!";
} else {
echo "Invalid credentials!";
}
?>
π₯ Why is this secure?
β
Uses ?
placeholders (not raw input)
β
Prevents SQL injection automatically
β
More efficient than manual escaping
2οΈβ£ Preventing SQL Injection Using MySQLi (Alternative)
If you're using MySQLi, you can still use prepared statements.
Safe Login Query (Using MySQLi)
<?php
$conn = new mysqli("localhost", "root", "", "zeroexp_dev");
$username = $_POST['username'] ?? '';
$password = $_POST['password'] ?? '';
// Use prepared statement
$stmt = $conn->prepare("SELECT * FROM users WHERE username = ? AND password = ?");
$stmt->bind_param("ss", $username, $password);
$stmt->execute();
$result = $stmt->get_result();
if ($result->num_rows > 0) {
echo "Login successful!";
} else {
echo "Invalid credentials!";
}
?>
π₯ Why is this secure?
β
Uses ?
placeholders
β
bind_param() prevents SQL injection
β
More secure than using raw queries
3οΈβ£ Avoiding Common SQL Injection Mistakes
β Never Concatenate User Input in Queries
$query = "SELECT * FROM users WHERE username = '$username'"; // β Bad practice!
β Always Use Prepared Statements Instead
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ?");
β Never Trust GET/POST Data Without Validation
$username = $_GET['username']; // β Unsafe
β Sanitize User Input First
$username = filter_input(INPUT_POST, "username", FILTER_SANITIZE_STRING);
4οΈβ£ Secure Insert, Update, and Delete Queries
1οΈβ£ Safe Insert Query
<?php
$stmt = $pdo->prepare("INSERT INTO users (username, email, password) VALUES (?, ?, ?)");
$stmt->execute(["zerodev", "contact@zeroexp.dev", "securepassword"]);
?>
2οΈβ£ Safe Update Query
<?php
$stmt = $pdo->prepare("UPDATE users SET email = ? WHERE username = ?");
$stmt->execute(["newemail@zeroexp.dev", "zerodev"]);
?>
3οΈβ£ Safe Delete Query
<?php
$stmt = $pdo->prepare("DELETE FROM users WHERE username = ?");
$stmt->execute(["zerodev"]);
?>
π₯ Why use prepared statements?
β
No SQL injection risk
β
Works with all queries (SELECT, INSERT, UPDATE, DELETE)
β
More secure and efficient
π― Mini Project: Secure Login System
Letβs build a real-world login system that:
β
Uses prepared statements
β
Prevents SQL injection
β
Secures user authentication
1οΈβ£ login.php (User Login Form)
<form action="login_process.php" method="post">
Username: <input type="text" name="username"><br>
Password: <input type="password" name="password"><br>
<input type="submit" value="Login">
</form>
2οΈβ£ login_process.php (Handles Login Securely)
<?php
session_start();
require "db.php"; // Database connection
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$username = trim($_POST["username"] ?? '');
$password = trim($_POST["password"] ?? '');
if (empty($username) || empty($password)) {
die("Both fields are required!");
}
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ? AND password = ?");
$stmt->execute([$username, $password]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
if ($user) {
$_SESSION["username"] = $username;
header("Location: dashboard.php");
} else {
echo "Invalid login!";
}
}
?>
3οΈβ£ dashboard.php (User Dashboard)
<?php
session_start();
if (!isset($_SESSION["username"])) {
echo "Access denied! <a href='login.php'>Login here</a>";
exit;
}
echo "Welcome, " . $_SESSION["username"] . "! <a href='logout.php'>Logout</a>";
?>
4οΈβ£ logout.php (Log Out the User)
<?php
session_start();
session_unset();
session_destroy();
header("Location: login.php");
?>
π₯ Whatβs Happening?
login.php
provides a secure login form.login_process.php
validates credentials using prepared statements.dashboard.php
only allows logged-in users.logout.php
destroys the session, logging the user out.
π You now have a fully secure login system!
π Final Thoughts
Now you know how to protect your PHP applications from SQL injection!
β
Use PDO or MySQLi prepared statements
β
Never trust user input
β
Secure all CRUD operations
π Next: Build a Simple Login System with PHP and MySQL
Happy coding! ππ