Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
EmailAddress.php
Go to the documentation of this file.
1 <?php
25 #require_once 'Zend/Validate/Abstract.php';
26 
30 #require_once 'Zend/Validate/Hostname.php';
31 
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 
53  protected $_messageTemplates = array(
54  self::INVALID => "Invalid type given. String expected",
55  self::INVALID_FORMAT => "'%value%' is not a valid email address in the basic format local-part@hostname",
56  self::INVALID_HOSTNAME => "'%hostname%' is not a 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 not a valid local part for email address '%value%'",
62  self::LENGTH_EXCEEDED => "'%value%' exceeds the allowed length",
63  );
64 
79  protected $_invalidIp = array(
80  '0' => '0.0.0.0/8',
81  '10' => '10.0.0.0/8',
82  '100' => '100.64.0.0/10',
83  '127' => '127.0.0.0/8',
84  '169' => '169.254.0.0/16',
85  '172' => '172.16.0.0/12',
86  '192' => array(
87  '192.0.0.0/24',
88  '192.0.2.0/24',
89  '192.88.99.0/24',
90  '192.168.0.0/16'
91  ),
92  '198' => '198.18.0.0/15',
93  '224' => '224.0.0.0/4',
94  '240' => '240.0.0.0/4'
95  );
96 
100  protected $_messageVariables = array(
101  'hostname' => '_hostname',
102  'localPart' => '_localPart'
103  );
104 
108  protected $_hostname;
109 
113  protected $_localPart;
114 
118  protected $_options = array(
119  'mx' => false,
120  'deep' => false,
121  'domain' => true,
123  'hostname' => null
124  );
125 
137  public function __construct($options = array())
138  {
139  if ($options instanceof Zend_Config) {
140  $options = $options->toArray();
141  } else if (!is_array($options)) {
142  $options = func_get_args();
143  $temp['allow'] = array_shift($options);
144  if (!empty($options)) {
145  $temp['mx'] = array_shift($options);
146  }
147 
148  if (!empty($options)) {
149  $temp['hostname'] = array_shift($options);
150  }
151 
152  $options = $temp;
153  }
154 
156  $this->setOptions($options);
157  }
158 
164  public function getOptions()
165  {
166  return $this->_options;
167  }
168 
175  public function setOptions(array $options = array())
176  {
177  if (array_key_exists('messages', $options)) {
178  $this->setMessages($options['messages']);
179  }
180 
181  if (array_key_exists('hostname', $options)) {
182  if (array_key_exists('allow', $options)) {
183  $this->setHostnameValidator($options['hostname'], $options['allow']);
184  } else {
185  $this->setHostnameValidator($options['hostname']);
186  }
187  } elseif ($this->_options['hostname'] == null) {
188  $this->setHostnameValidator();
189  }
190 
191  if (array_key_exists('mx', $options)) {
192  $this->setValidateMx($options['mx']);
193  }
194 
195  if (array_key_exists('deep', $options)) {
196  $this->setDeepMxCheck($options['deep']);
197  }
198 
199  if (array_key_exists('domain', $options)) {
200  $this->setDomainCheck($options['domain']);
201  }
202 
203  return $this;
204  }
205 
215  public function setMessage($messageString, $messageKey = null)
216  {
217  if ($messageKey === null) {
218  $this->_options['hostname']->setMessage($messageString);
219  parent::setMessage($messageString);
220  return $this;
221  }
222 
223  if (!isset($this->_messageTemplates[$messageKey])) {
224  $this->_options['hostname']->setMessage($messageString, $messageKey);
225  }
226 
227  $this->_messageTemplates[$messageKey] = $messageString;
228  return $this;
229  }
230 
236  public function getHostnameValidator()
237  {
238  return $this->_options['hostname'];
239  }
240 
246  public function setHostnameValidator(Zend_Validate_Hostname $hostnameValidator = null, $allow = Zend_Validate_Hostname::ALLOW_DNS)
247  {
248  if (!$hostnameValidator) {
249  $hostnameValidator = new Zend_Validate_Hostname($allow);
250  }
251 
252  $this->_options['hostname'] = $hostnameValidator;
253  $this->_options['allow'] = $allow;
254  return $this;
255  }
256 
264  public function validateMxSupported()
265  {
266  return function_exists('getmxrr');
267  }
268 
274  public function getValidateMx()
275  {
276  return $this->_options['mx'];
277  }
278 
288  public function setValidateMx($mx)
289  {
290  if ((bool) $mx && !$this->validateMxSupported()) {
291  #require_once 'Zend/Validate/Exception.php';
292  throw new Zend_Validate_Exception('MX checking not available on this system');
293  }
294 
295  $this->_options['mx'] = (bool) $mx;
296  return $this;
297  }
298 
304  public function getDeepMxCheck()
305  {
306  return $this->_options['deep'];
307  }
308 
315  public function setDeepMxCheck($deep)
316  {
317  $this->_options['deep'] = (bool) $deep;
318  return $this;
319  }
320 
326  public function getDomainCheck()
327  {
328  return $this->_options['domain'];
329  }
330 
338  public function setDomainCheck($domain = true)
339  {
340  $this->_options['domain'] = (boolean) $domain;
341  return $this;
342  }
343 
350  private function _isReserved($host){
351  if (!preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $host)) {
352  $host = gethostbyname($host);
353  }
354 
355  $octet = explode('.',$host);
356  if ((int)$octet[0] >= 224) {
357  return true;
358  } else if (array_key_exists($octet[0], $this->_invalidIp)) {
359  foreach ((array)$this->_invalidIp[$octet[0]] as $subnetData) {
360  // we skip the first loop as we already know that octet matches
361  for ($i = 1; $i < 4; $i++) {
362  if (strpos($subnetData, $octet[$i]) !== $i * 4) {
363  break;
364  }
365  }
366 
367  $host = explode("/", $subnetData);
368  $binaryHost = "";
369  $tmp = explode(".", $host[0]);
370  for ($i = 0; $i < 4 ; $i++) {
371  $binaryHost .= str_pad(decbin($tmp[$i]), 8, "0", STR_PAD_LEFT);
372  }
373 
374  $segmentData = array(
375  'network' => (int)$this->_toIp(str_pad(substr($binaryHost, 0, $host[1]), 32, 0)),
376  'broadcast' => (int)$this->_toIp(str_pad(substr($binaryHost, 0, $host[1]), 32, 1))
377  );
378 
379  for ($j = $i; $j < 4; $j++) {
380  if ((int)$octet[$j] < $segmentData['network'][$j] ||
381  (int)$octet[$j] > $segmentData['broadcast'][$j]) {
382  return false;
383  }
384  }
385  }
386 
387  return true;
388  } else {
389  return false;
390  }
391  }
392 
399  private function _toIp($binary)
400  {
401  $ip = array();
402  $tmp = explode(".", chunk_split($binary, 8, "."));
403  for ($i = 0; $i < 4 ; $i++) {
404  $ip[$i] = bindec($tmp[$i]);
405  }
406 
407  return $ip;
408  }
409 
415  private function _validateLocalPart()
416  {
417  // First try to match the local part on the common dot-atom format
418  $result = false;
419 
420  // Dot-atom characters are: 1*atext *("." 1*atext)
421  // atext: ALPHA / DIGIT / and "!", "#", "$", "%", "&", "'", "*",
422  // "+", "-", "/", "=", "?", "^", "_", "`", "{", "|", "}", "~"
423  $atext = 'a-zA-Z0-9\x21\x23\x24\x25\x26\x27\x2a\x2b\x2d\x2f\x3d\x3f\x5e\x5f\x60\x7b\x7c\x7d\x7e';
424  if (preg_match('/^[' . $atext . ']+(\x2e+[' . $atext . ']+)*$/', $this->_localPart)) {
425  $result = true;
426  } else {
427  // Try quoted string format (RFC 5321 Chapter 4.1.2)
428 
429  // Quoted-string characters are: DQUOTE *(qtext/quoted-pair) DQUOTE
430  $qtext = '\x20-\x21\x23-\x5b\x5d-\x7e'; // %d32-33 / %d35-91 / %d93-126
431  $quotedPair = '\x20-\x7e'; // %d92 %d32-126
432  if (preg_match('/^"(['. $qtext .']|\x5c[' . $quotedPair . '])*"$/', $this->localPart)) {
433  $result = true;
434  } else {
435  $this->_error(self::DOT_ATOM);
436  $this->_error(self::QUOTED_STRING);
437  $this->_error(self::INVALID_LOCAL_PART);
438  }
439  }
440 
441  return $result;
442  }
443 
449  private function _validateMXRecords()
450  {
451  $mxHosts = array();
452  $hostname = $this->_hostname;
453 
454  //decode IDN domain name if possible
455  if (function_exists('idn_to_ascii')) {
456  $hostname = idn_to_ascii($this->_hostname);
457  }
458 
459  $result = getmxrr($hostname, $mxHosts);
460  if (!$result) {
461  $this->_error(self::INVALID_MX_RECORD);
462  } else if ($this->_options['deep'] && function_exists('checkdnsrr')) {
463  $validAddress = false;
464  $reserved = true;
465  foreach ($mxHosts as $hostname) {
466  $res = $this->_isReserved($hostname);
467  if (!$res) {
468  $reserved = false;
469  }
470 
471  if (!$res
472  && (checkdnsrr($hostname, "A")
473  || checkdnsrr($hostname, "AAAA")
474  || checkdnsrr($hostname, "A6"))) {
475  $validAddress = true;
476  break;
477  }
478  }
479 
480  if (!$validAddress) {
481  $result = false;
482  if ($reserved) {
483  $this->_error(self::INVALID_SEGMENT);
484  } else {
485  $this->_error(self::INVALID_MX_RECORD);
486  }
487  }
488  }
489 
490  return $result;
491  }
492 
498  private function _validateHostnamePart()
499  {
500  $hostname = $this->_options['hostname']->setTranslator($this->getTranslator())
501  ->isValid($this->_hostname);
502  if (!$hostname) {
503  $this->_error(self::INVALID_HOSTNAME);
504 
505  // Get messages and errors from hostnameValidator
506  foreach ($this->_options['hostname']->getMessages() as $code => $message) {
507  $this->_messages[$code] = $message;
508  }
509 
510  foreach ($this->_options['hostname']->getErrors() as $error) {
511  $this->_errors[] = $error;
512  }
513  } else if ($this->_options['mx']) {
514  // MX check on hostname
515  $hostname = $this->_validateMXRecords();
516  }
517 
518  return $hostname;
519  }
520 
532  public function isValid($value)
533  {
534  if (!is_string($value)) {
535  $this->_error(self::INVALID);
536  return false;
537  }
538 
539  $matches = array();
540  $length = true;
541  $this->_setValue($value);
542 
543  // Split email address up and disallow '..'
544  if ((strpos($value, '..') !== false) or
545  (!preg_match('/^(.+)@([^@]+)$/', $value, $matches))) {
546  $this->_error(self::INVALID_FORMAT);
547  return false;
548  }
549 
550  $this->_localPart = $matches[1];
551  $this->_hostname = $matches[2];
552 
553  if ((strlen($this->_localPart) > 64) || (strlen($this->_hostname) > 255)) {
554  $length = false;
555  $this->_error(self::LENGTH_EXCEEDED);
556  }
557 
558  // Match hostname part
559  if ($this->_options['domain']) {
560  $hostname = $this->_validateHostnamePart();
561  }
562 
563  $local = $this->_validateLocalPart();
564 
565  // If both parts valid, return true
566  if ($local && $length) {
567  if (($this->_options['domain'] && $hostname) || !$this->_options['domain']) {
568  return true;
569  }
570  }
571 
572  return false;
573  }
574 }
elseif(isset( $params[ 'redirect_parent']))
Definition: iframe.phtml:17
__construct($options=array())
$message
_error($messageKey, $value=null)
Definition: Abstract.php:284
$value
Definition: gender.phtml:16
setHostnameValidator(Zend_Validate_Hostname $hostnameValidator=null, $allow=Zend_Validate_Hostname::ALLOW_DNS)
setMessages(array $messages)
Definition: Abstract.php:167
setOptions(array $options=array())
setMessage($messageString, $messageKey=null)
$i
Definition: gallery.phtml:31
$code
Definition: info.phtml:12