PDO query() vs prepare()
Also Known As
PDO query method
PDO execute vs query
PDO direct query unsafe
TL;DR
PDO query() executes raw SQL immediately — prepare() parameterises it. query() must never include user-controlled values.
Explanation
PDO::query($sql) sends a full SQL string to the database and executes it immediately. Any variables interpolated into that string become part of the SQL syntax itself — the database cannot distinguish data from code, which enables SQL injection. PDO::prepare() separates SQL structure from data at the protocol level: the query is compiled first, then values are bound and transmitted separately. This guarantees that input is always treated as data, never executable SQL. query() is only safe for strictly static queries with zero dynamic input.
How It's Exploited
Attacker supplies email = ' OR 1=1 -- which turns the query into a tautology, returning all users. In authentication queries, this bypasses login checks entirely.
Common Misconception
✗ Escaping input (e.g. addslashes or manual quoting) makes query() safe. It does not — escaping is encoding-dependent, easy to bypass, and fails in edge cases. Only prepared statements enforce separation between SQL and data.
Why It Matters
Using query() with even a single user-controlled value allows attackers to modify the SQL structure — bypassing authentication, dumping entire tables, or executing destructive queries. This is one of the most common causes of full database compromise.
Common Mistakes
- Using query() with string concatenation for 'simple' lookups — still exploitable.
- Assuming internal or trusted input cannot be malicious — second-order SQL injection is common.
- Using query() for convenience instead of switching to prepared statements.
Avoid When
- Never use query() with user input, even if validated or escaped.
- Avoid query() in any context where data may originate from a database, API, or user (second-order injection risk).
When To Use
- Use query() only for completely static SQL with no variables (e.g. SELECT VERSION(), SHOW TABLES).
- Use prepare() for every query that includes external input, variables, or dynamic conditions.
Code Examples
✗ Vulnerable
// SQL injection — direct interpolation
$email = $_GET['email'];
$user = $pdo->query("SELECT * FROM users WHERE email = '$email'")->fetch();
// also unsafe — concatenation
$id = $_GET['id'];
$user = $pdo->query('SELECT * FROM users WHERE id = ' . $id)->fetch();
✓ Fixed
// query() — safe only for static SQL
$version = $pdo->query('SELECT VERSION()')->fetchColumn();
// prepare() — always for dynamic input
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email');
$stmt->execute([':email' => $email]);
$user = $stmt->fetch();
Tags
🤝 Adopt this term
£79/year · your link shown here
Added
31 Mar 2026
Edited
16 Apr 2026
Views
20
🤖 AI Guestbook educational data only
|
|
Last 30 days
Agents 0
No pings yet today
No pings yesterday
Perplexity 6
Google 3
Unknown AI 2
ChatGPT 1
Meta AI 1
Ahrefs 1
Also referenced
How they use it
crawler 13
crawler_json 1
Related categories
⚡
DEV INTEL
Tools & Severity
🔴 Critical
⚙ Fix effort: Low
⚡ Quick Fix
Replace query() with prepare()->execute() whenever a query contains any variable. Only use query() for fixed, hardcoded SQL.
📦 Applies To
PHP 5.1+
web
cli
🔗 Prerequisites
🔍 Detection Hints
$pdo->query("...{$var}...") or $pdo->query('...' . $var . '...')
Auto-detectable:
✓ Yes
semgrep
phpstan
⚠ Related Problems
🤖 AI Agent
Confidence: High
False Positives: Low
✓ Auto-fixable
Fix: Low
Context: Line
CWE-89