验证器必须严格遵循tp6约定:文件置于app/validate/、命名空间匹配、调用scene()和batch();自定义规则方法需public且四参数;验证不等于过滤,安全输出须模板转义或参数化查询。

验证器类不是“写完就能用”的工具,它必须严格落在 app/validate/ 目录、命名空间匹配、调用时启用 scene() 和 batch(),否则大概率静默失败或只报第一个错。
验证器文件位置和命名空间必须完全对齐
TP6 不会扫描任意路径下的验证类。你写了个 UserRegister 类,就必须:
- 文件路径是
app/validate/UserRegister.php - 类名是
class UserRegister extends \think\Validate - 命名空间是
namespace app\validate;
多应用模式(如 app/admin/)下,命名空间要加前缀:namespace app\admin\validate;,否则 new UserRegister() 会直接报类未找到。别图省事改路径或命名空间——框架只认这个约定。
自定义规则方法签名必须带四个参数
想写手机号唯一性检查?别写 protected function checkMobile($value),TP6 会直接忽略。正确签名是:
public function ruleMobile($value, $rule = '', $data = [], $field = '')
注意四点:
- 方法必须是
public,不能是protected或static - 第四个参数
$field是字段名(如'phone'),漏掉会导致$this->fail()失效 - 规则字符串里写
'phone' => 'ruleMobile',不加function:前缀 - 若需传额外参数(如排除当前用户 ID),用
ruleMobile:123,此时$rule就是'123'
scene() 和 batch() 是必开开关,不是可选项
没设 scene() 就调 check($data),验证器会拿全部 $rule 字段去比对——哪怕你只提交了 email,它也会报 username 缺失。同理,不调 batch(true),getError() 只返回第一个失败项,掩盖其他问题。
典型写法:
$validate = new UserRegister();
$result = $validate->scene('register')->batch()->check($data);
if (!$result) {
dump($validate->getError()); // 返回 ['username' => '用户名不能为空', 'email' => '邮箱格式不正确']
}
验证 ≠ 过滤,安全输出还得靠模板层转义
validate() 默认不做任何转义、消毒或类型转换,它只回答“是否合法”。XSS 输出注入风险依然存在。必须在模板中统一使用 {{ $data|htmlspecialchars }},或在验证器配置中开启 'output_convert' => true(但该配置仅影响部分内置规则,不覆盖所有场景)。SQL 注入则必须配合参数化查询,禁用裸 db::query()。
真正容易被忽略的,是把验证当成“防注入”的全部手段——它只是四阶防御模型里的第二层,上层有客户端预检,下层有持久化前字段沙箱,缺一不可。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











