永远不要相信前端传输的数据,一定要进行验证,TP5有两种验证方式独立验证与验证器
独立验证
独立验证就是在操作方法中实例Validate对数据进行验证
<?php
namespace app\index\controller;
use think\Request;
use think\Validate;
class Index
{
/**
* 独立验证
* @param Request $request
*/
public function index(Request $request)
{
$id = $request->param('id');
$email = $request->param('email');
$data = [
'id' => $id,
'email' => $email,
];
$rule = [
'id'=>'require|number|max:2',
'email'=>'require|email'
];
$msg = [
'id.require' => 'id为必填项',
'id.max' => 'id最大不能超过99',
'email.require' => 'email邮箱为必填项',
'email.email' => 'email邮箱格式不正确',
];
$field = [
'id' => '自增编号',
'email' => '邮箱',
];
$validate = new Validate($rule,$msg,$field);
if( ! $validate->batch()->check($data) ){
$error = $validate->getError();
dump($error);exit;
};
}
}
直接在controller中使用unique
文档太简陋了,还要看源码才行,‘name’ => ‘unique:user,status=1&account=’.$data[‘account’],这种的只能放在controller中,自己来定义rule和message,在单独的validate类中无法将相关的值传递过去。
规则是:unique:【模型类名(或表名)】,【要验证的字段(或者包含=号或者包含^号,但是必须把本身的条件加入,别以为前面有name了就不把name本身加进去了)】,【要排除的字段】,【主键(可不填)】
<?php
namespace app\index\controller;
use think\Validate;
use think\Request;
class Index
{
/**
* 验证器验证
*/
public function index(Request $request)
{
$id = $request->post('id');
$shopId = session('shop_id');
$name = $request->post('name');
$sort = $request->post('sort', 0, 'intval');
$postData = [
'name' => $name,
'sort' => $sort
];
$rule = [
'name' => 'require|unique:ArticleCategory,shop_id=' . $shopId . '&name=' . $name,//名称
'sort' => 'number'
];
$message = [
'name.require' => '分类名称必须填写',
'name.unique' => '分类名称已存在',
'sort.number' => '排序必须填写整数',
];
$validate = new Validate($rule, $message);
if (!empty($id)) {
$validate->scene('edit',
[
'sort',
'name' => 'require|unique:ArticleCategory,shop_id=' . $shopId . '&name=' . $name . ',' . $id
]);
$validateRes = $validate->scene('edit')->check($postData);
} else {
$validate->scene('add', ['sort', 'name']);
$validateRes = $validate->scene('add')->check($postData);
}
if (true !== $validateRes) {
$data['msg'] = $validate->getError();
return json($data);
}
}
}
验证器
新建Validate子类,并定义验证规则,错误信息提示,场景等。然后再控制器中进行调用
简单版
<?php
namespace app\validate;
class UserValidate extends BaseValidate
{
// 验证器规则和提示信息合并显示
protected $rule = [
['username',"require|length:2,10","用户名不存在2|用户名只2-10位字符之间2"],
['password',"require|length:2,10","需要输入密码2|密码需要保持2-10位字符2"],
];
// 设置验证场景
protected $scene = [
'login' => ['username','password'],
];
}
场景使用
<?php
namespace app\index\controller;
use app\validate\UserValidate;
use think\Request;
class Index
{
/**
* 验证器验证
*/
public function index(Request $request)
{
$data = [
'name' => 'zs',
'age' => 'zs',
'email' => '[email protected]',
];
$validate = new UserValidate();
$res = $validate->scene('add')->batch()->check($data);
if( ! $res ){
$error = $validate->getError();
dump($error);exit;
}
}
}
//下面是独立的验证器
namespace app\validate;
use think\Validate;
class UserValidate extends Validate
{
protected $rule = [
'name' => 'require|max:25',
'age' => 'require|positiveInteger|between:18,120',
'email' => 'require|email',
];
protected $message = [
'name.require' => '名称必须',
'name.max' => '名称最多不能超过25个字符',
'age.number' => '年龄必须是数字',
'age.between' => '年龄只能在1-120之间',
'email' => '邮箱格式错误',
];
protected $field = [
'name' => '姓名',
'age' => '年龄',
'email' => '邮箱',
];
protected $scene = [
'edit' => [
'name',
'email',
],
'add' => [
'name',
'age',
'email',
],
];
/**
* 自定义验证规则
* @param $value string 验证数据
* @param $rule string 验证规则
* @param $data array 全部数据
* @param $field string 字段名
* @param $fieldDesc string 字段描述
* @return bool|string
*/
public function positiveInteger($value,$rule,$data,$field,$fieldDesc)
{
if( is_numeric($value) && is_int($value + 0) && ($value + 0) > 0 ) return true;
return $field.'必须是正整数';
}
}
利用AOP思想的验证器
- 首先创立一个基类验证器
我们就拿最常接受的数据来举例子,那就是 id 同常这个id就代表了我们数据库中某条数据的id,这个id我们往往设计为无符号自动递增的主键,翻译成人话就是正整数。那么如果客户传来的参数是负数或者小数那么就不应该通过验证。
我们根据上述需求,我们来创建一个验证器。位置还是跟之前的一样在validate文件夹下
namespace app\validate;
use app\lib\exception\ParameterException;
use think\Request;
use think\Validate;
class BaseValidate extends Validate
{
/**
* 检测客户端发来的参数是否符合验证类参数
* @return bool
* @throws ParameterException
*/
public function goCheck()
{
$request = Request::instance();
$params = $request->param();
if( ! $this->batch()->check($params) ){
$error = $this->error;
if( is_array($error) ){
$error = implode(';',$error);
}
throw new ParameterException(['msg' => $error]);
}
return true;
}
/**
* 判断是否是正整数
* 系统会自动传入几个参数
* 第一个是 要验证的值
* 第二个是规则自己可以规定规则内容或者不写
* 第三个是最初传入的data
* 其实不只这三个参数,想了解详细的可以看看文档
* @param $value
* @param $rule
* @param $data
* @param $field
* @param $fieldDesc
* @return bool|string
*/
protected function isPositiveInteger($value, $rule, $data, $field,$fieldDesc)
{
if (is_numeric($value) && is_int($value + 0) && ($value + 0) > 0) {
return true;
}
return $field . '必须是正整数';
}
}
- 然后再建立一个派生类
namespace app\validate;
class UserValidate extends BaseValidate
{
protected $rule = [
'name' => 'require|max:25',
//require是内置规则,而tp5并没有正整数的规则,所以下面这个isPositiveInteger使用自定义的规则
'age' => 'require|isPositiveInteger|between:18,120',
'email' => 'require|email',
];
}
- 使用验证器
public function test($id)
{
//在控制器中直接调用写上这行代码就搞定验证了
(new UserValidate)->goCheck();
// todo 后续的逻辑
return json('验证通过',200);
}
就这样的一句代码,直接搞定验证。
当我们实例化id验证器,调用它父类的goCheck方法。
goCheck方法会接受参数,并且将参数传入validate对象上check方法
就会去匹配我们在id验证器中$rule中规定的require规则和我们自定义的规则。
如果都通过就会返回true。
如果其中一条不匹配则会抛出异常。
这次只举了id为例子,虽然看上去比直接写独立验证麻烦很多,但是大家仔细想想,这个验证规则其实在很多地方都是一样的,比如密码验证规则,用户名验证规则等,当这个项目写完了。你已经完成了很多验证器。其实在下个项目中还可以继续套用的哦
参考文章:https://www.jianshu.com/p/1fb961dcab7f