PHP动态构建查询语句 未选复选框触发内存错误解决方法
问题描述
我尝试动态构建查询语句,但目前遇到了执行效率相关的问题。
假设我有如下表单:
<form method="post"> <input type="checkbox" name="item[]"> <input type="checkbox" name="item[]"> <input type="checkbox" name="item[]"> <input type="checkbox" name="item_2[]"> <input type="checkbox" name="item_2[]"> <input type="checkbox" name="item_2[]"> <input type="submit"> </form>
对应的PHP代码如下:
function add_item_to_query($query) { $item_array = []; if(isset($_POST["item"])){ $query .= " AND "; foreach ($_POST["item"] as $item){ $item_array[] = "item LIKE '%$item%'"; } $query .= implode(' OR ',$item_array); } return $query; }
我使用上述代码动态生成查询语句,但当用户未勾选任何复选框时,查询构建流程会触发内存限制错误,请问该问题应当如何解决?
问题原因
触发内存错误的核心原因是代码逻辑存在漏洞:
- 代码仅判断
$_POST["item"]键是否存在,没有校验该值是否为非空数组。当使用JS序列化表单提交、或后端框架自动解析请求参数时,即使没有勾选任何复选框,也可能提交值为空数组的item参数,此时isset($_POST["item"])返回true,代码会直接向查询语句拼接AND,但后续循环不会生成任何条件片段,最终得到带悬空AND的非法SQL语句。如果程序存在SQL错误重试、递归构建查询的兜底逻辑,就会进入死循环不断占用内存,最终触发内存限制。 - 原生HTML表单提交时,未勾选任何复选框确实不会提交对应字段,这种场景下
isset判断不会进入拼接分支,但只要存在提交空数组的场景就会触发bug。
另外现有代码还存在两个严重隐患:
- 多个
OR条件没有加括号包裹,和其他AND条件拼接时会出现SQL逻辑优先级错误,查询结果不符合预期 - 直接将用户输入拼接进SQL语句,存在SQL注入风险
修复方案
- 完善参数校验:除了判断键存在,还要校验参数是数组类型且不为空,再执行条件拼接逻辑
- 修正SQL逻辑:多个
OR连接的同组条件必须用括号包裹,保证逻辑优先级正确 - 替换安全写法:使用PDO/MySQLi预处理语句传值,不要直接拼接用户输入到SQL中,避免SQL注入
修复后的参考代码:
/** * 向查询语句追加item筛选条件 * @param string $query 原始查询SQL * @param array $params 预处理绑定参数数组 * @return array 拼接后的SQL和对应参数数组 */ function add_item_to_query(string $query, array $params): array { // 多重校验:键存在、值为数组、数组非空 if (isset($_POST["item"]) && is_array($_POST["item"]) && !empty($_POST["item"])) { $conditionList = []; foreach ($_POST["item"] as $item) { // 用占位符代替直接拼接值 $conditionList[] = "item LIKE ?"; // 把通配符和值绑定到参数数组,避免注入 $params[] = "%{$item}%"; } // 同组OR条件用括号包裹,避免逻辑优先级错误 $query .= " AND (" . implode(' OR ', $conditionList) . ")"; } return [$query, $params]; }
修复后无论是否收到空数组参数,都不会生成带悬空关键字的非法SQL,从根源避免异常重试导致的内存溢出问题,同时修复了逻辑错误和安全隐患。
内容的提问来源于stack exchange,提问作者KaiqueNormal
相关产品推荐
相关产品推荐

