如何在SQL命令中传入参数?PHP PDO动态参数传递实现问询
问题修复与优化方案
先直接点明你代码里的核心问题,再给出修正后的版本:
核心问题点
- WHERE子句字段名错误:你把变量
$villageID和$fabrik当成数据库字段名来写了,实际应该用表中真实的字段名(比如villageID和fabrik),变量是用来传值的,不是字段名。 - SQL注入风险:直接把
$res拼进SQL语句,要是传入恶意字符串会触发注入攻击,必须先校验这个参数是否为合法列名。 - 参数传递顺序错误:UPDATE语句里
SET$res= ?对应的是资源的数值,但你现在传的是$res本身;WHERE条件的参数顺序也和SQL占位符不匹配。 - 冗余查询:先SELECT再UPDATE完全没必要,直接在UPDATE里加
villageID = ? AND ownerID = ?的条件,既能完成存在性校验,还能避免并发场景下的数据不一致。
修正后的代码
public function setVillageRes(int $villageID, int $ownerID, string $res, int $fabrik, int $resValue){ // 校验$res是否为允许的列名,防止SQL注入 $allowedColumns = ['wood', 'stone', 'iron', 'gold']; // 替换成你实际的资源列名 if(!in_array($res, $allowedColumns)){ return "RE-3002"; // 非法列名错误码 } // 直接用UPDATE加条件,无需先查询 $sql = "UPDATE village SET `$res` = ? WHERE villageID = ? AND ownerID = ? AND fabrik = ?"; $stmt = $this->pdo->prepare($sql); // 参数顺序严格对应SQL占位符:资源值 -> 村庄ID -> 所有者ID -> 工厂ID $stmt->execute([$resValue, $villageID, $ownerID, $fabrik]); // 通过受影响行数判断村庄是否存在 if($stmt->rowCount() === 0){ return "RE-3001"; } return true; // 更新成功返回标识 }
关键改进说明
- 列名白名单校验:用
$allowedColumns限制$res的取值范围,彻底杜绝列名注入风险,同时确保传入的参数是业务中真实存在的资源字段。 - 合并逻辑减少查询:去掉多余的SELECT操作,直接用UPDATE的条件判断目标村庄是否存在,通过
rowCount()检查修改行数,效率更高也更安全。 - 修正参数传递:新增
$resValue参数传递要设置的资源数值,参数顺序严格对应SQL占位符,避免赋值错误。 - 字段名规范:WHERE子句使用正确的字段名,变量只用来传值,不再混淆字段名与变量。
内容的提问来源于stack exchange,提问作者dispoIT
相关产品推荐
相关产品推荐

