欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Yii2中的場(chǎng)景(scenario)和驗(yàn)證規(guī)則(rule)詳解

 更新時(shí)間:2018年01月14日 11:38:10   作者:tlanyan  
Yii2的rule用于對(duì)模型屬性進(jìn)行驗(yàn)證,scenario用戶定義不同場(chǎng)景下需要驗(yàn)證的模型,下面這篇文章主要給大家介紹了關(guān)于Yii2中場(chǎng)景(scenario)和驗(yàn)證規(guī)則(rule)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下。

前言

場(chǎng)景,顧名思義,就是一個(gè)情景,一種場(chǎng)面。在yii2中也有場(chǎng)景,這個(gè)場(chǎng)景跟你所理解的場(chǎng)景含義差不多。

和用戶有交互的系統(tǒng)必不可少的功能包括收集用戶數(shù)據(jù)、校驗(yàn)和處理。實(shí)際業(yè)務(wù)中,往往還需要將數(shù)據(jù)進(jìn)行持久化存儲(chǔ)。出于安全考慮,開(kāi)發(fā)人員應(yīng)當(dāng)牢牢把握“客戶端的輸入都是不可信”的準(zhǔn)則,客戶端傳過(guò)來(lái)的數(shù)據(jù)先進(jìn)行過(guò)濾和清洗后再存儲(chǔ)或傳遞到內(nèi)部系統(tǒng)。

Yii2推薦使用Model類(lèi)來(lái)收集和校驗(yàn)用戶數(shù)據(jù),持久化的ActiveRecord類(lèi)是其子類(lèi)。Model類(lèi)的load和validate兩個(gè)方法,分別用來(lái)收集和校驗(yàn)客戶端數(shù)據(jù)。哪些數(shù)據(jù)應(yīng)該被收集,哪些數(shù)據(jù)需要在什么場(chǎng)景下驗(yàn)證,便是本文的主題:場(chǎng)景(scenario)和驗(yàn)證規(guī)則(rule)。

下面話不多說(shuō)了,來(lái)隨著小編一起看看詳細(xì)的介紹吧。

系統(tǒng)結(jié)構(gòu)

先引入一個(gè)簡(jiǎn)單的業(yè)務(wù)系統(tǒng):系統(tǒng)中存在學(xué)生和教師兩種角色,數(shù)據(jù)庫(kù)中使用了三張表保存角色信息:

user: [id, username, password, status, 其他通用屬性]

student: [id, user_id, student_no, grade, class, 其他學(xué)生屬性]

teacher: [id, user_id, work_no, title, telphone, 其他教師屬性]

實(shí)際業(yè)務(wù)不限于對(duì)這三張表的增刪查改操作。為了簡(jiǎn)化問(wèn)題,后續(xù)僅討論user和student兩張表的數(shù)據(jù)變更(給出teacher表是為了讓讀者不認(rèn)為設(shè)計(jì)數(shù)據(jù)庫(kù)的人是腦殘:明明可以放到一張表的,為什么要拆開(kāi)!)。

學(xué)生報(bào)名

學(xué)生報(bào)名是典型的增刪查改操作,送分題。學(xué)生報(bào)名的簡(jiǎn)要代碼示例如下:

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使用經(jīng)驗(yàn)的人都能根據(jù)數(shù)據(jù)庫(kù)的字段約束快速的把User和Student類(lèi)的rules方法寫(xiě)出來(lái)。例如User類(lèi)文件內(nèi)容可能如下:

namespace app\models;
class User extends \yii\db\ActiveRecord
{
 public function rules()
 {
  return [   [["username", "password", "status",], "required"],
   ["username", "unique"],
   // other rules
  ];
 }
 // other method
}

定義數(shù)據(jù)的驗(yàn)證規(guī)則,這是大多數(shù)人對(duì)rules的第一印象,并且是一個(gè)很好的印象:它打回非法的數(shù)據(jù),讓正常的數(shù)據(jù)進(jìn)入系統(tǒng)中。安全的實(shí)踐應(yīng)該盡量定義完整的規(guī)則,充分驗(yàn)證數(shù)據(jù)。也建議每一個(gè)Yii2開(kāi)發(fā)人員對(duì)內(nèi)置的核心校驗(yàn)器熟悉。

修改信息

修改信息,也是典型的增刪查改操作。實(shí)現(xiàn)代碼和報(bào)名差別不大,這里僅討論兩點(diǎn):

1、用戶密碼的驗(yàn)證

注冊(cè)時(shí)會(huì)校驗(yàn)用戶密碼是否8-16位,密碼的規(guī)則可能是: ["password", "string", "length" => [8, 16]] 。明文保存密碼是不可取的,插入數(shù)據(jù)庫(kù)時(shí)至少會(huì)做MD5加密,password變成32位。假設(shè)用戶修改信息時(shí)未修改密碼,再次保存時(shí)密碼規(guī)則校驗(yàn)出錯(cuò)(長(zhǎng)度不符合),無(wú)法保存!

怎么解決這個(gè)問(wèn)題呢?翻閱Yii文檔,發(fā)現(xiàn)了規(guī)則中的when屬性可以救場(chǎng)。一種可能的驗(yàn)證規(guī)則是:

public function rules()
{
 return [
   ["password", "string", "length" => [8, 16], 'when' => function ($model) {
    return $model->isNewRecord;
   }],
   // other rules
  ];

只有在注冊(cè)(新增數(shù)據(jù))時(shí)才校驗(yàn)密碼字段。問(wèn)題解決,完美!

2、防止用戶私自改密碼

假設(shè)有個(gè)小聰明的家伙(例如湯姆),發(fā)現(xiàn)系統(tǒng)是用Yii框架做的,想搞點(diǎn)小破壞炫耀一下水平。在發(fā)送修改信息的表單時(shí),湯姆增加&password=12345678這一段數(shù)據(jù)。系統(tǒng)使用$user->load($data)收集用戶輸入,更新password字段,帶來(lái)如下后果:rules設(shè)置更新時(shí)不校驗(yàn)密碼字段,12345678直接作為password的值保存到數(shù)據(jù)庫(kù)中。這個(gè)操作帶來(lái)連鎖反應(yīng):用戶再次登錄時(shí),加密過(guò)后的密碼與數(shù)據(jù)庫(kù)中的明文密碼不匹配,導(dǎo)致湯姆無(wú)法登錄系統(tǒng)。煩人的是湯姆是個(gè)刺頭,登錄不上后整天騷擾客服,不省心!

怎么樣防止這種情況出現(xiàn)呢?一種解決的方法是阻止修改密碼:

unset($data["password"]); 
$user->load($data);
// 或者
$password = $user->password;
$user->load($data);
$user->password = $password;

把用戶輸入的密碼過(guò)濾掉,私自修改密碼的問(wèn)題就解決了。

但是問(wèn)題還沒(méi)有結(jié)束:湯姆可以轉(zhuǎn)向修改其他字段,比如說(shuō)性別,身份證等。更嚴(yán)重情況是修改student中user_id,就可以更改任意學(xué)生的信息。事情十分嚴(yán)重,需要馬上修復(fù)漏洞。

可以按照密碼的方法,逐個(gè)屏蔽受保護(hù)屬性,但顯得啰嗦難看(雖然好使)。如果受保護(hù)屬性多,可以僅允許白名單進(jìn)入,具體操作為:新增一個(gè)UpdateInfoForm類(lèi)繼承Model,屬性是白名單屬性合計(jì)。用UpdateInfoForm類(lèi)過(guò)濾用戶數(shù)據(jù),校驗(yàn)通過(guò)后再更新到user和student中:

$form = new UpdateInfoForm();
$form->load($data);
if ($form->validate()) {
 $user->load($form->attributes);
 $student->load($form->attributes);
 // next biz
}

這種方式更優(yōu)雅,但仔細(xì)一想代價(jià)不?。簩傩院万?yàn)證規(guī)則要重復(fù)寫(xiě)一遍;user和student保存時(shí)又重復(fù)校驗(yàn)屬性。這種方式看起來(lái)優(yōu)雅,實(shí)際上卻冗余又低效。

scenario的登場(chǎng),完美的解決解決上述問(wèn)題。

場(chǎng)景(scenario)

分析上面問(wèn)題,會(huì)發(fā)現(xiàn)關(guān)鍵點(diǎn)是批量賦值(massive assignment)和數(shù)據(jù)校驗(yàn)(validate)兩個(gè)方法。如果對(duì)不同的場(chǎng)景指定賦值字段和檢驗(yàn)規(guī)則,問(wèn)題就迎刃而解。

Yii中的scenario有 安全屬性 和 活躍屬性 兩個(gè)概念。安全屬性用在批量賦值的load方法,只有安全屬性才能被賦值;活躍屬性用在規(guī)則校驗(yàn)的validate方法,在活躍屬性集中并且定義了校驗(yàn)規(guī)則的屬性才會(huì)被校驗(yàn)?;钴S屬性和安全屬性的關(guān)系是,安全屬性是活躍屬性的子集。

\yii\base\Model類(lèi)定義了默認(rèn)場(chǎng)景:SCENARIO_DEFAULT(值為default)。默認(rèn)場(chǎng)景下,出現(xiàn)在rules方法中的屬性既是活躍屬性,又是安全屬性(這句話基本正確,看后續(xù)解釋?zhuān)椴煌瑘?chǎng)景指定活躍屬性、安全屬性以及校驗(yàn)器,可以通過(guò)覆蓋senarios或rules兩個(gè)方法實(shí)現(xiàn)(幾乎每個(gè)Model類(lèi)都會(huì)重寫(xiě)rules方法,senarios用得少)。

rules

先看rules方法。默認(rèn)的屬性加校驗(yàn)器定義方式,讓每個(gè)屬性既是安全屬性,也是活躍屬性。如果想讓某個(gè)屬性不是安全屬性(不能通過(guò)load批量賦值),在屬性名前加感嘆號(hào)!即可。例如student中的user_id字段:

public function rules()
{
 return [
  ["!user_od", "required"],
  ["!user_id", "integer"],
  ["!user_od", "unique"],
  // other rules
 ];
}

user_id是活躍屬性,在寫(xiě)入數(shù)據(jù)庫(kù)時(shí)會(huì)被校驗(yàn)。但它不是安全屬性,不能通過(guò)load方法進(jìn)行賦值,解決了安全隱患。

再看rules方法按場(chǎng)景區(qū)分校驗(yàn)器規(guī)則的做法:定義校驗(yàn)器時(shí)on屬性指定規(guī)則在哪些場(chǎng)景下生效,except屬性則排除一些場(chǎng)景(如果不指定on和except,規(guī)則對(duì)所有場(chǎng)景生效)。例如:

public function rules()
{
 return [
  ["password", "string", "length" => [8, 16], "on" => ["signup"]], // 僅在signup場(chǎng)景時(shí)才被驗(yàn)證
  ["status", "integer", "except" => ["signup"], // 除了signup場(chǎng)景,其他情況都校驗(yàn)
  // other rules
 ];
}

在原來(lái)基礎(chǔ)上新增感嘆號(hào)和on/except屬性,非常簡(jiǎn)便的就定義了非安全屬性以及分場(chǎng)景指定校驗(yàn)規(guī)則。

scenarios

另外一種更清晰定義安全屬性和活躍屬性的做法是重寫(xiě)scenarios方法。scenarios方法返回一個(gè)數(shù)組,數(shù)組的鍵是場(chǎng)景名稱(chēng),值是活躍屬性集合(包飯安全屬性)。例如student表的可能實(shí)現(xiàn)如下:

public function scenarios()
{
 return [
  self::SCENARIO_DEFAULT => ["!user_id", "grade", "class", xxxx],
  "update" => ["grade", "class", xxxx],
 ];
}

默認(rèn)情形下(學(xué)生報(bào)名),年級(jí)、班級(jí)這些信息是安全屬性,但user_id不是,只能在程序內(nèi)部賦值,并在插入數(shù)據(jù)時(shí)被校驗(yàn);在修改信息時(shí),user_id不是活躍屬性,既不能被批量賦值,也不需要校驗(yàn)(事實(shí)上它不應(yīng)該改變)。

scenarios方法只能定義活躍屬性和安全屬性,無(wú)法定義校驗(yàn)規(guī)則,需要和rules配合使用。

總結(jié)

金肯定義完善的數(shù)據(jù)校驗(yàn)規(guī)則

業(yè)務(wù)復(fù)雜時(shí)定義多個(gè)場(chǎng)景,仔細(xì)為每個(gè)場(chǎng)景定義安全屬性和校驗(yàn)規(guī)則

優(yōu)先使用rules;屬性較多、rules復(fù)雜時(shí),可以配合scenarios方法迅速理清安全屬性和活躍屬性

好了,以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。

參考

http://www.yiiframework.com/doc-2.0/guide-input-validation.html

相關(guān)文章

  • 淺談PHP正則中的捕獲組與非捕獲組

    淺談PHP正則中的捕獲組與非捕獲組

    下面小編就為大家?guī)?lái)一篇淺談PHP正則中的捕獲組與非捕獲組。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-07-07
  • Laravel執(zhí)行migrate命令提示:No such file or directory的解決方法

    Laravel執(zhí)行migrate命令提示:No such file or directory的解決方法

    這篇文章主要介紹了Laravel執(zhí)行migrate命令提示:No such file or directory的解決方法,分析了執(zhí)行migrate命令出現(xiàn)錯(cuò)誤的原因與相關(guān)的解決方法,需要的朋友可以參考下
    2016-03-03
  • Phpstorm+Xdebug斷點(diǎn)調(diào)試PHP的方法

    Phpstorm+Xdebug斷點(diǎn)調(diào)試PHP的方法

    這篇文章主要介紹了Phpstorm+Xdebug斷點(diǎn)調(diào)試PHP的方法,本教程將通過(guò)配置Xdebug擴(kuò)展進(jìn)行斷點(diǎn)調(diào)試,目的在于提高大家的開(kāi)發(fā)效率,感興趣的小伙伴們可以參考一下
    2018-05-05
  • 實(shí)例分析PHP將字符串轉(zhuǎn)換成數(shù)字的方法

    實(shí)例分析PHP將字符串轉(zhuǎn)換成數(shù)字的方法

    在本篇文章里我們給大家分享的是關(guān)于PHP將字符串轉(zhuǎn)換成數(shù)字的方法和相關(guān)知識(shí)點(diǎn),有興趣的朋友們學(xué)習(xí)下。
    2019-01-01
  • YII2框架中驗(yàn)證碼的簡(jiǎn)單使用方法示例

    YII2框架中驗(yàn)證碼的簡(jiǎn)單使用方法示例

    這篇文章主要介紹了YII2框架中驗(yàn)證碼的簡(jiǎn)單使用方法,結(jié)合實(shí)例形式分析了Yii2框架驗(yàn)證碼的基本創(chuàng)建、使用方法及操作注意事項(xiàng),需要的朋友可以參考下
    2020-03-03
  • PHPMailer發(fā)送郵件

    PHPMailer發(fā)送郵件

    PHPMailer是一個(gè)封裝好的PHP郵件發(fā)送類(lèi),支持發(fā)送HTML內(nèi)容的電子郵件,以及圖片附件,前提要設(shè)置好郵件服務(wù)器就能實(shí)現(xiàn)郵件發(fā)送功能。本文給大家分享PHPMailer發(fā)送郵件功能,一起看看吧
    2016-12-12
  • php使用json_encode對(duì)變量json編碼

    php使用json_encode對(duì)變量json編碼

    這篇文章主要是說(shuō)明 json_encode 使用時(shí)一個(gè)需要注意的細(xì)節(jié),無(wú)論返回的是數(shù)組還是 json,都不代表這一定就是個(gè)錯(cuò)誤的返回結(jié)果,當(dāng)前端需要的數(shù)組時(shí),數(shù)組就是正確的結(jié)果,反之亦然
    2014-04-04
  • WordPress中對(duì)訪客評(píng)論功能的一些優(yōu)化方法

    WordPress中對(duì)訪客評(píng)論功能的一些優(yōu)化方法

    這篇文章主要介紹了WordPress中對(duì)訪客評(píng)論功能的一些優(yōu)化,包括顯示評(píng)論上的歡迎信息等功能,需要的朋友可以參考下
    2015-11-11
  • php的lavarel框架中join和orWhere的用法

    php的lavarel框架中join和orWhere的用法

    這篇文章主要介紹了php的lavarel框架中join和orWhere的用法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-12-12
  • PHP生成(支持多模板)二維碼海報(bào)代碼

    PHP生成(支持多模板)二維碼海報(bào)代碼

    本篇文章給大家分享了PHP生成支持多模板二維碼海報(bào)代碼,如果大家對(duì)此有需要,可以跟著參考學(xué)習(xí)下。
    2018-04-04

最新評(píng)論