Looking for a structured path? Browse all PHP lessons.
- Maintained by
- Learning Platform content team
- Reviewed by
- Learning Platform source and executable-example contract
PHP PDO prepared statements: safe queries by default
Prepared statements keep untrusted values separate from SQL syntax. That prevents an input such as ' OR 1=1 -- from changing the meaning of a query.
Unsafe string interpolation
<?php
$email = $_POST['email'] ?? '';
$sql = "SELECT id, email FROM users WHERE email = '$email'";
Quoting the value yourself is not a defense. The input can contain quote characters and SQL tokens.
Prepare, bind, execute
<?php
$pdo = new PDO('sqlite::memory:', null, null, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);
$pdo->exec('CREATE TABLE users (id INTEGER PRIMARY KEY, email TEXT)');
$pdo->exec("INSERT INTO users (email) VALUES ('ada@example.test')");
$statement = $pdo->prepare(
'SELECT id, email FROM users WHERE email = :email'
);
$statement->execute(['email' => 'ada@example.test']);
$user = $statement->fetch(PDO::FETCH_ASSOC);
echo $user['email'];
Expected output:
ada@example.test
Use positional ? or named :email placeholders consistently. Binding an integer with PDO::PARAM_INT is useful when the driver would otherwise infer it as a string.
Identifiers are different
Placeholders represent data values, not table names, column names, or ASC/DESC. For dynamic ordering, map a small public option to an allowlisted SQL fragment:
<?php
$columns = ['newest' => 'created_at DESC', 'name' => 'name ASC'];
$order = $columns[$_GET['order'] ?? 'newest'] ?? $columns['newest'];
$sql = "SELECT id, name FROM users ORDER BY $order";
echo $sql;
Failure modes
Do not log DSNs, passwords, full exception traces, or query values in a public response. Return a fixed error to the client and keep sanitized diagnostics in protected logs. Prepared statements also do not replace authorization: a safe query can still expose another user's row if its access rule is wrong.
Practice with Working With Databases, review Auth and Security, and use the PHP playground for syntax-only examples.