Yii2的rule用于对模型属性进行验证,scenario用户定义不同场景下需要验证的模型,下面这篇文章主要给大家介绍了关于Yii2中场景(scenario)和验证规则(rule)的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下。
前言
场景,顾名思义,就是一个情景,一种场面。在yii2中也有场景,这个场景跟你所理解的场景含义差不多。
和用户有交互的系统必不可少的功能包括收集用户数据、校验和处理。实际业务中,往往还需要将数据进行持久化存储。出于安全考虑,开发人员应当牢牢把握“客户端的输入都是不可信”的准则,客户端传过来的数据先进行过滤和清洗后再存储或传递到内部系统。
Yii2推荐使用Model类来收集和校验用户数据,持久化的ActiveRecord类是其子类。Model类的load和validate两个方法,分别用来收集和校验客户端数据。哪些数据应该被收集,哪些数据需要在什么场景下验证,便是本文的主题:场景(scenario)和验证规则(rule)。
下面话不多说了,来随着小编一起看看详细的介绍吧。
系统结构
先引入一个简单的业务系统:系统中存在学生和教师两种角色,数据库中使用了三张表保存角色信息:
user: [id, username, password, status, 其他通用属性]
student: [id, user_id, student_no, grade, class, 其他学生属性]
teacher: [id, user_id, work_no, title, telphone, 其他教师属性]
实际业务不限于对这三张表的增删查改操作。为了简化问题,后续仅讨论user和student两张表的数据变更(给出teacher表是为了让读者不认为设计数据库的人是脑残:明明可以放到一张表的,为什么要拆开!)。
学生报名
学生报名是典型的增删查改操作,送分题。学生报名的简要代码示例如下:
public function actionSignup() { $data = Yii::$app->request->post(); $user = new User(); $user->load($data); if ($user->save()) { $student = new Student([ "user_id" => $user->id, ]); $student->load($data); if ($student->save()) { // redirect to success page } else { $user->delete(); } } // render error page }
相信有Yii2使用经验的人都能根据数据库的字段约束快速的把User和Student类的rules方法写出来。例如User类文件内容可能如下:
namespace app\models; class User extends \yii\db\ActiveRecord { public function rules() { return [ [["username", "password", "status",], "required"], ["username", "unique"], // other rules ]; } // other method }
定义数据的验证规则,这是大多数人对rules的第一印象,并且是一个很好的印象:它打回非法的数据,让正常的数据进入系统中。安全的实践应该尽量定义完整的规则,充分验证数据。也建议每一个Yii2开发人员对内置的核心校验器熟悉。
修改信息
修改信息,也是典型的增删查改操作。实现代码和报名差别不大,这里仅讨论两点:
1、用户密码的验证
注册时会校验用户密码是否8-16位,密码的规则可能是: ["password", "string", "length" => [8, 16]]
。明文保存密码是不可取的,插入数据库时至少会做MD5加密,password变成32位。假设用户修改信息时未修改密码,再次保存时密码规则校验出错(长度不符合),无法保存!
怎么解决这个问题呢?翻阅Yii文档,发现了规则中的when属性可以救场。一种可能的验证规则是:
public function rules() { return [ ["password", "string", "length" => [8, 16], 'when' => function ($model) { return $model->isNewRecord; }], // other rules ];
只有在注册(新增数据)时才校验密码字段。问题解决,完美!
2、防止用户私自改密码
假设有个小聪明的家伙(例如汤姆),发现系统是用Yii框架做的,想搞点小破坏炫耀一下水平。在发送修改信息的表单时,汤姆增加&password=12345678这一段数据。系统使用$user->load($data)
收集用户输入,更新password字段,带来如下后果:rules设置更新时不校验密码字段,12345678直接作为password的值保存到数据库中。这个操作带来连锁反应:用户再次登录时,加密过后的密码与数据库中的明文密码不匹配,导致汤姆无法登录系统。烦人的是汤姆是个刺头,登录不上后整天骚扰客服,不省心!
怎么样防止这种情况出现呢?一种解决的方法是阻止修改密码:
unset($data["password"]); $user->load($data); // 或者 $password = $user->password; $user->load($data); $user->password = $password;
把用户输入的密码过滤掉,私自修改密码的问题就解决了。
但是问题还没有结束:汤姆可以转向修改其他字段,比如说性别,身份证等。更严重情况是修改student中user_id,就可以更改任意学生的信息。事情十分严重,需要马上修复漏洞。
可以按照密码的方法,逐个屏蔽受保护属性,但显得啰嗦难看(虽然好使)。如果受保护属性多,可以仅允许白名单进入,具体操作为:新增一个UpdateInfoForm类继承Model,属性是白名单属性合计。用UpdateInfoForm类过滤用户数据,校验通过后再更新到user和student中:
$form = new UpdateInfoForm(); $form->load($data); if ($form->validate()) { $user->load($form->attributes); $student->load($form->attributes); // next biz }
这种方式更优雅,但仔细一想代价不小:属性和验证规则要重复写一遍;user和student保存时又重复校验属性。这种方式看起来优雅,实际上却冗余又低效。
scenario的登场,完美的解决解决上述问题。
场景(scenario)
分析上面问题,会发现关键点是批量赋值(massive assignment)和数据校验(validate)两个方法。如果对不同的场景指定赋值字段和检验规则,问题就迎刃而解。
Yii中的scenario有 安全属性 和 活跃属性 两个概念。安全属性用在批量赋值的load方法,只有安全属性才能被赋值;活跃属性用在规则校验的validate方法,在活跃属性集中并且定义了校验规则的属性才会被校验。活跃属性和安全属性的关系是,安全属性是活跃属性的子集。
\yii\base\Model类定义了默认场景:SCENARIO_DEFAULT(值为default)。默认场景下,出现在rules方法中的属性既是活跃属性,又是安全属性(这句话基本正确,看后续解释)。为不同场景指定活跃属性、安全属性以及校验器,可以通过覆盖senarios或rules两个方法实现(几乎每个Model类都会重写rules方法,senarios用得少)。
rules
先看rules方法。默认的属性加校验器定义方式,让每个属性既是安全属性,也是活跃属性。如果想让某个属性不是安全属性(不能通过load批量赋值),在属性名前加感叹号!即可。例如student中的user_id字段:
public function rules() { return [ ["!user_od", "required"], ["!user_id", "integer"], ["!user_od", "unique"], // other rules ]; }
user_id是活跃属性,在写入数据库时会被校验。但它不是安全属性,不能通过load方法进行赋值,解决了安全隐患。
再看rules方法按场景区分校验器规则的做法:定义校验器时on属性指定规则在哪些场景下生效,except属性则排除一些场景(如果不指定on和except,规则对所有场景生效)。例如:
public function rules() { return [ ["password", "string", "length" => [8, 16], "on" => ["signup"]], // 仅在signup场景时才被验证 ["status", "integer", "except" => ["signup"], // 除了signup场景,其他情况都校验 // other rules ]; }
在原来基础上新增感叹号和on/except属性,非常简便的就定义了非安全属性以及分场景指定校验规则。
scenarios
另外一种更清晰定义安全属性和活跃属性的做法是重写scenarios方法。scenarios方法返回一个数组,数组的键是场景名称,值是活跃属性集合(包饭安全属性)。例如student表的可能实现如下:
public function scenarios() { return [ self::SCENARIO_DEFAULT => ["!user_id", "grade", "class", xxxx], "update" => ["grade", "class", xxxx], ]; }
默认情形下(学生报名),年级、班级这些信息是安全属性,但user_id不是,只能在程序内部赋值,并在插入数据时被校验;在修改信息时,user_id不是活跃属性,既不能被批量赋值,也不需要校验(事实上它不应该改变)。
scenarios方法只能定义活跃属性和安全属性,无法定义校验规则,需要和rules配合使用。
总结
金肯定义完善的数据校验规则
业务复杂时定义多个场景,仔细为每个场景定义安全属性和校验规则
优先使用rules;属性较多、rules复杂时,可以配合scenarios方法迅速理清安全属性和活跃属性
参考
http://www.yiiframework.com/doc-2.0/guide-input-validation.html
您可能感兴趣的文章:
MixPHP、Yii和CodeIgniter的并发压力测试的小结
PHP基于非递归算法实现先序、中序及后序遍历二叉树操作的示例
以上是Yii2中的场景(scenario)和验证规则(rule)的详解的详细内容。更多信息请关注PHP中文网其他相关文章!

PHP主要是过程式编程,但也支持面向对象编程(OOP);Python支持多种范式,包括OOP、函数式和过程式编程。PHP适合web开发,Python适用于多种应用,如数据分析和机器学习。

PHP起源于1994年,由RasmusLerdorf开发,最初用于跟踪网站访问者,逐渐演变为服务器端脚本语言,广泛应用于网页开发。Python由GuidovanRossum于1980年代末开发,1991年首次发布,强调代码可读性和简洁性,适用于科学计算、数据分析等领域。

PHP适合网页开发和快速原型开发,Python适用于数据科学和机器学习。1.PHP用于动态网页开发,语法简单,适合快速开发。2.Python语法简洁,适用于多领域,库生态系统强大。

PHP在现代化进程中仍然重要,因为它支持大量网站和应用,并通过框架适应开发需求。1.PHP7提升了性能并引入了新功能。2.现代框架如Laravel、Symfony和CodeIgniter简化开发,提高代码质量。3.性能优化和最佳实践进一步提升应用效率。

PHPhassignificantlyimpactedwebdevelopmentandextendsbeyondit.1)ItpowersmajorplatformslikeWordPressandexcelsindatabaseinteractions.2)PHP'sadaptabilityallowsittoscaleforlargeapplicationsusingframeworkslikeLaravel.3)Beyondweb,PHPisusedincommand-linescrip

PHP类型提示提升代码质量和可读性。1)标量类型提示:自PHP7.0起,允许在函数参数中指定基本数据类型,如int、float等。2)返回类型提示:确保函数返回值类型的一致性。3)联合类型提示:自PHP8.0起,允许在函数参数或返回值中指定多个类型。4)可空类型提示:允许包含null值,处理可能返回空值的函数。

PHP中使用clone关键字创建对象副本,并通过\_\_clone魔法方法定制克隆行为。1.使用clone关键字进行浅拷贝,克隆对象的属性但不克隆对象属性内的对象。2.通过\_\_clone方法可以深拷贝嵌套对象,避免浅拷贝问题。3.注意避免克隆中的循环引用和性能问题,优化克隆操作以提高效率。

PHP适用于Web开发和内容管理系统,Python适合数据科学、机器学习和自动化脚本。1.PHP在构建快速、可扩展的网站和应用程序方面表现出色,常用于WordPress等CMS。2.Python在数据科学和机器学习领域表现卓越,拥有丰富的库如NumPy和TensorFlow。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

SublimeText3 Linux新版
SublimeText3 Linux最新版

EditPlus 中文破解版
体积小,语法高亮,不支持代码提示功能

PhpStorm Mac 版本
最新(2018.2.1 )专业的PHP集成开发工具

MinGW - 适用于 Windows 的极简 GNU
这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

ZendStudio 13.5.1 Mac
功能强大的PHP集成开发环境