
本文介绍如何使用 php 预处理语句(prepared statements)对数据库中已有数值字段进行安全、原子化的累加更新,避免 sql 注入风险,并修正原始代码中拼接字符串导致的语法错误与逻辑缺陷。
本文介绍如何使用 php 预处理语句(prepared statements)对数据库中已有数值字段进行安全、原子化的累加更新,避免 sql 注入风险,并修正原始代码中拼接字符串导致的语法错误与逻辑缺陷。
在实际库存管理系统中,常需对现有数量字段(如 inhouse)执行“新增入库”类操作——即不覆盖原值,而是将用户提交的新数量与数据库当前值相加后更新。原始代码试图通过字符串拼接实现 inhouse = '$new_quantity + $in',这不仅语法错误(SQL 中无法直接解析 PHP 变量表达式),更严重的是存在高危 SQL 注入漏洞:用户可通过恶意输入(如 '1'; DROP TABLE inv_tbl; --)篡改甚至摧毁数据库。
✅ 正确做法是利用 MySQL 的原生算术更新能力配合 PHP 预处理语句,确保逻辑在数据库层原子执行,同时彻底隔离用户输入:
include("../../connection.php");
if (isset($_POST['update'])) {
$id = (int) $_POST['id']; // 强制类型转换,防御基础注入
$quantity_to_add = (int) $_POST['quantity'];
// ✅ 使用预处理语句:SQL 结构与数据参数严格分离
$stmt = $connections->prepare("UPDATE inv_tbl SET inhouse = inhouse + ? WHERE id = ?");
$stmt->bind_param("ii", $quantity_to_add, $id); // "ii" 表示两个整型参数
$stmt->execute();
// ✅ 检查执行结果,增强健壮性
if ($stmt->affected_rows > 0) {
addLog($connections, "Added stock: ID={$id}, quantity={$quantity_to_add}");
} else {
error_log("Update failed for ID: {$id}");
}
$stmt->close();
header("Location: ../stocks.php");
exit;
}
? 关键改进说明:
-
原子性保障:
inhouse = inhouse + ?由数据库直接计算,避免读-改-写(Read-Modify-Write)竞态问题; -
零 SQL 注入风险:
?占位符经预处理机制自动转义,用户输入永不参与 SQL 解析; -
类型安全:
bind_param("ii", ...)明确声明参数为整型,无效输入将被拒绝; -
防误操作:添加
$stmt->affected_rows判断,确保更新真实生效; -
资源清理:调用
$stmt->close()释放预处理资源。
⚠️ 注意事项:
- HTML 模态框中
已具备基础数字校验,但服务端仍需(int)强制转换或使用filter_var($val, FILTER_VALIDATE_INT)做二次验证; - 若
inhouse字段允许负数(如退货场景),请确认业务逻辑是否允许减法操作; - 生产环境务必开启 MySQL 严格模式(
STRICT_TRANS_TABLES),防止隐式类型转换引发意外行为。
通过以上方案,您不仅能安全、高效地实现“数值累加更新”,更构建了符合现代 Web 安全规范的数据交互范式——让数据库做它最擅长的事,让 PHP 专注流程控制与安全防护。











