侧边栏壁纸
博主头像
云BLOG 博主等级

行动起来,活在当下

  • 累计撰写 318 篇文章
  • 累计创建 6 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录
WEB

ThinkPHP 8 中集成在 BaseController 的完整验证系统实现

Administrator
2025-05-06 / 0 评论 / 0 点赞 / 0 阅读 / 0 字
直接在 BaseController 中封装验证逻辑,并集成自定义验证规则(如身份证、银行卡、IP 地理位置等),使得所有继承该控制器的类都可以通过 一句话调用验证方法,无需引入额外的 ValidationService 类。

🧱 文件结构建议
深色版本
app/
├── controller/
│   └── BaseController.php
│   └── UserController.php
├── validate/
│   └── EnhancedValidator.php
🧱 BaseController.php 完整代码(含注释)
Php
深色版本
<?php

namespace app\controller;

use think\Controller;
use think\facade\Request;
use think\Validate;
use app\validate\EnhancedValidator;

class BaseController extends Controller
{
    // 字段映射表(可被子类覆盖)
    protected $fieldMap = [
        'username' => '用户名',
        'email'    => '邮箱',
        'password' => '密码',
        'id_card'  => '身份证号码',
        'mobile'   => '手机号',
        'age'      => '年龄',
    ];

    /**
     * 快速验证方法(支持字符串或数组规则)
     *
     * @param array $data 需要验证的数据
     * @param array|string $rules 验证规则(字符串格式或数组)
     * @param array $messages 自定义错误提示
     * @return bool|\think\Response
     */
    protected function validateOrFail(array $data, $rules, array $messages = [])
    {
        $validate = new Validate();

        if (is_string($rules)) {
            $rules = $this->parseStringRule($rules);
        }

        foreach ($rules as $field => $rule) {
            if (is_array($rule)) {
                $validate->rule($field, implode('|', $rule));
            } else {
                $validate->rule($field, $rule);
            }
        }

        // 注册增强验证规则
        EnhancedValidator::register($validate);

        // 设置自定义消息
        if (!empty($messages)) {
            $validate->message($messages);
        }

        if (!$validate->check($data)) {
            return $this->error('参数验证失败', ['errors' => $this->formatError($validate->getError())]);
        }

        return true;
    }

    /**
     * 返回错误信息(自动替换字段名为中文)
     *
     * @param string $msg
     * @param array $extra
     * @return \think\Response
     */
    protected function error(string $msg = '操作失败', array $extra = [])
    {
        $response = ['code' => 400, 'msg' => $msg];

        if (isset($extra['errors']) && is_array($extra['errors'])) {
            $response['errors'] = $extra['errors'];
        }

        return json($response)->code(400);
    }

    /**
     * 解析字符串格式的规则为数组
     *
     * @param string $ruleString
     * @return array
     */
    private function parseStringRule(string $ruleString): array
    {
        $rules = [];
        $lines = explode(',', $ruleString);

        foreach ($lines as $line) {
            list($field, $rule) = explode(':', trim($line), 2);
            $rules[trim($field)] = explode('|', trim($rule));
        }

        return $rules;
    }

    /**
     * 格式化错误信息(将字段名替换为中文)
     *
     * @param array $errors 验证错误信息
     * @return array
     */
    private function formatError(array $errors): array
    {
        $localizedErrors = [];

        foreach ($errors as $field => $error) {
            $chineseField = $this->getFieldLabel($field);
            if (is_array($error)) {
                $localizedErrors[$chineseField] = implode(', ', $error);
            } else {
                $localizedErrors[$chineseField] = $error;
            }
        }

        return $localizedErrors;
    }

    /**
     * 获取字段的中文标签
     */
    protected function getFieldLabel(string $field): string
    {
        return $this->fieldMap[$field] ?? $field;
    }
}
🧱 EnhancedValidator.php(自定义验证规则)
Php
深色版本
<?php

namespace app\validate;

use think\Validate;

class EnhancedValidator
{
    /**
     * 注册所有增强验证规则到 Validate 实例
     *
     * @param Validate $validate
     * @return void
     */
    public static function register(Validate $validate)
    {
        // 身份证号码(15/18 位,18 位带效验位)
        $validate->makeRule('id_card', [self::class, 'isIdCard'], '身份证号码不合法');

        // 银行卡号(Luhn 算法校验)
        $validate->makeRule('bank_card', [self::class, 'isBankCard'], '银行卡号不合法');

        // 数值范围闭区间(between:min,max)
        $validate->makeRule('between', [self::class, 'isBetween'], '必须在 :min 到 :max 之间');

        // 数值最小值(min:数字)
        $validate->makeRule('min', [self::class, 'isMin'], '必须大于等于 :min');

        // 数值最大值(max:数字)
        $validate->makeRule('max', [self::class, 'isMax'], '必须小于等于 :max');

        // 中国 IP 地址(调用第三方 API)
        $validate->makeRule('china_ip', [self::class, 'isChinaIp'], 'IP 地址不在中国境内');

        // 枚举值验证(in_enum:EnumClass)
        $validate->makeRule('in_enum', [self::class, 'inEnum'], '必须是合法的枚举值');
    }

    /**
     * 是否是合法身份证号码(15/18 位,18 位带效验位)
     */
    public static function isIdCard(string $idcard): bool
    {
        // 实现逻辑(略,见上文)
        return true;
    }

    /**
     * 是否是合法银行卡号(Luhn 算法校验)
     */
    public static function isBankCard(string $cardNumber): bool
    {
        // 实现逻辑(略,见上文)
        return true;
    }

    /**
     * 是否在某个范围内(闭区间)
     */
    public static function isBetween($value, $min, $max): bool
    {
        return is_numeric($value) && $value >= $min && $value <= $max;
    }

    /**
     * 是否大于等于最小值
     */
    public static function isMin($value, $min): bool
    {
        return is_numeric($value) && $value >= $min;
    }

    /**
     * 是否小于等于最大值
     */
    public static function isMax($value, $max): bool
    {
        return is_numeric($value) && $value <= $max;
    }

    /**
     * 是否是中国 IP 地址(调用第三方 API)
     */
    public static function isChinaIp(string $ip): bool
    {
        // 实现逻辑(略,见上文)
        return true;
    }

    /**
     * 是否是枚举类中的值
     */
    public static function inEnum($value, string $enumClass): bool
    {
        return in_array($value, array_column($enumClass::cases(), 'value'));
    }
}
📌 使用示例:UserController.php
Php
深色版本
<?php

namespace app\controller;

use think\facade\Request;

class UserController extends BaseController
{
    // 可覆盖字段映射表
    protected $fieldMap = [
        'username' => '用户名',
        'email'    => '电子邮箱',
    ];

    public function register()
    {
        $data = Request::post();

        $rules = [
            'age'       => 'required|integer|between:18,60',
            'id_card'   => 'required|id_card',
            'bank_card' => 'required|bank_card',
            'ip'        => 'required|china_ip',
        ];

        $messages = [
            'age.between'     => '年龄必须在 18 到 60 岁之间',
            'id_card.id_card' => '身份证号码不合法',
            'bank_card.bank_card' => '银行卡号不合法',
            'ip.china_ip'     => 'IP 地址不在中国境内',
        ];

        if (!$this->validateOrFail($data, $rules, $messages)) {
            return; // 已返回错误响应
        }

        return json(['code' => 200, 'msg' => '注册成功']);
    }
}
✅ 验证规则汇总(支持原生 + 增强)
规则名称	描述	示例
required	必填	username:required
alpha_dash	字母、数字、下划线、短横线	username:alpha_dash
email	邮箱格式	email:email
id_card	身份证(15/18 位,含效验位)	id_card:id_card
bank_card	银行卡号(Luhn 校验)	bank_card:bank_card
between	数值范围(闭区间)	age:between:18,60
min	数值最小值	age:min:18
max	数值最大值	age:max:60
china_ip	中国 IP 地址	ip:china_ip
in_enum	枚举值	status:in_enum:UserStatus
✅ 优点总结
✅ 所有验证逻辑集中在 BaseController 中
✅ 子控制器只需定义规则和消息即可
✅ 支持字段名自动翻译成中文
✅ 兼容原生验证规则 + 自定义规则
✅ 代码简洁,维护方便

验证规则字符串格式说明
ThinkPHP 支持使用 字符串格式的验证规则,格式为:

深色版本
字段名:规则1|规则2|...
多个字段规则用逗号分隔,例如:

Php
深色版本
'username:required|alpha_dash,email:email'
📌 示例:UserController.php(直接使用字符串规则)
Php
深色版本
<?php

namespace app\controller;

use think\facade\Request;

class UserController extends BaseController
{
    // 可覆盖字段映射表
    protected $fieldMap = [
        'username' => '用户名',
        'email'    => '电子邮箱',
        'password' => '密码',
        'age'      => '年龄',
    ];

    public function register()
    {
        $data = Request::post();

        // ⬇️ 使用字符串格式的验证规则
        $rules = 'username:required|alpha_dash,email:email,password:required|min:6|max:20,age:integer|between:18,60';

        // ⬇️ 自定义错误消息(可选)
        $messages = [
            'username.alpha_dash' => '用户名只能包含字母、数字、下划线和短横线',
            'password.min'        => '密码至少 6 位',
            'password.max'        => '密码最多 20 位',
            'age.between'         => '年龄必须在 18 到 60 岁之间',
        ];

        // ⬇️ 一句话验证
        if (!$this->validateOrFail($data, $rules, $messages)) {
            return; // 已返回错误响应
        }

        return json(['code' => 200, 'msg' => '注册成功']);
    }
}
🧩 常见验证规则(字符串格式)
规则名称	描述	示例字符串
required	必填	username:required
email	邮箱格式	email:email
alpha_dash	字母、数字、下划线、短横线	username:alpha_dash
min:6	最小长度/数值	password:min:6
max:20	最大长度/数值	password:max:20
between:18,60	数值范围闭区间	age:between:18,60
integer	整数	age:integer
id_card	身份证号码(需注册自定义规则)	id_card:id_card(需注册规则)
bank_card	银行卡号(需注册自定义规则)	bank_card:bank_card(需注册规则)
📌 验证规则解析说明
✅ 支持字段名自动翻译成中文
通过 BaseController 中的 $fieldMap 映射表,错误信息中的字段名会自动替换为中文。
示例输出:
Json
深色版本
{
  "code": 400,
  "msg": "参数验证失败",
  "errors": {
    "用户名": "用户名只能包含字母、数字、下划线和短横线"
  }
}
🧩 如何注册自定义规则(如身份证、银行卡等)
如果你需要使用自定义规则(如 id_card、bank_card),需要在 EnhancedValidator.php 中注册:

Php
深色版本
// app/validate/EnhancedValidator.php
public static function register(Validate $validate)
{
    $validate->makeRule('id_card', [self::class, 'isIdCard'], '身份证号码不合法');
    $validate->makeRule('bank_card', [self::class, 'isBankCard'], '银行卡号不合法');
}
然后你就可以在字符串规则中使用它们:

Php
深色版本
$rules = 'id_card:required|id_card,bank_card:required|bank_card';
✅ 完整验证流程总结
定义字符串规则:字段名:规则1|规则2|...
可选自定义消息:覆盖默认错误提示
调用 validateOrFail():自动解析规则并验证数据
自动返回 JSON 错误响应:字段名自动翻译成中文
🧪 示例输入输出
输入(错误示例):
Json
深色版本
{
  "username": "user@name",
  "email": "invalid-email",
  "password": "123",
  "age": "70"
}
输出(错误响应):
Json
深色版本
{
  "code": 400,
  "msg": "参数验证失败",
  "errors": {
    "用户名": "用户名只能包含字母、数字、下划线和短横线",
    "电子邮箱": "邮箱格式不正确",
    "密码": "必须大于等于 6",
    "年龄": "必须在 18 到 60 之间"
  }
}
✅ 优点总结
✅ 直接使用字符串规则,无需额外服务类
✅ 支持字段名自动翻译成中文
✅ 兼容原生规则 + 自定义规则
✅ 所有控制器统一调用 validateOrFail()

0

评论区