一、为什么链式调用是安全的?
ThinkPHP 的查询构建器会对所有传入的参数进行参数绑定(预处理),而非直接拼接 SQL 字符串。例如:
php
// 安全:框架会自动参数绑定
Db::name('user')->where('id', $id)->select();
// 生成的 SQL 类似:SELECT * FROM `user` WHERE `id` = :id
// 参数 :id 会通过 PDO 预处理机制传入,避免注入
危险行为:直接拼接 SQL 字符串(需绝对避免)
php
// 不安全!存在注入风险
Db::query("SELECT * FROM user WHERE id = " . $id);
二、查询构建器的基本用法(防注入)
以下是增删查改的标准用法,均基于查询构建器实现,自带防注入保护:
1. 查(查询数据)
php
// 1.1 单条数据
$user = Db::name('user')
->where('id', $id)
->find(); // 返回一条记录
// 1.2 多条数据
$list = Db::name('user')
->where('status', 1)
->where('create_time', '>=', $startTime)
->order('id', 'desc')
->limit(10)
->select(); // 返回数组
// 1.3 分页查询
$page = Db::name('user')
->where('status', 1)
->order('id', 'desc')
->paginate([
'list_rows' => 10, // 每页条数
'page' => 1 // 当前页
]);
$total = $page->total(); // 总记录数
$items = $page->items(); // 当前页数据
// 1.4 聚合查询
$count = Db::name('user')->where('status', 1)->count(); // 计数
$maxId = Db::name('user')->max('id'); // 最大值
2. 增(新增数据)
php
// 2.1 单条插入
$data = [
'name' => '张三',
'age' => 20,
'create_time' => time()
];
$insertId = Db::name('user')->insertGetId($data); // 返回新增ID
// 或
$affected = Db::name('user')->insert($data); // 返回影响行数
// 2.2 批量插入
$list = [
['name' => '张三', 'age' => 20],
['name' => '李四', 'age' => 22]
];
$affected = Db::name('user')->insertAll($list); // 返回插入总数
3. 改(更新数据)
php
// 3.1 更新单条/多条
$affected = Db::name('user')
->where('id', $id)
->update([
'name' => '新名称',
'update_time' => time()
]); // 返回影响行数
// 3.2 自增/自减
Db::name('user')->where('id', $id)->inc('age', 1)->update(); // 年龄+1
Db::name('user')->where('id', $id)->dec('score', 10)->update(); // 分数-10
4. 删(删除数据)
php
// 4.1 删除单条/多条
$affected = Db::name('user')
->where('id', $id)
->delete(); // 返回影响行数
// 4.2 清空表(谨慎使用)
Db::name('user')->truncate(); // 清空表,无返回值
三、复杂查询条件的安全写法
1. 多条件查询
php
// 方式1:多次调用 where
Db::name('user')
->where('status', 1)
->where('age', '>', 18)
->select();
// 方式2:数组条件(推荐,更清晰)
Db::name('user')
->where([
['status', '=', 1],
['age', '>', 18],
['create_time', 'between', [$start, $end]]
])
->select();
2. 带 OR 的条件
php
Db::name('user')
->where('status', 1)
->whereOr('age', '<', 18) // OR 条件
->select();
3. 字段筛选(避免查询敏感字段)
php
// 只查询指定字段
Db::name('user')->field('id, name, age')->select();
// 排除敏感字段
Db::name('user')->field('password', true)->select(); // 排除 password 字段
四、总结
推荐用法:始终使用
Db::name('table')链式调用,框架会自动防注入。避免行为:禁止直接拼接 SQL 字符串(如
Db::query("SELECT * FROM user WHERE id = $id"))。复杂场景:即使是多条件、OR 逻辑、批量操作,只要通过查询构建器的方法实现,均能保证安全。
ThinkPHP 的查询构建器已对 SQL 注入做了完善处理,遵循上述用法即可安全操作数据库。
评论区