用PHP校验EMAIL地址的正确方法(1)
由John Klensin编写的互联网任务工程组IETF)文档RFC 3696 “应用程序技术检查和命名转换”给出了多个真实有效的EMAIL地址,但很不幸的是这些地址却被大多数PHP校验程序给拒绝了,地址Abc\@def@example.com,customer/department=shipping@example.com 和!def!xyz%abc@example.com都是有效的,下面是在有关文献中给出的一个非常流行正则表达式,但它拒绝了前面给出的所有EMAIL地址:
^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$ |
这个正则表达式只允许下划线(_)和连字符-),数字和大小写字母。即使在此之前先对字母做了大小写转换,也会拒绝那些包含斜线/),等号=),惊叹号!)和百分号%)的地址。这个表达式也要求最高级的域组件至少要有2个或3个字符,因此也会拒绝有效的域,如.museum。
另一个受人喜欢的正则表达式是:
^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+$ |
这个正则表达式也会拒绝前面段落给出的有效示例地址,它优雅地解决了大写字母问题,并且当最高级域名只有2个或3个字符也不会报错了,但它又允许无效的域名,如example..com。
清单1显示了一个来自PHP Dev Shedhttp://www.devshed.com/c/a/PHP/Email-Address-Verification-with-PHP/2)的示例,这个代码包括至少)三个错误:
首先,它不能识别出许多有效的email地址字符,如百分号%)。
第二,它将email地址在@符合处分成用户名和域两部分,如果email地址在符号处包括一个引用,如Abc\@def@example.com,将会中断这个代码。
第三,它不能检查主机地址DNS记录,有DNS A记录的主机会接受email地址,不一定非得要MX记录,我没有在PHP Dev Shed上找作者的岔,至少有100位浏览者做了4-5星的评分。
清单1.一个错误的email校验程序
function checkEmail($email) { if(preg_match("/^([a-zA-Z0-9])+([a-zA-Z0-9\._-])*@([a-zA-Z0-9_-])+([a-zA-Z0-9\._-]+)+$/", $email)){ list($username,$domain)=split('@',$email); if(!checkdnsrr($domain,'MX')) { return false; } return true; } return false; |
一个比较好的解决方案来自IloveJackDanielhttp://ilovejackdaniels.com/)的Dave Child的博客,显示在清单2中http://www.ilovejackdaniels.com/php/email-address-validation)。
Dave不仅喜欢陈年的美国威士忌,而且它也有一个副业,就是阅读RFC 2822,找出在一个email地址用户名有效的字符范围,至少有50人对这个解决方案做了评论,包括一些已经被合并到最初的方案中的纠正,不过这个由大家共同开发的代码仍然有缺陷,主要是它不能允许在用户名中出现转移字符,如\@,并且当不止一个地址符号时也会拒绝,因此就不能使用@来将用户名与域进行划分,个人认为这会扩大检查域名中每个组件影响的范围。
清单2:IloveJackDaniel提供的更好的示例
function check_email_address($email) { //首先,我们检查这里的@符号,然后看其长度是否正确。 if (!ereg("^[^@]{1,64}@[^@]{1,255}$", $email)) { // email无效,因为某个小段中的字符数量错误或@符号的数量错误 return false; } //将其分割成小段 $email_array = explode("@", $email); $local_array = explode(".", $email_array[0]); for ($i = 0; $i < sizeof($local_array); $i++) { if (!ereg("^(([A-Za-z0-9!#$%&'*+/=?^_`{|}~-][A-Za-z0-9!#$%& ↪'*+/=?^_`{|}~\.-]{0,63})|(\"[^(\\|\")]{0,62}\"))$", $local_array[$i])) { return false; } } //检查域是否是一个IP地址,如果不是,它应该是一个有效的域 if (!ereg("^\[?[0-9\.]+\]?$", $email_array[1])) { $domain_array = explode(".", $email_array[1]); if (sizeof($domain_array) < 2) { return false; // 域长度不够 } for ($i = 0; $i < sizeof($domain_array); $i++) { if (!ereg("^(([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])| ↪([A-Za-z0-9]+))$", $domain_array[$i])) { return false; } } } return true; } |
PHP之友评论