email validation - PHP FILTER_VALIDATE_EMAIL does not work correctly -
i'm using php 5.3.10. code:
<?php $email = "test@example.c"; if (filter_var($email, filter_validate_email)) echo "email: ".$email." correct"; else echo "email not correct"; ?>
it returns: "email: test@example.c
correct.
i think top level domain 1 character not correct (i'm not aware of one-character-length tld according list: http://data.iana.org/tld/tlds-alpha-by-domain.txt
).
so, filter_validate_email
filter working correctly or not?
validating e-mail adresses kinda complicated. take @ list:
valid email addresses
- niceandsimple@example.com
- very.common@example.com
- a.little.lengthy.but.fine@dept.example.com
- disposable.style.email.with+symbol@example.com
- user@[ipv6:2001:db8:1ff::a0b:dbd0]
- "much.more unusual"@example.com
- "very.unusual.@.unusual.com"@example.com
- "very.(),:;<>[]\".very.\"very@\ \"very\".unusual"@strange.example.com
- postbox@com (top-level domains valid hostnames)
- admin@mailserver1 (local domain name no tld)
- !#$%&'*+-/=?^_`{}|~@example.org
- "()<>[]:,;@\\"!#$%&'*+-/=?^_`{}| ~.a"@example.org
- " "@example.org (space between quotes)
- üñîçøðé@example.com (unicode characters in local part)
invalid email addresses
- abc.example.com (an @ character must separate local , domain parts)
- a@b@c@example.com (only 1 @ allowed outside quotation marks)
- a"b(c)d,e:f;gi[j\k]l@example.com (none of special characters in local part allowed outside quotation marks)
- just"not"right@example.com (quoted strings must dot separated, or element making local-part)
- this is"not\allowed@example.com (spaces, quotes, , backslashes may exist when within quoted strings , preceded backslash)
- this\ still\"not\allowed@example.com (even if escaped (preceded backslash), spaces, quotes, , backslashes must still contained quotes)
source http://en.wikipedia.org/wiki/email_address
allmost e-mail validation implementations "bugged" php implementation fine work because accepts common e-mail adresses
update:
found on http://www.php.net/manual/en/filter.filters.validate.php
regarding "partial" addresses no . in domain part, comment in source code (in ext/filter/logical_filters.c) justifies rejection thus:
* regex below based on regex michael rushton. * however, not identical. changed consider routeable * addresses valid. michael's regex considers a@b valid address * conflicts section 2.3.5 of rfc 5321 states that: * * resolvable, fully-qualified domain names (fqdns) permitted * when domain names used in smtp. in other words, names can * resolved mx rrs or address (i.e., or aaaa) rrs (as discussed * in section 5) permitted, cname rrs targets can * resolved, in turn, mx or address rrs. local nicknames or * unqualified names must not used.
and here link class michael rushton (link broken see source below) supports both rfc 5321/5322
<?php /** * squiloople framework * * license: feel free use , redistribute code. * * @author michael rushton <michael@squiloople.com> * @link http://squiloople.com/ * @package squiloople * @version 1.0 * @copyright © 2012 michael rushton */ /** * email address validator * * validate email addresses according relevant standards */ final class emailaddressvalidator { // rfc 5321 constant const rfc_5321 = 5321; // rfc 5322 constant const rfc_5322 = 5322; /** * email address * * @access private * @var string $_email_address */ private $_email_address; /** * quoted string local part either allowed (true) or not (false) * * @access private * @var boolean $_quoted_string */ private $_quoted_string = false; /** * obsolete local part either allowed (true) or not (false) * * @access private * @var boolean $_obsolete */ private $_obsolete = false; /** * basic domain name either required (true) or not (false) * * @access private * @var boolean $_basic_domain_name */ private $_basic_domain_name = true; /** * domain literal domain either allowed (true) or not (false) * * @access private * @var boolean $_domain_literal */ private $_domain_literal = false; /** * comments , folding white spaces either allowed (true) or not (false) * * @access private * @var boolean $_cfws */ private $_cfws = false; /** * set email address , turn on relevant standard if required * * @access public * @param string $email_address * @param null|integer $standard */ public function __construct($email_address, $standard = null) { // set email address $this->_email_address = $email_address; // set relevant standard or throw exception if unknown requested switch ($standard) { // nothing if no standard requested case null: break; // otherwise if rfc 5321 requested case self::rfc_5321: $this->setstandard5321(); break; // otherwise if rfc 5322 requested case self::rfc_5322: $this->setstandard5322(); break; // otherwise throw exception default: throw new exception('unknown rfc standard email address validation.'); } } /** * call constructor fluently * * @access public * @static * @param string $email_address * @param null|integer $standard * @return emailaddressvalidator */ public static function setemailaddress($email_address, $standard = null) { return new self($email_address, $standard); } /** * validate email address using basic standard * * @access public * @return emailaddressvalidator */ public function setstandardbasic() { // quoted string local part not allowed $this->_quoted_string = false; // obsolete local part not allowed $this->_obsolete = false; // basic domain name required $this->_basic_domain_name = true; // domain literal domain not allowed $this->_domain_literal = false; // comments , folding white spaces not allowed $this->_cfws = false; // return emailaddressvalidator object return $this; } /** * validate email address using rfc 5321 * * @access public * @return emailaddressvalidator */ public function setstandard5321() { // quoted string local part allowed $this->_quoted_string = true; // obsolete local part not allowed $this->_obsolete = false; // basic domain name not required $this->_basic_domain_name = false; // domain literal domain allowed $this->_domain_literal = true; // comments , folding white spaces not allowed $this->_cfws = false; // return emailaddressvalidator object return $this; } /** * validate email address using rfc 5322 * * @access public * @return emailaddressvalidator */ public function setstandard5322() { // quoted string local part disallowed $this->_quoted_string = false; // obsolete local part allowed $this->_obsolete = true; // basic domain name not required $this->_basic_domain_name = false; // domain literal domain allowed $this->_domain_literal = true; // comments , folding white spaces allowed $this->_cfws = true; // return emailaddressvalidator object return $this; } /** * either allow (true) or not allow (false) quoted string local part * * @access public * @param boolean $allow * @return emailaddressvalidator */ public function setquotedstring($allow = true) { // either allow (true) or not allow (false) quoted string local part $this->_quoted_string = $allow; // return emailaddressvalidator object return $this; } /** * either allow (true) or not allow (false) obsolete local part * * @access public * @param boolean $allow * @return emailaddressvalidator */ public function setobsolete($allow = true) { // either allow (true) or not allow (false) obsolete local part $this->_obsolete = $allow; // return emailaddressvalidator object return $this; } /** * either require (true) or not require (false) basic domain name * * @access public * @param boolean $allow * @return emailaddressvalidator */ public function setbasicdomainname($allow = true) { // either require (true) or not require (false) basic domain name $this->_basic_domain_name = $allow; // return emailaddressvalidator object return $this; } /** * either allow (true) or not allow (false) domain literal domain * * @access public * @param boolean $allow * @return emailaddressvalidator */ public function setdomainliteral($allow = true) { // either allow (true) or not allow (false) domain literal domain $this->_domain_literal = $allow; // return emailaddressvalidator object return $this; } /** * either allow (true) or not allow (false) comments , folding white spaces * * @access public * @param boolean $allow * @return emailaddressvalidator */ public function setcfws($allow = true) { // either allow (true) or not allow (false) comments , folding white spaces $this->_cfws = $allow; // return emailaddressvalidator object return $this; } /** * return regular expression dot atom local part * * @access private * @return string */ private function _getdotatom() { return "([!#-'*+\/-9=?^-~-]+)(?>\.(?1))*"; } /** * return regular expression quoted string local part * * @access private * @return string */ private function _getquotedstring() { return '"(?>[ !#-\[\]-~]|\\\[ -~])*"'; } /** * return regular expression obsolete local part * * @access private * @return string */ private function _getobsolete() { return '([!#-\'*+\/-9=?^-~-]+|"(?>' . $this->_getfws() . '(?>[\x01-\x08\x0b\x0c\x0e-!#-\[\]-\x7f]|\\\[\x00-\xff]))*' . $this->_getfws() . '")(?>' . $this->_getcfws() . '\.' . $this->_getcfws() . '(?1))*'; } /** * return regular expression domain name domain * * @access private * @return string */ private function _getdomainname() { // return basic domain name format if required if ($this->_basic_domain_name) { return '(?>' . $this->_getdomainnamelengthlimit() . '[a-z\d](?>[a-z\d-]*[a-z\d])?' . $this->_getcfws() . '\.' . $this->_getcfws() . '){1,126}[a-z]{2,6}'; } // otherwise return full domain name format return $this->_getdomainnamelengthlimit() . '([a-z\d](?>[a-z\d-]*[a-z\d])?)(?>' . $this->_getcfws() . '\.' . $this->_getdomainnamelengthlimit() . $this->_getcfws() . '(?2)){0,126}'; } /** * return regular expression ipv6 address * * @access private * @return string */ private function _getipv6() { return '([a-f\d]{1,4})(?>:(?3)){7}|(?!(?:.*[a-f\d][:\]]){8,})((?3)(?>:(?3)){0,6})?::(?4)?'; } /** * return regular expression ipv4-mapped ipv6 address * * @access private * @return string */ private function _getipv4mappedipv6() { return '(?3)(?>:(?3)){5}:|(?!(?:.*[a-f\d]:){6,})(?5)?::(?>((?3)(?>:(?3)){0,4}):)?'; } /** * return regular expression ipv4 address * * @access private * @return string */ private function _getipv4() { return '(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)(?>\.(?6)){3}'; } /** * return regular expression domain literal domain * * @access private * @return string */ private function _getdomainliteral() { return '\[(?:(?>ipv6:(?>' . $this->_getipv6() . '))|(?>(?>ipv6:(?>' . $this->_getipv4mappedipv6() . '))?' . $this->_getipv4() . '))\]'; } /** * return either regular expression folding white spaces or backreference * * @access private * @param boolean $define * @return string */ private function _getfws($define = false) { // return backreference if $define set false otherwise return regular expression if ($this->_cfws) { return !$define ? '(?p>fws)' : '(?<fws>(?>(?>(?>\x0d\x0a)?[\t ])+|(?>[\t ]*\x0d\x0a)?[\t ]+)?)'; } } /** * return regular expression comments * * @access private * @return string */ private function _getcomments() { return '(?<comment>\((?>' . $this->_getfws() . '(?>[\x01-\x08\x0b\x0c\x0e-\'*-\[\]-\x7f]|\\\[\x00-\x7f]|(?p>comment)))*' . $this->_getfws() . '\))'; } /** * return either regular expression comments , folding white spaces or backreference * * @access private * @param boolean $define * @return string */ private function _getcfws($define = false) { // return backreference if $define set false if ($this->_cfws && !$define) { return '(?p>cfws)'; } // otherwise return regular expression if ($this->_cfws) { return '(?<cfws>(?>(?>(?>' . $this->_getfws(true) . $this->_getcomments() . ')+' . $this->_getfws() . ')|' . $this->_getfws() . ')?)'; } } /** * establish , return valid format local part * * @access private * @return string */ private function _getlocalpart() { // local part may obsolete if allowed if ($this->_obsolete) { return $this->_getobsolete(); } // otherwise local part must either dot atom or quoted string if latter allowed if ($this->_quoted_string) { return '(?>' . $this->_getdotatom() . '|' . $this->_getquotedstring() . ')'; } // otherwise local part must dot atom return $this->_getdotatom(); } /** * establish , return valid format domain * * @access private * @return string */ private function _getdomain() { // domain must either domain name or domain literal if latter allowed if ($this->_domain_literal) { return '(?>' . $this->_getdomainname() . '|' . $this->_getdomainliteral() . ')'; } // otherwise domain must domain name return $this->_getdomainname(); } /** * return email address length limit * * @access private * @return string */ private function _getemailaddresslengthlimit() { return '(?!(?>' . $this->_getcfws() . '"?(?>\\\[ -~]|[^"])"?' . $this->_getcfws() . '){255,})'; } /** * return local part length limit * * @access private * @return string */ private function _getlocalpartlengthlimit() { return '(?!(?>' . $this->_getcfws() . '"?(?>\\\[ -~]|[^"])"?' . $this->_getcfws() . '){65,}@)'; } /** * establish , return domain name length limit * * @access private * @return string */ private function _getdomainnamelengthlimit() { return '(?!' . $this->_getcfws() . '[a-z\d-]{64,})'; } /** * check see if domain can resolved mx rrs * * @access private * @param array $domain * @return integer|boolean */ private function _verifydomain($domain) { // return 0 if domain cannot resolved mx rrs if (!checkdnsrr(end($domain), 'mx')) { return 0; } // otherwise return true return true; } /** * perform validation check on email address's syntax and, if required, call _verifydomain() * * @access public * @param boolean $verify * @return boolean|integer */ public function isvalid($verify = false) { // return false if email address has incorrect syntax if (!preg_match( '/^' . $this->_getemailaddresslengthlimit() . $this->_getlocalpartlengthlimit() . $this->_getcfws() . $this->_getlocalpart() . $this->_getcfws() . '@' . $this->_getcfws() . $this->_getdomain() . $this->_getcfws(true) . '$/isd' , $this->_email_address )) { return false; } // otherwise check see if domain can resolved mx rrs if required if ($verify) { return $this->_verifydomain(explode('@', $this->_email_address)); } // otherwise return 1 return 1; } }
edit 2016: in php 7.1 beta noticed following:
- implemented email validation per rfc 6531. (leo feyer, anatol).
see section 3.3 https://tools.ietf.org/html/rfc6531#section-3.3
https://en.wikipedia.org/wiki/international_email
and nice examples
用户@例子.广告 (chinese, unicode) उपयोगकर्ता@उदाहरण.कॉम (hindi, unicode) юзер@екзампл.ком (ukrainian, unicode) θσερ@εχαμπλε.ψομ (greek, unicode) dörte@sörensen.example.com (german, unicode)
Comments
Post a Comment