PHP防SQL注入预处理语句prepare绑定参数
时间:2026-11-15 07:17 作者:emer 分类: 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']}'";
常见坑
- 只对字符串转义 addslashes,仍可能被宽字节绕过,用预处理。
- 表名、排序字段不能用占位符,需白名单校验。
- ATTR_EMULATE_PREPARES 开着等于模拟,失去真绑定意义。
- 绑定只防值,不防列名和 ORDER BY 注入。
- 字符集未设 utf8mb4,emoji 和特殊字符出错。
- 忘记 ERRMODE_EXCEPTION,错误被静默吞掉。
- 复用 stmt 时参数不要重复绑定冲突。
总结
PDO prepare + execute 绑定参数,SQL 与值分离防注入,命名/问号占位符都行,bindValue 指定类型。关闭模拟预处理。表名、排序字段走白名单,预处理保护的是值不是标识符。
遇到问题加QQ23979811 协助处理