Skip to content

数据验证

DuxLite 基于 Valitron 提供了强大而简洁的数据验证系统,让你轻松处理表单验证和数据校验。

🚀 快速开始

基础验证

在 Resource 控制器中定义验证规则:

php
public function validator(array $data, ServerRequestInterface $request, array $args): array
{
    return [
        "title" => ["required", '标题不能为空'],
        "email" => ["required", "email", '请输入有效的邮箱地址'],
        "age" => ["required", "integer", "min", 18, '年龄必须大于18岁'],
    ];
}

验证规则格式

每个字段的验证规则格式为:[规则名, 参数1, 参数2, ..., 错误消息]

php
return [
    // 基础规则:[规则名, 错误消息]
    "name" => ["required", '姓名不能为空'],

    // 带参数规则:[规则名, 参数, 错误消息]
    "age" => ["min", 18, '年龄必须大于18岁'],

    // 多个规则:[[规则1, 消息1], [规则2, 参数, 消息2]]
    "password" => [
        ["required", '密码不能为空'],
        ["lengthMin", 6, '密码长度至少6位']
    ]
];

📋 内置验证规则

必填验证

php
return [
    // 基础必填
    "name" => ["required", '姓名不能为空'],

    // 条件必填 - 当其他字段存在时必填
    "password" => ["requiredWith", "username", '用户名存在时密码必填'],

    // 条件必填 - 当其他字段不存在时必填
    "email" => ["requiredWithout", "phone", '手机号不存在时邮箱必填'],
];

类型验证

php
return [
    "email" => ["email", '邮箱格式不正确'],
    "age" => ["integer", '年龄必须是整数'],
    "price" => ["numeric", '价格必须是数字'],
    "website" => ["url", '网址格式不正确'],
    "is_active" => ["boolean", '状态必须是布尔值'],
    "tags" => ["array", '标签必须是数组'],
];

长度验证

php
return [
    "title" => ["length", 10, '标题必须是10个字符'],
    "content" => ["lengthBetween", 10, 500, '内容长度必须在10-500字符之间'],
    "summary" => ["lengthMin", 5, '摘要至少5个字符'],
    "description" => ["lengthMax", 200, '描述最多200个字符'],
];

数值验证

php
return [
    "age" => ["min", 18, '年龄必须大于等于18'],
    "score" => ["max", 100, '分数不能超过100'],
    "price" => ["numeric", '价格必须是数字'],
    "quantity" => ["integer", '数量必须是整数'],
];

选项验证

php
return [
    "status" => ["in", ["active", "inactive"], '状态值无效'],
    "role" => ["notIn", ["admin"], '不能选择管理员角色'],
    "colors" => ["listContains", "red", '颜色列表必须包含红色'],
];

字符串验证

php
return [
    "name" => ["alpha", '姓名只能包含字母'],
    "username" => ["alphaNum", '用户名只能包含字母和数字'],
    "slug" => ["slug", 'URL别名格式不正确'],
    "content" => ["ascii", '内容只能包含ASCII字符'],
];

正则验证

php
return [
    "phone" => ["regex", "/^1[3-9]\d{9}$/", '手机号格式不正确'],
    "username" => ["regex", "/^[a-zA-Z0-9_]{3,16}$/", '用户名格式不正确'],
];

日期验证

php
return [
    "birthday" => ["date", '生日格式不正确'],
    "created_at" => ["dateFormat", "Y-m-d H:i:s", '创建时间格式不正确'],
    "start_date" => ["dateBefore", "2024-12-31", '开始日期必须在2024年之前'],
    "end_date" => ["dateAfter", "2024-01-01", '结束日期必须在2024年之后'],
];

其他验证

php
return [
    "terms" => ["accepted", '必须同意服务条款'],
    "password" => ["equals", "password_confirm", '两次密码输入不一致'],
    "new_password" => ["different", "old_password", '新密码不能与旧密码相同'],
    "ip_address" => ["ip", 'IP地址格式不正确'],
    "email_dns" => ["emailDNS", '邮箱域名无效'],
    "website" => ["urlActive", '网站地址无法访问'],
];

🎯 DuxLite 特有规则

DuxLite 在 Valitron 基础上扩展了一些常用的验证规则:

php
return [
    // 身份证号验证
    "idcard" => ["regex", "/^(\\d{18,18}|\\d{15,15}|\\d{17,17}x)$/i", '身份证号格式不正确'],

    // 手机号验证
    "phone" => ["regex", "/^1[3-9]\\d{9}$/", '手机号格式不正确'],

    // 枚举值验证
    "status" => [function($field, $value, $params, $fields) {
        return in_array($value, ['active', 'inactive']);
    }, '状态值无效'],
];

规则映射

DuxLite 会自动将一些常见规则映射到 Valitron 规则:

DuxLite 规则Valitron 规则说明
booleanboolean布尔值验证
datedate日期验证
emailemail邮箱验证
enum自定义函数枚举值验证
idcardregex身份证号验证
lengthlength长度验证
minlengthMin最小长度验证
maxlengthMax最大长度验证
numbernumeric数字验证
patternregex正则验证
requiredrequired必填验证
telnumberregex手机号验证
urlurlURL验证

🔧 自定义验证规则

闭包验证

php
public function validator(array $data, ServerRequestInterface $request, array $args): array
{
    return [
        "username" => [
            ["required", '用户名不能为空'],
            [function ($field, $value, $params, $fields) use ($args) {
                // 检查用户名唯一性
                $query = User::where('username', $value);
                if ($args['id']) {
                    $query->where('id', '<>', $args['id']);
                }
                return !$query->exists();
            }, '用户名已存在']
        ],

        "email" => [
            ["required", "email", '请输入有效的邮箱'],
            [function ($field, $value) {
                // 检查邮箱域名
                $domain = substr(strrchr($value, "@"), 1);
                $allowedDomains = ['gmail.com', 'qq.com', 'company.com'];
                return in_array($domain, $allowedDomains);
            }, '只允许使用指定邮箱域名']
        ],

        "password" => [
            ["required", '密码不能为空'],
            [function ($field, $value) {
                // 密码强度检查
                return preg_match('/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/', $value);
            }, '密码必须包含大小写字母和数字,至少8位']
        ],
    ];
}

跨字段验证

php
public function validator(array $data, ServerRequestInterface $request, array $args): array
{
    return [
        "password" => ["required", '密码不能为空'],
        "password_confirmation" => [
            ["required", '确认密码不能为空'],
            [function ($field, $value, $params, $fields) {
                return $value === $fields['password'];
            }, '两次密码输入不一致']
        ],

        "start_date" => ["required", "date", '开始日期不能为空'],
        "end_date" => [
            ["required", "date", '结束日期不能为空'],
            [function ($field, $value, $params, $fields) {
                return strtotime($value) > strtotime($fields['start_date']);
            }, '结束日期必须大于开始日期']
        ],
    ];
}

📊 条件验证

基于请求类型的验证

php
public function validator(array $data, ServerRequestInterface $request, array $args): array
{
    $isEdit = !empty($args['id']);

    $rules = [
        "title" => ["required", '标题不能为空'],
        "content" => ["required", '内容不能为空'],
    ];

    // 创建时密码必填,编辑时可选
    if (!$isEdit) {
        $rules["password"] = [
            ["required", '密码不能为空'],
            ["lengthMin", 6, '密码至少6位']
        ];
    } else {
        $rules["password"] = ["lengthMin", 6, '密码至少6位'];
    }

    return $rules;
}

基于用户权限的验证

php
public function validator(array $data, ServerRequestInterface $request, array $args): array
{
    // 获取当前用户认证信息
    $auth = $request->getAttribute('auth');
    $isAdmin = $auth['role'] === 'admin'; // 根据实际权限逻辑判断

    $rules = [
        "title" => ["required", '标题不能为空'],
        "content" => ["required", '内容不能为空'],
    ];

    // 只有管理员可以设置置顶
    if (!$isAdmin) {
        unset($data['is_top']);
    } else {
        $rules["is_top"] = ["boolean", '置顶状态格式错误'];
    }

    return $rules;
}

🎯 实际应用示例

用户管理验证(基于真实代码)

基于 app/System/Admin/User.php 的实际验证逻辑:

php
public function validator(array $data, ServerRequestInterface $request, array $args): array
{
    return [
        "nickname" => ["required", '昵称不能为空'],
        "username" => [
            ["required", '用户名不能为空'],
            [function ($field, $value, $params, $fields) use ($args) {
                $model = SystemUser::query()->where('username', $fields['username']);
                if ($args['id']) {
                    $model->where("id", "<>", $args['id']);
                }
                return !$model->exists();
            }, '用户名已存在']
        ],
        "password" => ["requiredWithout", "id", '密码不能为空'],
        "role_id" => ["required", '角色不能为空'],
    ];
}

文章发布验证

php
public function validator(array $data, ServerRequestInterface $request, array $args): array
{
    return [
        "title" => [
            ["required", '标题不能为空'],
            ["lengthMax", 100, '标题不能超过100个字符'],
            [function ($field, $value, $params, $fields) use ($args) {
                $query = Article::where('title', $value);
                if ($args['id']) {
                    $query->where('id', '<>', $args['id']);
                }
                return !$query->exists();
            }, '标题已存在']
        ],

        "slug" => [
            ["required", 'URL别名不能为空'],
            ["regex", "/^[a-z0-9-]+$/", 'URL别名只能包含小写字母、数字和连字符'],
            [function ($field, $value, $params, $fields) use ($args) {
                $query = Article::where('slug', $value);
                if ($args['id']) {
                    $query->where('id', '<>', $args['id']);
                }
                return !$query->exists();
            }, 'URL别名已存在']
        ],

        "content" => [
            ["required", '内容不能为空'],
            ["lengthMin", 10, '内容至少10个字符']
        ],

        "category_id" => [
            ["required", "integer", '请选择分类'],
            [function ($field, $value) {
                return Category::where('id', $value)->exists();
            }, '分类不存在']
        ],
    ];
}

🔍 验证错误处理

自动错误响应

验证失败时,DuxLite 会自动返回错误响应:

json
{
  "code": 422,
  "message": "验证失败",
  "data": {
    "username": ["用户名不能为空", "用户名已存在"],
    "email": ["邮箱格式不正确"],
    "password": ["密码至少8位"]
  }
}

自定义错误处理

php
public function validator(array $data, ServerRequestInterface $request, array $args): array
{
    return [
        "email" => [
            [function ($field, $value) {
                if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
                    // 抛出自定义异常
                    throw new \InvalidArgumentException('邮箱格式不正确,请检查输入');
                }
                return true;
            }, '邮箱验证失败']
        ]
    ];
}

💡 最佳实践

1. 验证规则分组

php
public function validator(array $data, ServerRequestInterface $request, array $args): array
{
    // 基础验证规则
    $baseRules = [
        "title" => [
            ["required", '标题不能为空'],
            ["lengthMax", 100, '标题不超过100字符']
        ],
        "content" => ["required", '内容不能为空'],
    ];

    // 高级验证规则
    $advancedRules = [
        "slug" => [
            ["required", 'URL别名不能为空'],
            [function ($field, $value, $params, $fields) use ($args) {
                return $this->validateUniqueSlug($value, $args['id'] ?? null);
            }, 'URL别名已存在']
        ],
    ];

    return array_merge($baseRules, $advancedRules);
}

private function validateUniqueSlug(string $slug, ?int $excludeId = null): bool
{
    $query = Article::where('slug', $slug);
    if ($excludeId) {
        $query->where('id', '<>', $excludeId);
    }
    return !$query->exists();
}

2. 复用验证逻辑

php
trait UserValidationTrait
{
    protected function getUsernameRules(?int $excludeId = null): array
    {
        return [
            ["required", '用户名不能为空'],
            ["lengthBetween", 3, 20, '用户名长度为3-20个字符'],
            [function ($field, $value) use ($excludeId) {
                $query = User::where('username', $value);
                if ($excludeId) {
                    $query->where('id', '<>', $excludeId);
                }
                return !$query->exists();
            }, '用户名已存在']
        ];
    }
}

class User extends Resources
{
    use UserValidationTrait;

    public function validator(array $data, ServerRequestInterface $request, array $args): array
    {
        return [
            "username" => $this->getUsernameRules($args['id'] ?? null),
            // 其他规则...
        ];
    }
}

🎉 总结

DuxLite 的验证系统特点:

  • 📝 声明式验证:简洁的数组语法定义验证规则
  • 🔧 灵活扩展:支持自定义验证函数和复杂逻辑
  • 🎯 条件验证:基于上下文的动态验证规则
  • ✅ 自动处理:验证失败自动返回标准错误响应
  • 🚀 高性能:内置缓存和优化机制

通过合理使用这些验证功能,你可以构建出安全、可靠的数据处理逻辑!