1. 程式人生 > >yii2.0驗證規則原始碼分析&php正則使用

yii2.0驗證規則原始碼分析&php正則使用

之前兩天在極客頭條上看了一篇帖子,最嚴謹的校驗email地址的正則表示式 ,最近接手的最多的就是yii2.0框架,所以很好奇想看看yii2.0是怎麼實現驗證規則。

首先,一般在自定義的繼承model類中,會有個rules()方法:

    public function rules()
    {
        /*echo "<pre>";
        $e=new \Exception();
        var_export($e->getTraceAsString());*/
        return [
            // username and password are both required
            [['username', 'password'], 'required'],
            // password is validated by validatePassword()
            ['password', 'validatePassword'],

        ];
    }
然後看下列印結果,如下:


通過上面的呼叫棧資訊,我們看到,對於post提交的表單,我們在使用load()載入的時候會呼叫rules()方法,然後我們再進入load()裡面看,load()方法只給屬性賦值,不涉及到任何對屬性的判斷,通過簡單的驗證就可以看出來,這裡就不截圖了,所以對屬性的判斷並不在load()中!

我們獲取錯誤資訊是通過getErrors(),那就看下addErrors()的呼叫棧資訊,如下:


裡面在呼叫棧中出現了validateAttribute()方法,


從這次的棧資訊中,可以看出來,validateAttribute是對rules裡面定義的規則,每一個執行一次,validateAttribute()裡面呼叫了validateValue()方法

    public function validateAttribute($model, $attribute)
    {
        $result = $this->validateValue($model->$attribute);
        if (!empty($result)) {
            $this->addError($model, $attribute, $result[0], $result[1]);
        }
    }

所以這裡的$this拿到的就是RequiredValidator的控制代碼了,所以所有對rules的規則的驗證都是在validators目錄下。

----------------------------------------------------------------------------------下面是對email的驗證和php正則---------------------------------------------------------------------------------------------------

檔案路徑:\yii\validators\EmailValidator

    protected function validateValue($value)
    {
        if (!is_string($value)) {
            $valid = false;

        } elseif (!preg_match('/^(?P<name>(?:"?([^"]*)"?\s)?)(?:\s+)?(?:(?P<open><?)((?P<local>.+)@(?P<domain>[^>]+))(?P<close>>?))$/i', $value, $matches)) {
            $valid = false;
        } else {
            if ($this->enableIDN) {
                $matches['local'] = idn_to_ascii($matches['local']);
                $matches['domain'] = idn_to_ascii($matches['domain']);
                $value = $matches['name'] . $matches['open'] . $matches['local'] . '@' . $matches['domain'] . $matches['close'];
            }

            if (strlen($matches['local']) > 64) {
                // The maximum total length of a user name or other local-part is 64 octets. RFC 5322 section 4.5.3.1.1
                // http://tools.ietf.org/html/rfc5321#section-4.5.3.1.1
                $valid = false;
            } elseif (strlen($matches['local'] . '@' . $matches['domain']) > 254) {
                // There is a restriction in RFC 2821 on the length of an address in MAIL and RCPT commands
                // of 254 characters. Since addresses that do not fit in those fields are not normally useful, the
                // upper limit on address lengths should normally be considered to be 254.
                //
                // Dominic Sayers, RFC 3696 erratum 1690
                // http://www.rfc-editor.org/errata_search.php?eid=1690
                $valid = false;
            } else {
                $valid = preg_match($this->pattern, $value) || $this->allowName && preg_match($this->fullPattern, $value);
                if ($valid && $this->checkDNS) {
                    $valid = checkdnsrr($matches['domain'], 'MX') || checkdnsrr($matches['domain'], 'A');
                }
            }
        }

        return $valid ? null : [$this->message, []];
    }

所以yii對email的驗證使用的也就是這樣一段正則
/^(?P<name>(?:"?([^"]*)"?\s)?)(?:\s+)?(?:(?P<open><?)((?P<local>.+)@(?P<domain>[^>]+))(?P<close>>?))$/i
上面涉及到了非獲取匹配,後面會介紹,結果就是:
        $value="1  <[email protected]>";
        preg_match('/^(?P<name>(?:"?([^"]*)"?\s)?)(?:\s+)?(?:(?P<open><?)((?P<local>.+)@(?P<domain>[^>]+))(?P<close>>?))$/i', $value, $matches);
        var_dump($matches);


1(name):(?P<name>(?:"?([^"]*)"?\s)?) 匹配空格和空格前的字元

2:([^"]*)   匹配除了"之外的任意字元0次或多次

3(open):(?P<open><?) 匹配<

4: ((?P<local>.+)@(?P<domain>[^>]+))(?P<close>>?))

5(local):(?P<local>.+)匹配任意字元1次到多次

6(domain):(?P<domain>[^>]+)匹配除了>外的字元1次到多次

7: (?P<close>>?)匹配>標籤

idn_to_ascii 將domain name轉換成ASCII形式

補充一些php正則表示式的知識:

chr()將ASCII值轉換成字元,
hexdec()把十六進位制轉換成十進位制,
ord()返回字串的首個字元的ASCII值,
雙引號包圍十六進位制的ASCII碼echo輸出的時候會轉換成字元。
//echo ord($b);
//echo chr('\x7E');
//echo hexdec('\x5C');


(?:pattern)匹配pattern但不獲取結果, (pattern)匹配pattern並獲取匹配結果,(?:pattern)匹配pattern但不獲取匹配結果,(?=pattern)正向預查,(?!pattern)反向預查
預查不消耗字元,也就是a(?=b|c)匹配了ab或ac之後,下次匹配的時候還可以從b或c處開始匹配
var_dump(preg_replace('/^(?:a(a|b))?/','xxx',"aaab"));//xxxab 3個x
var_dump(preg_replace('/^(?:a(?=a|b))?/','xxx',"aaab"));//xxxaab 3個x
var_dump(preg_replace('/(?:a(?=a|b))/','xxx',"aaab"));//xxxxxxxxxb 9個x
var_dump(preg_replace('/(?:a(a|b))?/','xxx',"aaab"));//xxxxxxxxx 9個x
var_dump(preg_replace('/(?:a(?!a|c))/','xxx','aaab'));//aaxxxb
var_dump(preg_replace('/(?!a|c)/','xxx','aaab'));//aaaxxxbxxx

相關推薦

yii2.0驗證規則原始碼分析&php使用

之前兩天在極客頭條上看了一篇帖子,最嚴謹的校驗email地址的正則表示式 ,最近接手的最多的就是yii2.0框架,所以很好奇想看看yii2.0是怎麼實現驗證規則。 首先,一般在自定義的繼承model類中,會有個rules()方法: public function

jQuery原始碼分析——常用表示式(RegExp)

常用的數字正則(嚴格匹配) 正則 含義 ^[1-9]\d*$ 匹配正整數 ^-[1-9]\d*$ 匹配負整數 ^-?[1-9]\d*$ 匹配整數 ^[1-9]\d*|0$ 匹配非負整數(正整數 +

php驗證手機、郵箱

als href 驗證 clas private hone net 電話 span //驗證電話private function reg_phone($phone){ if (preg_match("/^13[0-9]{1}[0-9]{8}$|15[0189]

php表達式驗證(郵件地址、Url地址、電話號碼、郵政編碼)

規則 main .com als url地址 host name fun ipc 1、電子郵件地址的校驗 <?php /* 校驗郵件地址*/ function checkMail($email) { //用戶名,由“w”格式字符、“-”或“.”組成 $email_n

PHPPHP表示式驗證表單

以下內容轉載自:https://www.jb51.net/article/93375.htm 模式匹配符: \:轉義字元 例如:\b轉義了b ^:正則表示式開始符號 $:正則表示式結束符號 *:匹配前面的字元出現0次或者n次 +:匹配前面的字元出現1次或者n次 ?:匹配前面的字元出現

webpack-tapable-0.2.8 原始碼分析

webpack 是基於事件流的打包構建工具,也就是內建了很多 hooks。作為使用方,可以在這些鉤子當中,去插入自己的處理邏輯,而這一切的實現都得益於 tapable 這個工具。它有多個版本,webpack 前期的版本是依賴於 tapable 0.2.8 這個版本,後來重構了,發了 2.0.0 beta 版本

JdbcTemplate 0.9版本原始碼分析

JdbcTemplate 核心方法: public void query(PreparedStatementCreator psc, RowCallbackHandler callbackHandler) throws DataAccessException {

php表示式驗證手機號碼

php正則表示式驗證手機號碼是否合法:         $phone = 13688888888;         $check = '/^(1(([35789][0-9])|(47)))\

Spark2.4.0 Dataset head 原始碼分析

Spark2.4.0 Dataset head 原始碼分析 更多資源 github: https://github.com/opensourceteams/spark-scala-maven-2.4.0 視訊 Spark2.4.0 Dataset head 原理分析(bilibili視訊

PHP表示式驗證郵箱是否正確

一 程式碼 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml

Android6.0的Looper原始碼分析(1)

Android在Java標準執行緒模型的基礎上,提供了訊息驅動機制,用於多執行緒之間的通訊。而其具體實現就是Looper。 Android Looper的實現主要包括了3個概念:Message,MessageQueue,Handler,Looper。其中Message就是

PHP表示式的匹配規則

咱們要查詢數字,字母,空白很簡單,因為已經有了對應這些字元的元字元,但是如果匹配沒有預定義元字元的字元集合(比如母音字母a、e、i、o、u),方法很簡單,在方括號裡列出它們就行,如[aeiou]匹配任何一個英文母音字母,[.?! ]匹配各種標點符號以及空格等等,[]匹配單個字元,儘管內部含有好多

thinkphp 5.0 驗證規則

// 表示驗證name欄位的值是否在user表(不包含字首)中唯一’name’ => ‘unique:user’,// 驗證其他欄位’name’ => ‘unique:user,account’,// 排除某個主鍵值’name’ => ‘unique:user,account,1

Android 5.0 Camera系統原始碼分析(2):Camera開啟流程

1. 前言 本文將分析android系統原始碼,從frameworks層到hal層,暫不涉及app層和kernel層。由於某些函式比較複雜,在貼出程式碼時會適當對其進行簡化。本文屬於自己對原始碼的總結,僅僅是貫穿程式碼流程,不會深入分析各個細節。歡迎聯絡討論,QQ:1026

Android 7.0 Gallery相簿原始碼分析8

在Android 7.0 Gallery相簿原始碼分析3 - 資料載入及顯示流程一文最後講了AlbumSetSlidingWindow的onContentChanged方法,專輯縮圖和縮圖下面的label的載入就是在此方法中完成的 public

mahout關聯規則原始碼分析 Part 1

先說下命令列執行關聯規則,關聯規則的演算法在mahout-core-0,7.jar包下面,命令列執行如下: [email protected]:~/hadoop-1.0.2$ bin/hadoop jar ../mahout-pure-0.7/core/targ

PHP+表示式之手機號驗證

php用正則表示式判斷手機號碼的寫法:從文章中匹配出所有的手機號就可以preg_match_all(),如果要檢查使用者輸入的手機號是否正確可這樣來檢查:preg_match() 用正則匹配手機號碼的

Android 7.0 Gallery相簿原始碼分析4

上篇文章講了初始化View時會例項化一個SlotView並監聽其事件,至於它是怎麼實現的,用的是Android自帶的GestureDetector。 GestureDetector是Android自帶的用來監聽各種使用者手勢的的一個類,比如監聽單擊、雙擊和

Retrofit2.0所以然之原始碼分析

Retrofit2.0之所以然-原始碼解讀 原始碼解讀 小結 原始碼解讀 上節已經列出可以在專案中實操的retrofit使用方式,本節看一下核心的原始碼,通過對原始碼的認識,可以更瞭解其機制。 retrofit使用的是目前比較流行的流式程式設計。

js,php驗證是否為數字與…

網站使用者註冊的過程中經常會需要驗證某些欄位是不是由多少位數字和字母組成的,由於對正則不是很熟,這種東西我還是記錄下來以備需要的時候拿來用一下吧。 php驗證欄位必須為6-15位的字母和數字組合 if(!preg_match("/^[a-zd]{6,15}$/i",$variable)){