无法使电子邮件验证工作

时间:2011-12-17 21:54:14

标签: php regex validation email phpunit

在寻找一个好的电子邮件验证程序之后,我找到this answer to a similar question并认为它看起来像是最有可能的候选人。我为电子邮件验证实现了以下类(它继承的RegexMatch类是根据关联配置数组的'needle'键中提供的正则表达式验证字符串):

class Email extends RegexMatch implements iface\Prop
{
    const
        /**
         * Regular expression for validating email addresses
         * 
         * This regex is meant to validate against RFC 5322 and was taken from
         * a post on Stack Overflow regarding email validation (see the links)
         * 
         * @link http://www.ietf.org/rfc/rfc5322.txt, https://stackoverflow.com/questions/201323/what-is-the-best-regular-expression-for-validating-email-addresses/1917982#1917982
         */
         PATTERN    = '
/(?(DEFINE)
   (?<address>         (?&mailbox) | (?&group))
   (?<mailbox>         (?&name_addr) | (?&addr_spec))
   (?<name_addr>       (?&display_name)? (?&angle_addr))
   (?<angle_addr>      (?&CFWS)? < (?&addr_spec) > (?&CFWS)?)
   (?<group>           (?&display_name) : (?:(?&mailbox_list) | (?&CFWS))? ;
                                          (?&CFWS)?)
   (?<display_name>    (?&phrase))
   (?<mailbox_list>    (?&mailbox) (?: , (?&mailbox))*)

   (?<addr_spec>       (?&local_part) \@ (?&domain))
   (?<local_part>      (?&dot_atom) | (?&quoted_string))
   (?<domain>          (?&dot_atom) | (?&domain_literal))
   (?<domain_literal>  (?&CFWS)? \[ (?: (?&FWS)? (?&dcontent))* (?&FWS)?
                                 \] (?&CFWS)?)
   (?<dcontent>        (?&dtext) | (?&quoted_pair))
   (?<dtext>           (?&NO_WS_CTL) | [\x21-\x5a\x5e-\x7e])

   (?<atext>           (?&ALPHA) | (?&DIGIT) | [!#\$%&\'*+-\/=?^_`{|}~])
   (?<atom>            (?&CFWS)? (?&atext)+ (?&CFWS)?)
   (?<dot_atom>        (?&CFWS)? (?&dot_atom_text) (?&CFWS)?)
   (?<dot_atom_text>   (?&atext)+ (?: \. (?&atext)+)*)

   (?<text>            [\x01-\x09\x0b\x0c\x0e-\x7f])
   (?<quoted_pair>     \\ (?&text))

   (?<qtext>           (?&NO_WS_CTL) | [\x21\x23-\x5b\x5d-\x7e])
   (?<qcontent>        (?&qtext) | (?&quoted_pair))
   (?<quoted_string>   (?&CFWS)? (?&DQUOTE) (?:(?&FWS)? (?&qcontent))*
                        (?&FWS)? (?&DQUOTE) (?&CFWS)?)

   (?<word>            (?&atom) | (?&quoted_string))
   (?<phrase>          (?&word)+)

   # Folding white space
   (?<FWS>             (?: (?&WSP)* (?&CRLF))? (?&WSP)+)
   (?<ctext>           (?&NO_WS_CTL) | [\x21-\x27\x2a-\x5b\x5d-\x7e])
   (?<ccontent>        (?&ctext) | (?&quoted_pair) | (?&comment))
   (?<comment>         \( (?: (?&FWS)? (?&ccontent))* (?&FWS)? \) )
   (?<CFWS>            (?: (?&FWS)? (?&comment))*
                       (?: (?:(?&FWS)? (?&comment)) | (?&FWS)))

   # No whitespace control
   (?<NO_WS_CTL>       [\x01-\x08\x0b\x0c\x0e-\x1f\x7f])

   (?<ALPHA>           [A-Za-z])
   (?<DIGIT>           [0-9])
   (?<CRLF>            \x0d \x0a)
   (?<DQUOTE>          ")
   (?<WSP>             [\x20\x09])
 )

 (?&address)/x';

    public function setConfig (array $config = array ())
    {
        $config = array_merge ($config, array ('needle' => self::PATTERN));
        return (parent::setConfig ($config));
    }

    public function isValid ()
    {
        return ((is_null ($this -> getData ()))
            || (parent::isValid ()));
    }
}

我还构建了一个PHPUnit测试,该测试针对从各种来源(主要是维基百科)中挑选出的有效和无效电子邮件地址的各种排列来运行此类。

这个类似乎在许多更普通的情况下起作用,但它遇到了问题,因为它传递了一些本来应该是无效的电子邮件,并且失败了一些本来应该没问题的电子邮件。我在下面列出了它们:

  • much."more\ unusual"@example.com(失败,应该有效)
  • "(),:;<>[\]@example.com(通行证,应该是无效的)
  • just"not"right@example.com(通行证,应该是无效的)
  • A@b@c@example.com(通行证,应该是无效的)
  • this\ is\"really\"not\\allowed@example.com(通行证,应该是无效的)

PHP似乎正确解析正则表达式,它不会发出任何错误,警告或通知。此外,我所有的其他测试用例(其他7个有效地址和其他2个无效)都会被传递或失败,因此我怀疑是因为我的PHP版本(5.3.8)不支持此处使用的正则表达式语法。但是,由于我有假阳性和假阴性,显然有些不对劲。要么我的测试数据不正确(正如我所说,我主要是从维基百科中剔除),要么正则表达式在某种程度上是不正确的。

上面输入的正则表达式是否正确?如果没有,需要进行哪些更正?如果它是正确的,那么我的测试用例是否有问题?

编辑:我也忘了提及,因为这是一个验证类,它只需要传递包含电子邮件地址的字符串而不需要其他内容。我不想在非电子邮件地址数据中传递包含有效电子邮件地址的字符串。我知道你通过使用^pattern_goes_here$来做到这一点,但这个正则表达式比我过去使用过的大多数都要先进,而且我不确定^和$应该去哪里。如果你也可以帮助我,我会很感激。

2 个答案:

答案 0 :(得分:2)

完全验证电子邮件地址是非常棘手的业务。

这是一个完整的测试列表,显示了解决它的不同方法,但没有一个能够通过所有案例。

  

http://fightingforalostcause.net/misc/2006/compare-email-regex.php

     

得分最高的表达式目前是PHP的filter_var()使用的表达式,它基于Michael Rushton的正则表达式

我强烈建议您使用filter_var()

答案 1 :(得分:1)

如果你想添加^$个锚点,那就是这个地方:

  ^(?&address)$  /x';

您还需要验证电子邮件测试用例资源。我更信任那些正则表达式子程序,因为有人通过翻译RFC中的BNF声明来编写它。