PHP MySQL Prepared Statements
In this page:
$stmt = mysqli_prepare($conn, "SELECT * FROM table_name WHERE column = ?");
mysqli_stmt_bind_param($stmt, "s", $value); // s = string, i = integer
mysqli_stmt_execute($stmt);
Why Prepared Statements Exist
Directly building SQL by concatenating a variable into the query string, like "SELECT * FROM users WHERE name = '$name'", lets an attacker supply a value like '; DROP TABLE users; -- that changes the query's actual meaning.
Prepared statements prevent this by sending the SQL template and the values as two entirely separate things.
Example: Why Prepared Statements Exist
<?php
$name = "Robert'); DROP TABLE users; --";
// Never do: "SELECT * FROM users WHERE name = '$name'"
echo "The SQL template and the value are sent separately instead";
?>
Login to try C/C++/Java/PHP code in the editor
Preparing a Statement with Placeholders
mysqli_prepare($conn, $sql) compiles a SQL statement containing one or more ? placeholders in place of the actual values, returning a statement object you will attach real values to and then execute -- the placeholders mark exactly where values belong without specifying what they are yet.
Example: Preparing a Statement with Placeholders
<?php
$db = new SQLite3(':memory:');
$db->exec("CREATE TABLE users (name TEXT)");
$stmt = $db->prepare("INSERT INTO users (name) VALUES (?)"); // mysqli_prepare($conn, $sql)
echo "Statement compiled with a placeholder";
?>
Login to try C/C++/Java/PHP code in the editor
Binding Values with bind_param
mysqli_stmt_bind_param($stmt, $types, ...$values) attaches actual values to a prepared statement's placeholders, in order -- the $types string tells MySQL each value's kind: "i" for integer, "d" for double/float, "s" for string, and "b" for binary blob data.
Example: Binding Values with bind_param
<?php
$db = new SQLite3(':memory:');
$db->exec("CREATE TABLE users (id INTEGER, name TEXT)");
$stmt = $db->prepare("INSERT INTO users (id, name) VALUES (?, ?)");
$stmt->bindValue(1, 1, SQLITE3_INTEGER); // like "i" in mysqli's bind_param
$stmt->bindValue(2, "Alice", SQLITE3_TEXT); // like "s"
$stmt->execute();
echo "Values bound by type";
?>
Login to try C/C++/Java/PHP code in the editor
Executing and Retrieving Results
mysqli_stmt_execute($stmt) runs the prepared statement with its bound values, and mysqli_stmt_get_result($stmt) converts the statement's result into a regular result set you can loop over with the same fetch functions used for a plain query, like mysqli_fetch_assoc().
Example: Executing and Retrieving Results
<?php
// Create a new `SQLite3` instance with ':memory:', stored in `$db`
$db = new SQLite3(':memory:');
$db->exec("CREATE TABLE users (name TEXT)");
$db->exec("INSERT INTO users (name) VALUES ('Alice')");
// Declare `$stmt`, set to `$db->prepare("SELECT * FROM users WHERE name = ?")`
$stmt = $db->prepare("SELECT * FROM users WHERE name = ?");
$stmt->bindValue(1, "Alice", SQLITE3_TEXT);
// Declare `$result`, set to `$stmt->execute()`
$result = $stmt->execute();
// Print a human-readable dump of `$result->fetchArray(SQLITE3_ASSOC)`
print_r($result->fetchArray(SQLITE3_ASSOC));
?>
Login to try C/C++/Java/PHP code in the editor
Reusing a Prepared Statement
A single prepared statement can be executed multiple times with different bound values, without re-preparing it each time -- just call bind_param (or rebind) and execute again for each new set of values, which is both safer and faster than preparing a fresh statement per call.
Example: Reusing a Prepared Statement
<?php
$db = new SQLite3(':memory:');
$db->exec("CREATE TABLE users (name TEXT)");
$stmt = $db->prepare("INSERT INTO users (name) VALUES (?)");
foreach (["Alice", "Bob", "Carol"] as $name) {
$stmt->bindValue(1, $name, SQLITE3_TEXT);
$stmt->execute(); // same statement, new values each time
}
echo "3 rows inserted with one prepared statement";
?>
Login to try C/C++/Java/PHP code in the editor
- Skipping prepared statements for a query because the input 'seems safe', when any value originating from a user, even indirectly, should be treated as untrusted.
- Forgetting to specify the correct type string (s, i, d, b) when calling bind_param, causing values to be interpreted incorrectly.
- Mixing manually escaped, concatenated SQL with prepared statement placeholders in the same query, defeating the safety prepared statements are meant to provide.
- mysqli_prepare($conn, $sql) compiles a SQL statement with ? placeholders where values will go, before any actual data is attached.
- mysqli_stmt_bind_param($stmt, $types, ...$values) attaches real values to the placeholders, with a type string indicating each value's kind.
- The database engine keeps the SQL structure and the bound values strictly separate, making SQL injection through bound values structurally impossible.
Prepared statements have been supported by mysqli since PHP 5, and are considered the standard, safe way to run parameterized queries.
Chapter Quiz — Complete all 21 topics to unlock
0/21 topics done
Complete these topics first:
- PHP MySQL Introduction
- PHP MySQLi Connection
- PHP PDO Introduction
- PHP CRUD Operations
- PHP Prepared Statements
- PHP Stored Procedures
- PHP Transactions
- PHP Error Handling in DB
- PHP MySQL Connect
- PHP MySQL Create DB
- PHP MySQL Create Table
- PHP MySQL Insert Data
- PHP MySQL Get Last ID
- PHP MySQL Insert Multiple
- PHP MySQL Prepared Statements
- PHP MySQL Select Data
- PHP MySQL Where
- PHP MySQL Order By
- PHP MySQL Delete Data
- PHP MySQL Update Data
- PHP MySQL Limit Data