SQL Injection in PHP 2025: How to Protect Yourself? Complete Guide

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Introduction: Why is SQL Injection Still Relevant in 2025?



Imagine: you wrote a cool website in PHP, added a feedback form, product search, and a week later you discover that an attacker has dumped the entire customer database. Sounds like a horror story from the 2010s? Unfortunately, according to OWASP, SQL injection is still in the top 3 most dangerous web application vulnerabilities. And yes, in 2025, developers are still making this mistake.



The question "How can I prevent SQL injection in PHP?" on Stack Overflow has gathered thousands of views and hundreds of answers. But the problem isn't a lack of information — the problem is that many still use outdated methods like mysql_* functions (which were removed back in PHP 7.0) or naively rely on mysqli_real_escape_string() as a silver bullet.



In this article, we will break down the best practices for protecting against SQL injection in PHP in 2025. You will learn why prepared statements are the industry standard, how to properly work with PDO and mysqli, and what pitfalls still await inexperienced developers. Let's go!



What is SQL Injection in Simple Terms?



SQL injection is an attack where an attacker "injects" malicious SQL code into a query through user input (forms, URLs, cookies). Instead of simply passing a username, a hacker can send: ' OR '1'='1 — and gain access to all data.



Here is a classic example of vulnerable code:



// NEVER do this!$username = $_POST['username'];$password = $_POST['password'];$query = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";$result = mysqli_query($conn, $query);


If an attacker enters in the username field: admin' --, the query becomes:



SELECT * FROM users WHERE username = 'admin' --' AND password = '...'


Everything after -- is a comment. Authentication is bypassed. The database is ours. Hello, data breach!



Method #1 (and the most important): Prepared Statements



In 2025, this is the only recommended way to protect against SQL injection. Prepared statements separate SQL logic from data. You first tell the database: "Here is the query template, here are the places for variables," and then pass the data separately. The database itself escapes everything that needs escaping.



Option A: PDO (PHP Data Objects) — the modern standard



PDO supports 12 different DBMS (MySQL, PostgreSQL, SQLite, and others). If you are writing a new project in 2025 — use PDO.



<?php// Connecting to the database via PDO$dsn = 'mysql:host=localhost;dbname=testdb;charset=utf8mb4';$user = 'root';$password = '';

try { $pdo = new PDO($dsn, $user, $password); // Important: throw exceptions on errors $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);} catch (PDOException $e) { die('Connection error: ' . $e->getMessage());}

// Prepared statement with named placeholders$stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email AND status = :status');$stmt->execute([ ':email' => $_POST['email'], ':status' => 'active']);$user = $stmt->fetch(PDO::FETCH_ASSOC);

// Alternative with positional placeholders (?)$stmt = $pdo->prepare('SELECT * FROM users WHERE email = ? AND status = ?');$stmt->execute([$_POST['email'], 'active']);$user = $stmt->fetch();?>


Why is this safe? Because the data is never inserted directly into the SQL string. Even if the user passes ' OR '1'='1, PDO will pass it as a string literal, and the database will treat it exactly as a string, not as part of an SQL command.



Option B: MySQLi (MySQL Imp

Blogs

Book Recommendations