[ Index ] |
PHP Cross Reference of moodle-2.8 |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Zend Framework 4 * 5 * LICENSE 6 * 7 * This source file is subject to the new BSD license that is bundled 8 * with this package in the file LICENSE.txt. 9 * It is also available through the world-wide-web at this URL: 10 * http://framework.zend.com/license/new-bsd 11 * If you did not receive a copy of the license and are unable to 12 * obtain it through the world-wide-web, please send an email 13 * to [email protected] so we can send you a copy immediately. 14 * 15 * @category Zend 16 * @package Zend_Validate 17 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) 18 * @license http://framework.zend.com/license/new-bsd New BSD License 19 * @version $Id$ 20 */ 21 22 /** 23 * @see Zend_Validate_Abstract 24 */ 25 require_once 'Zend/Validate/Abstract.php'; 26 27 /** 28 * @see Zend_Validate_Hostname 29 */ 30 require_once 'Zend/Validate/Hostname.php'; 31 32 /** 33 * @category Zend 34 * @package Zend_Validate 35 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) 36 * @license http://framework.zend.com/license/new-bsd New BSD License 37 */ 38 class Zend_Validate_EmailAddress extends Zend_Validate_Abstract 39 { 40 const INVALID = 'emailAddressInvalid'; 41 const INVALID_FORMAT = 'emailAddressInvalidFormat'; 42 const INVALID_HOSTNAME = 'emailAddressInvalidHostname'; 43 const INVALID_MX_RECORD = 'emailAddressInvalidMxRecord'; 44 const INVALID_SEGMENT = 'emailAddressInvalidSegment'; 45 const DOT_ATOM = 'emailAddressDotAtom'; 46 const QUOTED_STRING = 'emailAddressQuotedString'; 47 const INVALID_LOCAL_PART = 'emailAddressInvalidLocalPart'; 48 const LENGTH_EXCEEDED = 'emailAddressLengthExceeded'; 49 50 /** 51 * @var array 52 */ 53 protected $_messageTemplates = array( 54 self::INVALID => "Invalid type given, value should be a string", 55 self::INVALID_FORMAT => "'%value%' is no valid email address in the basic format local-part@hostname", 56 self::INVALID_HOSTNAME => "'%hostname%' is no valid hostname for email address '%value%'", 57 self::INVALID_MX_RECORD => "'%hostname%' does not appear to have a valid MX record for the email address '%value%'", 58 self::INVALID_SEGMENT => "'%hostname%' is not in a routable network segment. The email address '%value%' should not be resolved from public network.", 59 self::DOT_ATOM => "'%localPart%' can not be matched against dot-atom format", 60 self::QUOTED_STRING => "'%localPart%' can not be matched against quoted-string format", 61 self::INVALID_LOCAL_PART => "'%localPart%' is no valid local part for email address '%value%'", 62 self::LENGTH_EXCEEDED => "'%value%' exceeds the allowed length", 63 ); 64 65 /** 66 * @see http://en.wikipedia.org/wiki/IPv4 67 * @var array 68 */ 69 protected $_invalidIp = array( 70 '0' => '0.0.0.0/8', 71 '10' => '10.0.0.0/8', 72 '127' => '127.0.0.0/8', 73 '128' => '128.0.0.0/16', 74 '169' => '169.254.0.0/16', 75 '172' => '172.16.0.0/12', 76 '191' => '191.255.0.0/16', 77 '192' => array( 78 '192.0.0.0/24', 79 '192.0.2.0/24', 80 '192.88.99.0/24', 81 '192.168.0.0/16' 82 ), 83 '198' => '198.18.0.0/15', 84 '223' => '223.255.255.0/24', 85 '224' => '224.0.0.0/4', 86 '240' => '240.0.0.0/4' 87 ); 88 89 /** 90 * @var array 91 */ 92 protected $_messageVariables = array( 93 'hostname' => '_hostname', 94 'localPart' => '_localPart' 95 ); 96 97 /** 98 * @var string 99 */ 100 protected $_hostname; 101 102 /** 103 * @var string 104 */ 105 protected $_localPart; 106 107 /** 108 * Internal options array 109 */ 110 protected $_options = array( 111 'mx' => false, 112 'deep' => false, 113 'domain' => true, 114 'allow' => Zend_Validate_Hostname::ALLOW_DNS, 115 'hostname' => null 116 ); 117 118 /** 119 * Instantiates hostname validator for local use 120 * 121 * The following option keys are supported: 122 * 'hostname' => A hostname validator, see Zend_Validate_Hostname 123 * 'allow' => Options for the hostname validator, see Zend_Validate_Hostname::ALLOW_* 124 * 'mx' => If MX check should be enabled, boolean 125 * 'deep' => If a deep MX check should be done, boolean 126 * 127 * @param array|Zend_Config $options OPTIONAL 128 * @return void 129 */ 130 public function __construct($options = array()) 131 { 132 if ($options instanceof Zend_Config) { 133 $options = $options->toArray(); 134 } else if (!is_array($options)) { 135 $options = func_get_args(); 136 $temp['allow'] = array_shift($options); 137 if (!empty($options)) { 138 $temp['mx'] = array_shift($options); 139 } 140 141 if (!empty($options)) { 142 $temp['hostname'] = array_shift($options); 143 } 144 145 $options = $temp; 146 } 147 148 $options += $this->_options; 149 $this->setOptions($options); 150 } 151 152 /** 153 * Returns all set Options 154 * 155 * @return array 156 */ 157 public function getOptions() 158 { 159 return $this->_options; 160 } 161 162 /** 163 * Set options for the email validator 164 * 165 * @param array $options 166 * @return Zend_Validate_EmailAddress fluid interface 167 */ 168 public function setOptions(array $options = array()) 169 { 170 if (array_key_exists('messages', $options)) { 171 $this->setMessages($options['messages']); 172 } 173 174 if (array_key_exists('hostname', $options)) { 175 if (array_key_exists('allow', $options)) { 176 $this->setHostnameValidator($options['hostname'], $options['allow']); 177 } else { 178 $this->setHostnameValidator($options['hostname']); 179 } 180 } 181 182 if (array_key_exists('mx', $options)) { 183 $this->setValidateMx($options['mx']); 184 } 185 186 if (array_key_exists('deep', $options)) { 187 $this->setDeepMxCheck($options['deep']); 188 } 189 190 if (array_key_exists('domain', $options)) { 191 $this->setDomainCheck($options['domain']); 192 } 193 194 return $this; 195 } 196 197 /** 198 * Sets the validation failure message template for a particular key 199 * Adds the ability to set messages to the attached hostname validator 200 * 201 * @param string $messageString 202 * @param string $messageKey OPTIONAL 203 * @return Zend_Validate_Abstract Provides a fluent interface 204 * @throws Zend_Validate_Exception 205 */ 206 public function setMessage($messageString, $messageKey = null) 207 { 208 $messageKeys = $messageKey; 209 if ($messageKey === null) { 210 $keys = array_keys($this->_messageTemplates); 211 $messageKeys = current($keys); 212 } 213 214 if (!isset($this->_messageTemplates[$messageKeys])) { 215 $this->_options['hostname']->setMessage($messageString, $messageKey); 216 } 217 218 $this->_messageTemplates[$messageKeys] = $messageString; 219 return $this; 220 } 221 222 /** 223 * Returns the set hostname validator 224 * 225 * @return Zend_Validate_Hostname 226 */ 227 public function getHostnameValidator() 228 { 229 return $this->_options['hostname']; 230 } 231 232 /** 233 * @param Zend_Validate_Hostname $hostnameValidator OPTIONAL 234 * @param int $allow OPTIONAL 235 * @return void 236 */ 237 public function setHostnameValidator(Zend_Validate_Hostname $hostnameValidator = null, $allow = Zend_Validate_Hostname::ALLOW_DNS) 238 { 239 if (!$hostnameValidator) { 240 $hostnameValidator = new Zend_Validate_Hostname($allow); 241 } 242 243 $this->_options['hostname'] = $hostnameValidator; 244 $this->_options['allow'] = $allow; 245 return $this; 246 } 247 248 /** 249 * Whether MX checking via getmxrr is supported or not 250 * 251 * This currently only works on UNIX systems 252 * 253 * @return boolean 254 */ 255 public function validateMxSupported() 256 { 257 return function_exists('getmxrr'); 258 } 259 260 /** 261 * Returns the set validateMx option 262 * 263 * @return boolean 264 */ 265 public function getValidateMx() 266 { 267 return $this->_options['mx']; 268 } 269 270 /** 271 * Set whether we check for a valid MX record via DNS 272 * 273 * This only applies when DNS hostnames are validated 274 * 275 * @param boolean $mx Set allowed to true to validate for MX records, and false to not validate them 276 * @return Zend_Validate_EmailAddress Fluid Interface 277 */ 278 public function setValidateMx($mx) 279 { 280 if ((bool) $mx && !$this->validateMxSupported()) { 281 require_once 'Zend/Validate/Exception.php'; 282 throw new Zend_Validate_Exception('MX checking not available on this system'); 283 } 284 285 $this->_options['mx'] = (bool) $mx; 286 return $this; 287 } 288 289 /** 290 * Returns the set deepMxCheck option 291 * 292 * @return boolean 293 */ 294 public function getDeepMxCheck() 295 { 296 return $this->_options['deep']; 297 } 298 299 /** 300 * Set whether we check MX record should be a deep validation 301 * 302 * @param boolean $deep Set deep to true to perform a deep validation process for MX records 303 * @return Zend_Validate_EmailAddress Fluid Interface 304 */ 305 public function setDeepMxCheck($deep) 306 { 307 $this->_options['deep'] = (bool) $deep; 308 return $this; 309 } 310 311 /** 312 * Returns the set domainCheck option 313 * 314 * @return unknown 315 */ 316 public function getDomainCheck() 317 { 318 return $this->_options['domain']; 319 } 320 321 /** 322 * Sets if the domain should also be checked 323 * or only the local part of the email address 324 * 325 * @param boolean $domain 326 * @return Zend_Validate_EmailAddress Fluid Interface 327 */ 328 public function setDomainCheck($domain = true) 329 { 330 $this->_options['domain'] = (boolean) $domain; 331 return $this; 332 } 333 334 /** 335 * Returns if the given host is reserved 336 * 337 * @param string $host 338 * @return boolean 339 */ 340 private function _isReserved($host){ 341 if (!preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $host)) { 342 $host = gethostbyname($host); 343 } 344 345 $octet = explode('.',$host); 346 if ((int)$octet[0] >= 224) { 347 return true; 348 } else if (array_key_exists($octet[0], $this->_invalidIp)) { 349 foreach ((array)$this->_invalidIp[$octet[0]] as $subnetData) { 350 // we skip the first loop as we already know that octet matches 351 for ($i = 1; $i < 4; $i++) { 352 if (strpos($subnetData, $octet[$i]) !== $i * 4) { 353 break; 354 } 355 } 356 357 $host = explode("/", $subnetData); 358 $binaryHost = ""; 359 $tmp = explode(".", $host[0]); 360 for ($i = 0; $i < 4 ; $i++) { 361 $binaryHost .= str_pad(decbin($tmp[$i]), 8, "0", STR_PAD_LEFT); 362 } 363 364 $segmentData = array( 365 'network' => (int)$this->_toIp(str_pad(substr($binaryHost, 0, $host[1]), 32, 0)), 366 'broadcast' => (int)$this->_toIp(str_pad(substr($binaryHost, 0, $host[1]), 32, 1)) 367 ); 368 369 for ($j = $i; $j < 4; $j++) { 370 if ((int)$octet[$j] < $segmentData['network'][$j] || 371 (int)$octet[$j] > $segmentData['broadcast'][$j]) { 372 return false; 373 } 374 } 375 } 376 377 return true; 378 } else { 379 return false; 380 } 381 } 382 383 /** 384 * Converts a binary string to an IP address 385 * 386 * @param string $binary 387 * @return mixed 388 */ 389 private function _toIp($binary) 390 { 391 $ip = array(); 392 $tmp = explode(".", chunk_split($binary, 8, ".")); 393 for ($i = 0; $i < 4 ; $i++) { 394 $ip[$i] = bindec($tmp[$i]); 395 } 396 397 return $ip; 398 } 399 400 /** 401 * Internal method to validate the local part of the email address 402 * 403 * @return boolean 404 */ 405 private function _validateLocalPart() 406 { 407 // First try to match the local part on the common dot-atom format 408 $result = false; 409 410 // Dot-atom characters are: 1*atext *("." 1*atext) 411 // atext: ALPHA / DIGIT / and "!", "#", "$", "%", "&", "'", "*", 412 // "+", "-", "/", "=", "?", "^", "_", "`", "{", "|", "}", "~" 413 $atext = 'a-zA-Z0-9\x21\x23\x24\x25\x26\x27\x2a\x2b\x2d\x2f\x3d\x3f\x5e\x5f\x60\x7b\x7c\x7d\x7e'; 414 if (preg_match('/^[' . $atext . ']+(\x2e+[' . $atext . ']+)*$/', $this->_localPart)) { 415 $result = true; 416 } else { 417 // Try quoted string format 418 419 // Quoted-string characters are: DQUOTE *([FWS] qtext/quoted-pair) [FWS] DQUOTE 420 // qtext: Non white space controls, and the rest of the US-ASCII characters not 421 // including "\" or the quote character 422 $noWsCtl = '\x01-\x08\x0b\x0c\x0e-\x1f\x7f'; 423 $qtext = $noWsCtl . '\x21\x23-\x5b\x5d-\x7e'; 424 $ws = '\x20\x09'; 425 if (preg_match('/^\x22([' . $ws . $qtext . '])*[$ws]?\x22$/', $this->_localPart)) { 426 $result = true; 427 } else { 428 $this->_error(self::DOT_ATOM); 429 $this->_error(self::QUOTED_STRING); 430 $this->_error(self::INVALID_LOCAL_PART); 431 } 432 } 433 434 return $result; 435 } 436 437 /** 438 * Internal method to validate the servers MX records 439 * 440 * @return boolean 441 */ 442 private function _validateMXRecords() 443 { 444 $mxHosts = array(); 445 $result = getmxrr($this->_hostname, $mxHosts); 446 if (!$result) { 447 $this->_error(self::INVALID_MX_RECORD); 448 } else if ($this->_options['deep'] && function_exists('checkdnsrr')) { 449 $validAddress = false; 450 $reserved = true; 451 foreach ($mxHosts as $hostname) { 452 $res = $this->_isReserved($hostname); 453 if (!$res) { 454 $reserved = false; 455 } 456 457 if (!$res 458 && (checkdnsrr($hostname, "A") 459 || checkdnsrr($hostname, "AAAA") 460 || checkdnsrr($hostname, "A6"))) { 461 $validAddress = true; 462 break; 463 } 464 } 465 466 if (!$validAddress) { 467 $result = false; 468 if ($reserved) { 469 $this->_error(self::INVALID_SEGMENT); 470 } else { 471 $this->_error(self::INVALID_MX_RECORD); 472 } 473 } 474 } 475 476 return $result; 477 } 478 479 /** 480 * Internal method to validate the hostname part of the email address 481 * 482 * @return boolean 483 */ 484 private function _validateHostnamePart() 485 { 486 $hostname = $this->_options['hostname']->setTranslator($this->getTranslator()) 487 ->isValid($this->_hostname); 488 if (!$hostname) { 489 $this->_error(self::INVALID_HOSTNAME); 490 491 // Get messages and errors from hostnameValidator 492 foreach ($this->_options['hostname']->getMessages() as $code => $message) { 493 $this->_messages[$code] = $message; 494 } 495 496 foreach ($this->_options['hostname']->getErrors() as $error) { 497 $this->_errors[] = $error; 498 } 499 } else if ($this->_options['mx']) { 500 // MX check on hostname 501 $hostname = $this->_validateMXRecords(); 502 } 503 504 return $hostname; 505 } 506 507 /** 508 * Defined by Zend_Validate_Interface 509 * 510 * Returns true if and only if $value is a valid email address 511 * according to RFC2822 512 * 513 * @link http://www.ietf.org/rfc/rfc2822.txt RFC2822 514 * @link http://www.columbia.edu/kermit/ascii.html US-ASCII characters 515 * @param string $value 516 * @return boolean 517 */ 518 public function isValid($value) 519 { 520 if (!is_string($value)) { 521 $this->_error(self::INVALID); 522 return false; 523 } 524 525 $matches = array(); 526 $length = true; 527 $this->_setValue($value); 528 529 // Split email address up and disallow '..' 530 if ((strpos($value, '..') !== false) or 531 (!preg_match('/^(.+)@([^@]+)$/', $value, $matches))) { 532 $this->_error(self::INVALID_FORMAT); 533 return false; 534 } 535 536 $this->_localPart = $matches[1]; 537 $this->_hostname = $matches[2]; 538 539 if ((strlen($this->_localPart) > 64) || (strlen($this->_hostname) > 255)) { 540 $length = false; 541 $this->_error(self::LENGTH_EXCEEDED); 542 } 543 544 // Match hostname part 545 if ($this->_options['domain']) { 546 $hostname = $this->_validateHostnamePart(); 547 } 548 549 $local = $this->_validateLocalPart(); 550 551 // If both parts valid, return true 552 if ($local && $length) { 553 if (($this->_options['domain'] && $hostname) || !$this->_options['domain']) { 554 return true; 555 } 556 } 557 558 return false; 559 } 560 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 20:29:05 2014 | Cross-referenced by PHPXref 0.7.1 |