# 增加验证
由于我们使用的是基于html5的浏览器,所以当我们把input的type值设置为email时,会对输入的值是否为正确的邮箱进行验证。如下图所示:
![](https://box.kancloud.cn/2016-06-14_575fa8c0379b2.png)
但我们也应该非常清楚的认识到,并不是所有的用户都在使用基于HTML5的浏览器。也就是说,仅仅靠前台的验证并不可靠。
**<span class="text-danger">实际的生产环境更是这样:用户不但可以使用非html5的浏览器,还可以使用一些其它的软件来直接进行数据的POST操作。</span>**
> 前台的验证目的是为了提升用户的使用感受; 后台验证的目的,是为了保证数据的合法性。两者相辅相成,缺一不可。
## 暂时去除前台的email验证
我们将
~~~
<input type="email" name="email" />
~~~
修改为:
~~~
<input type="text" name="email" />
~~~
测试结果如下图所示:
![](https://box.kancloud.cn/2016-06-14_575fa8c04c022.png)
![](https://box.kancloud.cn/2016-06-14_575fa8c060f64.png)
我们发现,非法的邮箱被传入了。
# 开启验证
> 官方参考文档:http://www.kancloud.cn/manual/thinkphp5/129319 http://www.kancloud.cn/manual/thinkphp5/129355
使用验证以前,我们需要先用Teacher模型新建一个验证模型。 其实不用太纠结『模型』这个字眼,简单理解一下,模型就是一个类。之所以这样叫,我们现在仅仅是为了区分『控制器』这个名词,因为控制器也是一个类。很显然,虽然大家都是类,但是我们还是想把它们区分开。
增加如下验证文件:
~~~
<?php
namespace app\common\validate;
use think\Validate; // 内置验证类
class Teacher extends Validate
{
protected $rule = [
'email' => 'email',
];
}
~~~
> 是的,文件的位置必须放在application\common\validate 下,并且,必须和我们的数据表模型名称一致。 因为只有这样,thinkphp这个框架才能找到它。
修改C层代码,加入验证信息:
~~~
public function insert()
{
// 接收传入数据
$postData = Request::instance()->post();
// 实例化Teacher空对象
$Teacher = new Teacher();
// 为对象赋值
$Teacher->name = $postData['name'];
$Teacher->username = $postData['username'];
$Teacher->sex = $postData['sex'];
$Teacher->email = $postData['email'];
// 新增对象至数据表
$result = $Teacher->validate(true)->save($Teacher->getData());
// 反馈结果
if (false === $result)
{
return '新增失败:' . $Teacher->getError();
} else {
return '新增成功。新增ID为:' . $Teacher->id;
}
}
~~~
我们发现,增加自动验证后,即使字段中全部有值,也会产生错误。
测试:
![](https://box.kancloud.cn/2016-06-14_575fa8c094b0c.png)
## 改写框架
刚刚我们虽然实现了新增数据验证的目的,但实现的并不完美。
我们更希望看到:
~~~
// 新增对象至数据表
$result = $Teacher->validate(true)->save();
~~~
而不是:
~~~
// 新增对象至数据表
$result = $Teacher->validate(true)->save($Teacher->getData());
~~~
原因很简单的,上面的写法才是真正的面象对象。正确的思想是:我们给一个对象赋值,然后对这个对象进行验证。显然,上面的写法更贴近我们的真实想法。
ThinkPHP是一个开源的软件,我们可以在Github中,找到它的身影 。下一个贡献者会不会就是你呢?
在这里,为了更好的实现验证,我们对`think\Model`及`think\Validate`类进行改写。
* * * * *
> 如果你并不想动框架的源代码,那么可以略过下面本节中我们下面要讲的内容。只需要在以后涉及到验证操作时,使用`$Teacher->validate(true)->save($Teacher->getData());`即可。
* * * * *
一、`think\Model`类文件的位于`thinkphp/library/think/Model.php`
1、我们找到其中的save方法,改写前:
~~~
public function save($data = [], $where = [], $sequence = null)
{
if (!empty($data)) {
// 数据自动验证
if (!$this->validateData($data)) {
return false;
}
// 数据对象赋值
foreach ($data as $key => $value) {
$this->setAttr($key, $value, $data);
}
if (!empty($where)) {
$this->isUpdate = true;
}
}
// 检测字段
if (!empty($this->field)) {
$this->db();
foreach ($this->data as $key => $val) {
if (!in_array($key, $this->field)) {
unset($this->data[$key]);
}
}
}
...
~~~
改写后:
~~~
public function save($data = [], $where = [], $sequence = null)
{
if (!empty($data)) {
// 数据自动验证
if (!$this->validateData($data)) {
return false;
}
// 数据对象赋值
foreach ($data as $key => $value) {
$this->setAttr($key, $value, $data);
}
if (!empty($where)) {
$this->isUpdate = true;
}
// 未传入数据,则依新增与更新分别进行验证 --- 梦云智
} else {
// 更新,只验证有变化的值
if ($this->isUpdate && !empty($this->change)) {
foreach ($this->change as $value) {
$data[$value] = $this->getData($value);
}
// 新增,验证全部的值
} else {
$data = $this->getData();
}
// 数据自动验证
if (!$this->validateData($data, $this->isUpdate)) {
return false;
}
}
// 检测字段
if (!empty($this->field)) {
$this->db();
foreach ($this->data as $key => $val) {
if (!in_array($key, $this->field)) {
unset($this->data[$key]);
}
}
}
...
~~~
2、我们再找到该文件中的validateData方法
改写前:
~~~
/**
* 自动验证数据
* @access protected
* @param array $data 验证数据
* @return bool
*/
protected function validateData($data)
...
$validate = Loader::validate($name);
if (!empty($scene)) {
$validate->scene($scene);
}
}
if (!$validate->check($data)) {
...
~~~
改写后:
~~~
/**
* 自动验证数据
* @access protected
* @param array $data 验证数据
* @param bool $isUpdate 是否为数据的更新操作 --- 梦云智
* @return bool
*/
protected function validateData($data, $isUpdate = false)
...
$validate = Loader::validate($name);
if (!empty($scene)) {
$validate->scene($scene);
}
}
// 进行数据更新操作则只验证有变化的字段 --- 梦云智
if ($isUpdate) {
$validate->reMakeRule($data);
}
if (!$validate->check($data)) {
...
~~~
二、 `think\Validate`类文件的位于`thinkphp/library/think/Validate.php`
在类中新增`reMakeRule`方法,比如我在`rule()方法`后后面进行添加。
~~~
/**
* 重新生成规则 (删除规则中不存在的更新字段规则 )
* @param array $datas 要验证的数据
* @return
* @author panjie@yunzhiclub.com http://www.mengyunzhi.com
* @DateTime 2016-10-21T13:13:44+0800
*/
public function reMakeRule($datas = [])
{
$rule = [];
if (is_array($datas)) {
foreach ($datas as $key => $data) {
if (array_key_exists($key, $this->rule)) {
$rule[$key] = $this->rule[$key];
}
}
}
$this->rule = $rule;
}
~~~
有了上述代码后,我们在C层就可以这样使用了。
~~~
// 新增对象至数据表
$result = $Teacher->validate(true)->save();
~~~
测试:
![](https://box.kancloud.cn/2016-06-14_575fa8c094b0c.png)
~~~
git checkout -f step3.3.5.1
~~~
虽然只更改了几处代码,但仍然存在一定的难度。为此,我们在代码仓库中已经为大家改写好了上述两个文件。我们强烈建议你执行完`git checkout -f step3.3.5.1`后,将上述的两个文件复制到你的项目当中(由thinkphp5guide复制到thinkphp5中)。
如果你还没有安装git,那么可以点击如下链接,下载我们在百度网盘中为你准备好的文件。
https://pan.baidu.com/s/1kVHeIaj#list/path=%2FThinkphp5%E5%85%A5%E9%97%A8%E5%AE%9E%E4%BE%8B%E6%95%99%E7%A8%8B%2Fthinkphp%2Flibrary%2Fthink
## 实际项目的验证方法
在实际的项目开发中,我们不但需要对邮箱格式是否有误进行验证,还需要对用户名的最大最小长度,用户姓名的最大最小长度,传入的性别非0即1等,进行验证。
按上述要求,我们对验证规则进行改写:
> 参考官方手册:http://www.kancloud.cn/manual/thinkphp5/129356
~~~
<?php
namespace app\common\validate;
use think\Validate; // 内置验证类
class Teacher extends Validate
{
protected $rule = [
'username' => 'require|unique:teacher|length:4,25',
'name' => 'require|length:2,25',
'sex' => 'in:0,1',
'email' => 'email',
];
}
~~~
是的,我并没有去写错误提示信息,因为thinkphp已经给我们内置了错误提示信息。只有当我们认为thinkphp内置的错误提示信息不符合我们的要求时,我们才会去自已定义。
## 再说测试
我们一直在强调测试的方法,上面的验证规则写完以后,我们当然首先想的就是继续利用form表单进行验证。但我想说的是,如果是那样的话,我们在更改验证规则时,刷新页面,重新添加数据,然后重新提交后查看验结果。显然,效率有一点低。
恰当的方法是我们新建一个专门用于做测试的方法,在实际的项目开发中,我们往往会专门的新建一个控制器专门用来做测试使用。
> 控制器验证 http://www.kancloud.cn/manual/thinkphp5/129354
通过查看官方手册我们得之,除了可以直接在模型中自动关联验证外,还可以在控制器中进行自动关联验证。在这里,我们采用在控制器中直接调用验证方法来进行测试。
示例代码:
验证username为空是否报错的示例代码:
~~~
...
namespace app\index\controller;
class TeacherController extends Controller
{
...
public function test()
{
$data = array();
$data['username'] = '';
$data['name'] = '1';
$data['sex'] = '1';
$data['email'] = 'hello@hello.com';
var_dump($this->validate($data, 'Teacher'));
}
...
}
~~~
测试结果如下图所示:
![](https://box.kancloud.cn/0d87ca78167e47d96bf0480855d01775_866x70.png)
下面,再给出几组测试的示例代码。
测试用户名是否被占用:
~~~
public function test()
{
$data = array();
$data['username'] = 'ceshi';
$data['name'] = '1';
$data['sex'] = '1';
$data['email'] = 'hello@hello.com';
var_dump($this->validate($data, 'Teacher'));
}
~~~
测试用户名是否过短:
~~~
public function test()
{
$data = array();
$data['username'] = 'ce';
$data['name'] = '1';
$data['sex'] = '1';
$data['email'] = 'hello@hello.com';
var_dump($this->validate($data, 'Teacher'));
}
~~~
其它测试信息,请自己尝试修改。
### 还原V层
~~~
<input type="email" name="email" />
~~~
~~~
git checkout -f step3.3.5.2
~~~
**提醒:**
**试读章节**到此为止,如果你还希望继续和我们一起学习,请打开网址:http://www.kancloud.cn/yunzhiclub/thinkphp5guide 点击【试读】按钮右边的【购买】按钮进行购买,购买后可继续学习后续章节的内容。
> 为便于大家交流,我们新近申请了QQ群,群号:338438158。我们期待在群中看到您的身影 ,并殷切地期望当其他的小伙伴遇到相同的问题时,您能伸出援助之手。
- 序言
- 第一章 准备知识
- 第一节:XAMPP
- 第二节:NAVICAT
- 第三节:GIT
- 第二章 HelloWorld
- 第一节:下载THINPHP5.0
- 第二节:启动xampp
- 第三节:hello thinkphp
- 第四节:Hello world
- 第五节:MCA
- 第六节:单引号与双引号
- 第三章 教师管理
- 第一节:新建数据库
- 第二节:CURD之R 读数据
- 3.2.1 时序图
- 3.2.2 连接数据库
- 3.2.3 直接读取数据
- 3.2.4 间接读取数据
- 3.2.5 使用V层显示数据
- 3.2.6 引入bootstrap
- 3.2.7 加入bootstrap样式
- 第三节:CURD之 C 增加数据
- 3.3.1 插入数据
- 3.3.2 表单传值
- 3.3.3 存储表单数据
- 3.3.4 自动时间戳
- 3.3.5 增加验证
- 第四节:CURD之 D 删除数据
- 3.4.1 什么是关键字
- 3.4.2 删除数据
- 3.4.3 定制删除链接
- 3.4.4 完善删除
- 第五节:CURD之 U 更新数据
- 3.5.1 读取数据
- 3.5.2 展示数据
- 3.5.3 修改数据
- 3.5.4 传递数据
- 3.5.5 接收数据
- 3.5.6 更新数据 方法一
- 3.5.7 更新数据 方法二
- 第六节:衔接各个action & 重构代码
- 3.6.1 index action
- 3.6.2 add action
- 3.6.3 insert action
- 3.6.4 delete action
- 3.6.5 edit action
- 3.6.6 update action
- 第七节:分页
- 3.7.1 调用内置分页
- 3.7.2 select与paginate(选学)
- 3.7.3 分页原理(选学)
- 3.7.4 调用page(选学)
- 第八节:模糊查询
- 3.8.1 增加查询
- 3.8.2 完善查询
- 第四章 登录与注销
- 第一节:cookie 与 session
- 第二节:静态方法
- 第三节:规划URL跳转
- 第四节:登录
- 4.4.1 登录流程
- 4.4.2 index action
- 4.4.3 login action
- 4.4.4 引入M层
- 4.4.5 异常Exception
- 第五节:注销
- 第六节:验证
- 4.6.1 action增加验证
- 4.6.2 使用构造函数验证
- 4.6.3 使用继承验证
- 第五章 E-R图与数据字典
- 第一节:第一张E-R图
- 第二节:实体间的关系
- 第三节:开发规范
- 第六章 班级管理
- 第一节:建立数据表
- 第二节:数据列表index
- 第三节:增加数据add
- 第四节:编辑数据edit
- 第五节:删除数据delete
- 第七章 学生管理
- 第一节:建立数据表
- 第二节:数据列表
- 7.2.1 显示性别
- 7.2.2 显示创建时间
- 7.2.3 显示班级名称
- 7.2.4 显示辅导员姓名
- 第三节:编辑数据
- 第四节:魔法函数
- 第五节:源码分析
- 第八章 课程管理
- 第一节:建立数据表
- 第二节:新增课程
- 第三节:编辑课程
- 8.3.1 edit
- 8.3.2 update
- 第九章 代码重构
- 第一节:add 与 edit
- 第二节:insert 与 update
- 第三节:模板继承
- 9.3.1 index.html
- 9.3.2 edit.html
- 9.3.3 小结
- 第十章 UML图
- 第一节:E-R图回顾
- 第二节:UML图
- 第十一章 菜单与路由
- 第一节:添加菜单
- 第二节:虚拟主机
- 第三节:定制路由
- 第十二章 开发调试
- 第一节:开启trace
- 第二节:查看日志
- 第十三章:总结