简介
本文件面向 DouPHP 后台的请求验证系统,系统性说明表单验证规则的定义与使用、内置与自定义验证器、复合规则、请求对象的数据绑定与类型转换、批量数据验证机制、错误处理与国际化消息、以及性能优化与安全注意事项。文档以代码级实现为依据,提供可视化图示与可操作的开发指引。
项目结构
DouPHP 的后台验证由“请求对象 + 声明式验证器”组成:
- 请求对象:继承 FormRequest,定义 rules() 与可选的 validationData(),用于场景化校验与白名单字段提取。
- 验证器:Validator 负责解析规则串、执行校验、抛出异常并返回错误集合(支持收集全部错误)。
- 语言包:validator_* 键名提供默认错误消息,可按 field.rule 覆盖。
graph TB
Controller["控制器"] --> FR["FormRequest<br/>rules()/validationData()"]
FR --> V["Validator<br/>validate()"]
V --> DB["数据库连接<br/>唯一性/存在性检查"]
V --> Lang["语言包<br/>validator_* / {field}_{rule}"]
V --> Check["Check工具类<br/>格式校验"]
核心组件
- 表单请求基类 FormRequest
- 职责:封装场景化校验流程;从 POST 读取数据;按 rules() 白名单过滤输出。
- 关键点:validated() 内部构造 Validator 并执行 validate();validationData() 可被重写以合并路由/查询参数到校验数据。
- 声明式验证器 Validator
- 职责:解析规则串、逐项执行规则、生成错误键、统一抛出 DomainException(支持收集全部错误)。
- 能力:内置大量规则(必填、长度、数值、邮箱、URL、IP、日期、布尔、唯一性、存在性、确认、正则、枚举、前缀后缀、手机号、密码、非法字符、用户名、别名、身份证、QQ、邮编、JSON、数组、接受、文件/图片/扩展名/大小/尺寸等)。
- 错误消息优先级:messages[field.rule] > 语言包 {field}{rule} > 语言包 validator{rule} > 开发占位符。
架构总览
请求进入控制器后,通过容器注入的 FormRequest 子类完成校验与白名单提取;随后将已验证数据交给服务层或模型层持久化。
sequenceDiagram
participant C as "控制器"
participant R as "FormRequest子类"
participant V as "Validator"
participant DB as "数据库"
participant L as "语言包"
C->>R : validated()
R->>R : validationData()
R->>V : validate(data, rules)
V->>V : splitRules()/applyRule(...)
V->>DB : unique/exists 检查(必要时)
V->>L : 获取错误消息
V-->>R : 通过或抛出DomainException
R-->>C : 返回白名单数据
详细组件分析
表单请求对象设计模式
- 数据绑定
- 默认仅绑定 POST 数据;可通过重写 validationData() 合并路由/查询参数(如 update 场景的 id/user_id)。
- 类型转换与默认值
- 在 validationData() 中可使用 request()->integer('id', 0) 等方式进行类型转换与默认值设置,确保 rules() 能正确触发 integer/min_value 等规则。
- 白名单字段
- validated() 返回 array_intersect_key($data, $rules),即仅包含 rules() 中定义的字段,天然实现白名单过滤。
- 场景化规则
- 通过 scene(store/update)动态增减规则,例如更新时要求 id 必填且为整数。
验证规则体系
- 内置规则概览
- 基础:required、required_if、same、different、accepted、array、json
- 文本:alpha_dash、alpha、alpha_num、max/min/between、starts_with、ends_with、regex/not_regex
- 数值:numeric、integer、float、price、digits、digits_between、max_value/min_value/between_value
- 地址与标识:email、url、domain、ip、phone、password、username、admin_account、slug、idcard、qq、postcode
- 业务:unique、exists、confirmed
- 文件:file、image、mimes、max_kb、dimensions
- 规则解析
- 以 | 分隔,支持带参数的规则(如 max:150、unique:table,field[,excludeField])。
- 对 regex 规则中的 | 做了保护,避免误拆分。
- 复合规则
- 可在同一字段组合多个规则,如 'required|price'、'email|unique:user,email'。
- 条件规则
- required_if:field,val1,val2 当其他字段命中指定值时才必填。
- 自定义规则
- 通过 messages['field.rule'] 覆盖错误消息;或通过新增规则分支扩展 Validator::applyRule()。
批量数据验证
- 数组字段
- 使用 array 规则可校验字段是否为数组;结合 min/max/between 可实现数组长度约束。
- 动态规则生成
- 在 rules() 中根据场景或配置动态追加规则(如 slug 是否启用、update 场景追加 id 必填)。
- 条件验证
- 使用 required_if 实现基于其他字段的条件必填;配合 same/different 做跨字段一致性校验。
- 示例参考
- 商品表单:根据 features.slug 开关决定是否启用 slug 的唯一性校验。
- 用户表单:update 场景下 password 留空表示不修改,confirmed 在空值时短路。
上传文件验证
- file/image/mimes/max_kb/dimensions
- 自动识别 UploadedFile 实例或从 $_FILES 解析。
- image 会校验扩展名是否在允许列表(回退至文件系统配置)。
- mimes 支持显式扩展名清单,为空时回退到全局允许扩展名。
- max_kb 支持传入上限或回退到全局配置。
- dimensions 支持宽高范围、精确宽高、比例 ratio 等约束。
- 注意
- 未提供有效文件时,file/image/mimes/max_kb/dimensions 会短路通过(需在前置 required 控制)。
错误处理与国际化
- 错误消息优先级
- 优先使用 messages['field.rule'] 覆盖;其次查找语言包 {field}{rule};再回退到 validator{rule};最后显示开发占位符。
- 收集全部错误
- validate(..., collectAll=true) 可聚合所有字段错误并在末尾一次性抛出,便于前端展示完整问题。
- confirmed 映射
- confirmed 失败时错误默认映射到 {field}_confirm,便于定位确认输入框。
- 语言包
- 通用消息位于 common.lang.php 的 validator_* 键名;可按模块/字段细化。
开发示例指引
- 创建自定义验证器
- 在 Validator::applyRule() 新增 case 分支,复用 Check 工具方法或数据库查询。
- 在语言包添加 validator_{rule} 或按 field.rule 覆盖。
- 复杂验证场景
- 使用 required_if/same/different 表达跨字段依赖;使用 unique/exists 进行数据库一致性校验。
- 国际化消息
- 在对应语言文件中补充 validator* 或 {module}{field}_{rule} 键值,确保多语言提示。
依赖关系分析
- 组件耦合
- FormRequest 依赖 Validator 与 Request(读取 POST/路由参数)、语言包(lang_all)。
- Validator 依赖数据库连接(唯一性/存在性)、Check 工具(格式校验)、UploadedFile(文件校验)。
- 外部依赖
- 数据库:用于 unique/exists 规则。
- 文件系统配置:用于图片扩展名与最大上传大小回退。
- 潜在循环依赖
- 当前结构清晰,无直接循环依赖。
graph LR
FR["FormRequest"] --> V["Validator"]
V --> DB["数据库连接"]
V --> CK["Check工具"]
V --> UF["UploadedFile"]
V --> LG["语言包"]
性能考虑
- 规则解析优化
- 不含 regex/not_regex 时走快速路径;含正则时智能保护 | 不被误切分。
- 数据库访问最小化
- unique/exists 仅在需要时访问数据库;建议在高并发场景对热点表加索引。
- 文件校验开销
- dimensions 会读取图片元信息,建议在必要场景使用,并结合 max_kb 限制大文件。
- 批量错误收集
- collectAll=true 会遍历全部规则后再抛错,适合前端一次性展示;高频接口建议首错即抛以减少开销。
故障排查指南
- 常见问题
- 规则未生效:确认字段存在于 rules() 中;update 场景需在 validationData() 合并 id/user_id。
- 唯一性冲突:检查 unique 规则的 table/field/exclude 参数是否正确。
- 文件校验失败:确认 file/image/mimes/max_kb/dimensions 前置 required 是否合理;检查允许扩展名与文件大小配置。
- 错误消息不显示:检查 messages['field.rule'] 或语言包键名是否匹配;确认模块名前缀是否影响翻译。
- 调试建议
- 使用 collectAll=true 收集全部错误,定位多字段问题。
- 在日志中记录异常信息与上下文,辅助定位。
结论
DouPHP 后台验证系统通过 FormRequest + Validator 的组合,提供了声明式、可扩展、易用的请求校验能力。借助丰富的内置规则、场景化规则、文件校验与国际化消息机制,开发者可以高效构建健壮的后端入口。遵循本文的性能与安全建议,可进一步提升系统的稳定性与安全性。
附录
- 常用规则速查
- 必填与条件:required、required_if
- 文本与格式:alpha_dash、email、url、domain、ip、date/date_format、boolean、regex
- 数值与范围:numeric、integer、float、price、digits/digits_between、max/min/between、max_value/min_value/between_value
- 业务校验:unique、exists、confirmed、same、different、in/not_in、starts_with/ends_with
- 身份与标识:phone、password、username、admin_account、slug、idcard、qq、postcode
- 文件:file、image、mimes、max_kb、dimensions
- 最佳实践
- 始终在 rules() 中明确白名单字段;敏感字段尽量在后端再次校验。
- 对外部输入一律视为不可信,结合 XSS/SQL 注入防护策略。
- 对文件上传严格限制类型与大小,避免恶意文件。
- 使用 collectAll=false 提升常见接口的响应速度;批量提交时使用 collectAll=true 改善用户体验。