预处理防SQL注入因将SQL结构与用户数据分离:数据库先编译带占位符语句,再单独传参,参数值绝不执行;常见错误是误用转义函数或废弃mysql_*函数;所有含用户输入的CRUD操作均应使用,但表名、字段名等结构部分仍需白名单校验。

PHP预处理语句为什么能防SQL注入
因为预处理把「SQL结构」和「用户数据」彻底分开:数据库先编译好带占位符的语句(比如 SELECT * FROM users WHERE id = ?),再单独传入参数——参数值绝不会被当SQL代码执行,哪怕里面是 ' OR 1=1 -- 这种字符串。
常见错误现象:
用 mysqli_real_escape_string() 或拼接字符串 + 单引号包裹,看似“转义了”,但遇到宽字节、多字节编码或 LIKE 场景时仍可能绕过;mysql_* 函数已废弃,不支持预处理。
使用场景:
所有含用户输入的查询都该用,包括 INSERT、UPDATE、DELETE、SELECT,尤其带 WHERE、ORDER BY(注意:排序字段名不能用占位符,得白名单校验)。
怎么写一个安全的PDO预处理查询
PDO 是最推荐的方式,兼容性好、错误提示清晰、支持命名参数(比问号更易维护)。
实操建议:
- 连接时必须禁用模拟预处理:
$pdo = new PDO($dsn, $user, $pass, [PDO::ATTR_EMULATE_PREPARES => false]);,否则 PDO 会在客户端“假装”预处理,实际还是拼接 SQL - 参数类型别全靠
PDO::PARAM_STR,整数用PDO::PARAM_INT,避免隐式类型转换导致绕过 - 命名参数用冒号前缀,如
:id,绑定时键名要严格匹配(':id'不等于'id')
示例:
$stmt = $pdo->prepare('SELECT name FROM users WHERE status = :status AND age > :min_age');
$stmt->bindValue(':status', 'active', PDO::PARAM_STR);
$stmt->bindValue(':min_age', 18, PDO::PARAM_INT);
$stmt->execute();
mysqli 预处理容易漏掉的三个点
mysqli 比 PDO 稍繁琐,但原生支持、性能略高;问题常出在“以为写了预处理,其实没生效”。
容易踩的坑:
- 没检查
prepare()返回值,失败时返回false,但很多人直接链式调用->bind_param()导致致命错误 -
bind_param()的第一个参数是类型字符串,'s'表示字符串,'i'表示整数,'d'表示浮点数——类型错配不会报错,但可能查不到数据或类型截断 - 查询结果要用
get_result()或bind_result()取,不能直接用fetch_assoc(),否则拿不到数据
示例(带错误检查):
$stmt = $mysqli->prepare('SELECT email FROM logs WHERE user_id = ? AND created_at > ?');
if (!$stmt) die('Prepare failed: ' . $mysqli->error);
$stmt->bind_param('is', $uid, $since); // 注意类型顺序和变量顺序一致
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) { /* ... */ }
哪些地方预处理也救不了你
预处理只保护「参数值」,不保护「SQL结构本身」。一旦用户输入参与了表名、字段名、ORDER BY 子句或 UNION 分支,就又回到拼接风险区。
必须手动防御的场景:
- 动态表名/字段名:只能走白名单校验,比如
in_array($table, ['users', 'orders'], true) -
ORDER BY后的字段:用映射数组转换,$sort_map = ['name' => 'username', 'time' => 'created_at']; $order = $sort_map[$input] ?? 'id'; - 分页
LIMIT的 offset:必须强制转为(int),不能用bind_param('i', $offset)就放心——因为LIMIT ?, ?中第二个参数允许负数或极大值,需额外范围校验
复杂点在于:这些校验逻辑分散在业务各处,很容易漏掉一两个分支。只要有一个地方用了 $_GET['sort'] 直接进 SQL,整套预处理就形同虚设。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











