PHP防SQL注入预处理语句prepare绑定参数 PHP

前言

把用户输入直接拼进 SQL 是 SQL 注入的根源。预处理语句(prepared statement)把 SQL 和参数分开传输,占位符绑定值,从根本上杜绝注入。本文讲解 PDO 预处理、绑定参数、不同占位符类型和错误示范对照。

操作步骤

1. PDO 连接(开启模拟关闭)

$pdo = new PDO('mysql:host=127.0.0.1;dbname=test;charset=utf8mb4', 'root', 'pwd', [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_EMULATE_PREPARES => false,
]);

2. 问号占位符绑定

$stmt = $pdo->prepare('SELECT * FROM users WHERE id = ?');
$stmt->execute([$_GET['id']]);
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

3. 命名占位符

$stmt = $pdo->prepare('SELECT * FROM users WHERE name = :name');
$stmt->execute([':name' => $_POST['name']]);

4. 绑定参数指定类型

$stmt = $pdo->prepare('INSERT INTO users(name,age) VALUES(?,?)');
$stmt->bindValue(1, $name, PDO::PARAM_STR);
$stmt->bindValue(2, $age, PDO::PARAM_INT);
$stmt->execute();

5. 错误写法(禁止)

// 危险:直接拼接
$sql = "SELECT * FROM users WHERE name = '{$_POST['name']}'";

常见坑

  1. 只对字符串转义 addslashes,仍可能被宽字节绕过,用预处理。
  2. 表名、排序字段不能用占位符,需白名单校验。
  3. ATTR_EMULATE_PREPARES 开着等于模拟,失去真绑定意义。
  4. 绑定只防值,不防列名和 ORDER BY 注入。
  5. 字符集未设 utf8mb4,emoji 和特殊字符出错。
  6. 忘记 ERRMODE_EXCEPTION,错误被静默吞掉。
  7. 复用 stmt 时参数不要重复绑定冲突。

总结

PDO prepare + execute 绑定参数,SQL 与值分离防注入,命名/问号占位符都行,bindValue 指定类型。关闭模拟预处理。表名、排序字段走白名单,预处理保护的是值不是标识符。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-11-15 07:17 
'); })();