yii2.0验证规则源码分析&php正则使用
2016-09-14 13:28
477 查看
之前两天在极客头条上看了一篇帖子,最严谨的校验email地址的正则表达式 ,最近接手的最多的就是yii2.0框架,所以很好奇想看看yii2.0是怎么实现验证规则。
首先,一般在自定义的继承model类中,会有个rules()方法:
通过上面的调用栈信息,我们看到,对于post提交的表单,我们在使用load()加载的时候会调用rules()方法,然后我们再进入load()里面看,load()方法只给属性赋值,不涉及到任何对属性的判断,通过简单的验证就可以看出来,这里就不截图了,所以对属性的判断并不在load()中!
我们获取错误信息是通过getErrors(),那就看下addErrors()的调用栈信息,如下:
里面在调用栈中出现了validateAttribute()方法,
从这次的栈信息中,可以看出来,validateAttribute是对rules里面定义的规则,每一个执行一次,validateAttribute()里面调用了validateValue()方法
所以这里的$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 <water@xxxx.com>";
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
php正则表达式 ASCII码
首先,一般在自定义的继承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 <water@xxxx.com>";
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
php正则表达式 ASCII码
相关文章推荐
- 使用VS TFS源码分析软件PATFS创建异常规则
- PHP使用正则匹配进行表单验证案例
- 使用Jquery.Validate通过正则表达式自定义验证规则汇总(常用验证规则),非常实用
- PHP正则表达式preg_match的具体使用规则介绍
- php使用正则验证中文
- 39-41.Struts2_短路验证&非字段验证&相同的验证规则使用同一条响应消息&自定义验证器
- Yii2.0源码分析之——控制器文件分析(Controller.php)创建动作、执行动作
- Yii2.0源码分析之——控制器文件分析(Controller.php)创建动作、执行动作
- Universal-Image-Loader(UIL)使用方法&流程图&源码分析 ----- 未完
- php数组使用规则分析
- Android 神兵利器Dagger2使用详解(二)Module&Component源码分析
- matches 正则表达式的使用 编写代码,验证手机号码,并告知用户是"189""158""130" 号段各自的运营公司, 如果号码长度有误,告诉用户手机号码 不存在。
- Rails自带用户验证has_secure_password的使用与源码分析
- C#中Queue<T>类的使用以及部分方法的源码分析
- php使用身份证的验证规则
- php使用websocket编写的简易客服系统源码分析
- php使用正则验证中文
- php数组使用规则分析
- PHP在使用正则表达式验证,防注入的时候要注意一下的细节
- Android 使用正则表达式验证身份证号是否符合规则