烦人的正则表达式(五)

正则表达式的应用十分广泛,你既可以用它来提取一大堆文字中的含有对应规则的单词,也可以用来查看文本中是否存在格式不规范的语句,或者运用它来实现过滤,过滤某些捣蛋鬼输入的惊为天人的用户名,或是某些黑客的恶意语句。

但编写一条逻辑性强符合要求的正则表达式往往令人头大,某个点的疏忽可能会导致存在功能不完善,过滤不完全导致可绕过等缺陷。当运用在网站上前后端数据交互过滤的正则存在缺陷,则会被黑客利用进行攻击。

我现在介绍的是如何思考与编写合格的正则表达式。由于我个人熟悉的是web方面,所以详细介绍网站前后端常用的正则表达式。可能我下面介绍的例子所用的方法不是最优的,这是因为我研究的不够深入,欢迎大家给予纠正或建议。

网页注册页面截图

登陆图片

可以看到各个输入框都有对应的提示信息,我们希望用户能按我们的要求输入相关信息,但我们不能天真地认为给个温馨提示所有用户就会乖乖地按要求输入,毕竟还是有捣蛋鬼和黑客存在。

手机号

这个内容算是比较容易的,首先手机号当然是纯数字的(说不是的难道号码是16进制的?),长度固定为11位。
小明:总结起来就是需要用户输入长度为11位的纯数字

/^\d{11}$/

然后小明就被捣蛋鬼给调戏了一下,捣蛋鬼输入了11个0
这时小明才赶紧去科普了一下手机号码组成规则,原来首位必须是1啊(至于限制于155,139,135等等这样繁琐的规则我们就权当不知道^.^)

/^1\d{10}$/

至于说怎么验证手机号码真伪的…需要结合短信验证或号码大数据支持,略

用户名

捣蛋鬼想了好多个狂傲炫酷的名称希望以此展示个性,但为了彰显我们是正规网站(其实重点是为了安全),我们需要给予一点限制。
用户可以给他们随便起个名称abcde,或者是具有意义的KING,或者使用数字等,但单双引号这些特殊字符就没必要用来彰显自己的个性了,为了安全我们要禁止用户使用特殊字符,长度最好限制在能一口气读完…
我们就写一个白名单机制的正则表达式

/^\w{6,20}$/

不对啊,万一用户想起个中文名称呢,这要求也不过分吧。这时我们就要修改一下,添加个中文的白名单

/^[\u4e00-\u9fa5_a-zA-Z0-9]{6,20}+$/  
/^[\u4e00-\u9fa5$]+$/  #纯中文匹配

这次可以愉快的交差了。至于那些粗俗的昵称,是需要根据完整的庞大的黑名单进行屏蔽,所以我只能温馨提示:小孩子不可以讲脏话

另一种是基于黑名单过滤所有特殊符号的(一般黑名单会有隐藏的风险)

/^[`~!@#$^&*()=|{}':;',\\[\\].<>/?~!@#¥……&*()——|{}【】‘;:”“'。,、?%+_]+$/

一次性把所有特殊字符都写上去了,除了_下划线。

邮箱

邮箱是一个很重要的元素,可以用来验证身份,接收网站邮件等。我们需要开放这功能,顺便加点过滤,防止用户输入有害信息。
分析一下邮箱的格式,一般邮箱都是名称@域名这样的形式,含有大小写字母和.(点号),-(减号),_(下划线)。域名可分多段,且只有第一段会出现数字。(最详细的规则不止这些,现在简化一下)到现在是不是感觉有点绕,觉得过于复杂不知如何入手,但我们可以将其分段实现
先把各部分组成单独列出来,长度我自由设置的,应该能匹配到大多数邮箱(老司机可跳过此步)

[a-zA-Z0-9_\-\.]+  #名称部分,匹配长度1个或多个  
@                  #匹配@  
([a-zA-Z0-9_\-]){2,6}(\.[a-zA-Z]+)*  #分段匹配  

检查一下每一小段,感觉差不多了,最后拼成一句就完事了

/^([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]){2,6}((\.[a-zA-Z]{2,6})*)$/  

最后拼接成超长的语句,但如果一小段一小段的去分析,你会发现也不过如此。这是比较粗暴的匹配了,更多规则添加欢迎自己来挑战。

密码

先舒口气。密码的话,还是很简单的嘛。
限制为大小写字母和数字组合就好了

/^[a-zA-Z0-9]{8,30}

what?添加特殊字符后密码安全系数直线上升…
那干脆别过滤了[滑稽]
这虽然能保障用户密码安全,不易被破解,但这需要一套完善的后台处理机制,感兴趣的可深入研究web安全

该怎么使用这些正则表达式

对于应用网站检验表单,我们使用匹配这一类的函数即可。对传入参数进行一遍匹配,根据返回值判断内容是否符合正则表达式,设置相应的if判断语句。

if(! preg_match("/^([0-9A-Za-z\\-_\\.]+)@([0-9a-z]+\\.[a-z]{2,3}(\\.[a-z]{2})?)$/i", $email) )   
{  
    echo '<script type="text/javascript">alert("邮箱格式错误");history.go(-1)</script>';  
    exit;  
}