Как отмечается в комментариях к моему посту, в 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);
}
}