Я начал использовать Zend_Validate_EmailAddress
с параметрами mx
и deep
, установленными в true. Я думаю, что я получаю некоторые ложные негативы, когда речь идет о записях MX, которые имеют IP-адреса в зарезервированных диапазонах IP.
Хорошим примером являются записи MX для harn.ufl.edu . Похоже, что он не работает из-за IP-адресов в диапазоне 128.0.0.0/16. Однако у него есть одна запись, которая использует 8.6.245.30, которая не находится в зарезервированном диапазоне.
Другим примером является запись MX для martinhealth.org . В домене MX используется 198.136.38.2.
Это случай чего-то, что технически некорректно, но на самом деле работает?
Поскольку комментарии к моему сообщению намекают, есть ошибка в Zend_Validate_EmailAddress::_isReserved
. Мало того, что это багги, но трудно понять логический поток. Это была private
функция, поэтому я заменил ее на protected
чтобы я мог переопределить ее в своем подклассе. Были также некоторые неправильные диапазоны в массиве $_invalidIp
.
Для моей проверки логики я решил, что самый простой (ясный) способ сравнения IP-адресов состоял в том, чтобы преобразовать их в их десятичные целочисленные эквиваленты.
Вот мой подкласс:
class My_Validate_EmailAddressDeep extends Zend_Validate_EmailAddress { /** * @var array */ protected $_messageTemplates = array( self::INVALID => "Invalid type given. String expected", self::INVALID_FORMAT => "'%value%' is not a valid email address in the basic [user]@[hostname] format", self::INVALID_HOSTNAME => "The '%hostname%' part of '%value%' is not a valid hostname", self::INVALID_MX_RECORD => "'%hostname%' does not appear to be configured to accept email", self::INVALID_SEGMENT => "'%hostname%' does not appear to be configured to accept external email", self::DOT_ATOM => null, self::QUOTED_STRING => null, self::INVALID_LOCAL_PART => "The '%localPart%' part of '%value%' is not valid", self::LENGTH_EXCEEDED => "'%value%' is longer than the allowed length for an email address", ); /** * Internal options array * @var array */ protected $_options = array( 'allow' => Zend_Validate_Hostname::ALLOW_DNS, 'deep' => true, 'domain' => true, 'hostname' => null, 'mx' => true, ); /** * @see http://en.wikipedia.org/wiki/Reserved_IP_addresses#Reserved_IPv4_addresses * @var array [first octet] => [[CIDR] => [[range start], [range end]]] */ protected $_reservedIps = array( '0' => array('0.0.0.0/8' => array('0.0.0.0', '0.255.255.255',),), '10' => array('10.0.0.0/8' => array('10.0.0.0', '10.255.255.255',),), '127' => array('127.0.0.0/8' => array('127.0.0.0', '127.255.255.255',),), '169' => array('169.254.0.0/16' => array('169.254.0.0', '169.254.255.255',),), '172' => array('172.16.0.0/12' => array('172.16.0.0', '172.31.255.255',),), '192' => array( '192.0.2.0/24' => array('192.0.2.0', '192.0.2.255',), '192.88.99.0/24' => array('192.88.99.0', '192.88.99.255',), '192.168.0.0/16' => array('192.168.0.0', '192.168.255.255',), ), '198' => array( '198.18.0.0/15' => array('198.18.0.0', '198.19.255.255',), '198.51.100.0/24' => array('198.51.100.0', '198.51.100.255',), ), '203' => array('203.0.113.0/24' => array('203.0.113.0', '203.0.113.255',),), '224' => array('224.0.0.0/4' => array('224.0.0.0', '239.255.255.255',),), '240' => array('240.0.0.0/4' => array('240.0.0.0', '255.255.255.255',),), ); /** * Returns if the given host is reserved * * @param string $host * @return boolean */ protected function _isReserved($host) { if (!preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $host)) { $host = gethostbyname($host); } $octets = explode('.', $host); if (224 <= (int) $octets[0]) { // IP Addresses beginning with 224 or greater are all reserved, short-circuit range checks return true; } elseif (array_key_exists($octets[0], $this->_reservedIps)) { // for integer comparisons $intIp = $this->_ipToInt($host); // loop over reserved IP addresses foreach ($this->_reservedIps as $ranges) { foreach ($ranges as $range) { if (($this->_ipToInt($range[0]) <= $intIp) && ($this->_ipToInt($range[1]) >= $intIp)) { // the IP address falls in a reserved range return true; } } } // the IP address did not fall in a reserved range return false; } else { return false; } } /** * Convert a dot-decimal IP address to it's decimal integer equivalent * * @param string $ip * @return integer */ protected function _ipToInt($ip) { $octets = explode('.', $ip); foreach ($octets as $key => $octet) { $octets[$key] = str_pad(decbin($octet), 8, '0', STR_PAD_LEFT); } $bin = implode('', $octets); return bindec($bin); } }