空数组本身不导致SQL注入,风险源于其参与字符串拼接或预处理配置不当;应仅作参数容器、全程预处理、禁用模拟、字段白名单校验。

定义空数组本身不会导致 SQL 注入,它只是一个数据结构操作。但在旧系统(如 PHP 5.6)中,空数组常被误用于拼接查询、动态构建 WHERE 条件或作为 bind_param 的参数源,此时若处理不当,会间接引发注入风险。关键不是“定义空数组”,而是它后续如何参与 SQL 构建。
下面聚焦实际维护场景中的规范操作:
避免用空数组触发危险的字符串拼接
常见错误:把空数组当作“默认条件容器”,再用 implode() 拼进 SQL 字符串:
✘ 危险写法(即使数组为空,逻辑脆弱):$where = [];<br>if (!empty($_GET['status'])) {<br> $where[] = "status = '{$_GET['status']}'"; // 直接拼接!<br>}<br>$sql = "SELECT * FROM orders WHERE 1=1" . (count($where) ? " AND " . implode(' AND ', $where) : '');
立即学习“PHP免费学习笔记(深入)”;
→ 一旦某处漏校验,$_GET['status'] 含 ' OR 1=1 -- 就直接注入。
- 初始化空数组只用于存待绑定的值,不参与 SQL 字符串拼接
- WHERE 条件模板应提前写死占位符,或用白名单映射字段名
- 示例(PDO):
$params = [];<br>$conditions = [];<br><br>if (!empty($_GET['status']) && in_array($_GET['status'], ['pending','shipped','cancelled'])) {<br> $conditions[] = "status = ?";<br> $params[] = $_GET['status'];<br>}<br><br>$sql = "SELECT * FROM orders WHERE 1=1";<br>if (!empty($conditions)) {<br> $sql .= " AND " . implode(' AND ', $conditions);<br>}<br><br>$stmt = $pdo->prepare($sql);<br>$stmt->execute($params); // 安全绑定PHP 5.6 下预处理必须显式禁用模拟(关键!)
PHP 5.6 默认可能启用 PDO::ATTR_EMULATE_PREPARES => true,此时 prepare 只是客户端字符串替换,空数组传进去也救不了你。
$pdo = new PDO($dsn, $user, $pass, [<br> PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,<br> PDO::ATTR_EMULATE_PREPARES => false, // ← 必须加这一行<br> PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4"<br>]);
验证是否生效:var_dump($pdo->getAttribute(PDO::ATTR_EMULATE_PREPARES)); // 应输出 bool(false)
空数组用于 bind_param 时注意引用与类型(MySQLi 场景)
若用 MySQLi 且需动态绑定(如条件数不确定),不能直接传空数组给 bind_param() —— 它不接受空参列表。
- 条件为空时,改用固定语句(如
"SELECT * FROM table") - 条件非空时,用
call_user_func_array()动态绑定,但必须确保:
✓ 所有变量已声明并赋值(不能是未定义变量)
✓ 类型字符串严格匹配('s','i'等)
✓ PHP 5.6 中仍需显式传引用:call_user_func_array([$stmt, 'bind_param'], $refs),其中$refs是引用数组
标识符(表名/字段名)永远不用数组“兜底”,必须白名单
有人试图用空数组接收用户传入的排序字段:$sort_fields = []; $sort_fields[] = $_GET['sort']; → 然后拼进 ORDER BY {$sort_fields[0]}。这毫无防护意义。
$allowed_sort = ['id', 'created_at', 'amount'];<br>$sort = isset($_GET['sort']) && in_array($_GET['sort'], $allowed_sort) ? $_GET['sort'] : 'id';<br>$sql = "SELECT * FROM orders ORDER BY `$sort` DESC"; // 字段名加反引号,且来自白名单
→ 白名单校验必须在拼接前完成,空数组在这里不承担任何安全职责。



















