You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

133 line
5.2KB

  1. <?php
  2. /**
  3. * @link http://www.yiiframework.com/
  4. * @copyright Copyright (c) 2008 Yii Software LLC
  5. * @license http://www.yiiframework.com/license/
  6. */
  7. namespace yii\validators;
  8. use Yii;
  9. use yii\base\InvalidConfigException;
  10. use yii\web\JsExpression;
  11. use yii\helpers\Json;
  12. /**
  13. * EmailValidator validates that the attribute value is a valid email address.
  14. *
  15. * @author Qiang Xue <qiang.xue@gmail.com>
  16. * @since 2.0
  17. */
  18. class EmailValidator extends Validator
  19. {
  20. /**
  21. * @var string the regular expression used to validate the attribute value.
  22. * @see http://www.regular-expressions.info/email.html
  23. */
  24. public $pattern = '/^[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$/';
  25. /**
  26. * @var string the regular expression used to validate email addresses with the name part.
  27. * This property is used only when [[allowName]] is true.
  28. * @see allowName
  29. */
  30. public $fullPattern = '/^[^@]*<[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?>$/';
  31. /**
  32. * @var boolean whether to allow name in the email address (e.g. "John Smith <john.smith@example.com>"). Defaults to false.
  33. * @see fullPattern
  34. */
  35. public $allowName = false;
  36. /**
  37. * @var boolean whether to check whether the email's domain exists and has either an A or MX record.
  38. * Be aware that this check can fail due to temporary DNS problems even if the email address is
  39. * valid and an email would be deliverable. Defaults to false.
  40. */
  41. public $checkDNS = false;
  42. /**
  43. * @var boolean whether validation process should take into account IDN (internationalized domain
  44. * names). Defaults to false meaning that validation of emails containing IDN will always fail.
  45. * Note that in order to use IDN validation you have to install and enable `intl` PHP extension,
  46. * otherwise an exception would be thrown.
  47. */
  48. public $enableIDN = false;
  49. /**
  50. * @inheritdoc
  51. */
  52. public function init()
  53. {
  54. parent::init();
  55. if ($this->enableIDN && !function_exists('idn_to_ascii')) {
  56. throw new InvalidConfigException('In order to use IDN validation intl extension must be installed and enabled.');
  57. }
  58. if ($this->message === null) {
  59. $this->message = Yii::t('yii', '{attribute} is not a valid email address.');
  60. }
  61. }
  62. /**
  63. * @inheritdoc
  64. */
  65. protected function validateValue($value)
  66. {
  67. if (!is_string($value)) {
  68. $valid = false;
  69. } elseif (!preg_match('/^(?P<name>(?:"?([^"]*)"?\s)?)(?:\s+)?(?:(?P<open><?)((?P<local>.+)@(?P<domain>[^>]+))(?P<close>>?))$/i', $value, $matches)) {
  70. $valid = false;
  71. } else {
  72. if ($this->enableIDN) {
  73. $matches['local'] = idn_to_ascii($matches['local']);
  74. $matches['domain'] = idn_to_ascii($matches['domain']);
  75. $value = $matches['name'] . $matches['open'] . $matches['local'] . '@' . $matches['domain'] . $matches['close'];
  76. }
  77. if (strlen($matches['local']) > 64) {
  78. // The maximum total length of a user name or other local-part is 64 octets. RFC 5322 section 4.5.3.1.1
  79. // http://tools.ietf.org/html/rfc5321#section-4.5.3.1.1
  80. $valid = false;
  81. } elseif (strlen($matches['local'] . '@' . $matches['domain']) > 254) {
  82. // There is a restriction in RFC 2821 on the length of an address in MAIL and RCPT commands
  83. // of 254 characters. Since addresses that do not fit in those fields are not normally useful, the
  84. // upper limit on address lengths should normally be considered to be 254.
  85. //
  86. // Dominic Sayers, RFC 3696 erratum 1690
  87. // http://www.rfc-editor.org/errata_search.php?eid=1690
  88. $valid = false;
  89. } else {
  90. $valid = preg_match($this->pattern, $value) || $this->allowName && preg_match($this->fullPattern, $value);
  91. if ($valid && $this->checkDNS) {
  92. $valid = checkdnsrr($matches['domain'], 'MX') || checkdnsrr($matches['domain'], 'A');
  93. }
  94. }
  95. }
  96. return $valid ? null : [$this->message, []];
  97. }
  98. /**
  99. * @inheritdoc
  100. */
  101. public function clientValidateAttribute($model, $attribute, $view)
  102. {
  103. $options = [
  104. 'pattern' => new JsExpression($this->pattern),
  105. 'fullPattern' => new JsExpression($this->fullPattern),
  106. 'allowName' => $this->allowName,
  107. 'message' => Yii::$app->getI18n()->format($this->message, [
  108. 'attribute' => $model->getAttributeLabel($attribute),
  109. ], Yii::$app->language),
  110. 'enableIDN' => (bool)$this->enableIDN,
  111. ];
  112. if ($this->skipOnEmpty) {
  113. $options['skipOnEmpty'] = 1;
  114. }
  115. ValidationAsset::register($view);
  116. if ($this->enableIDN) {
  117. PunycodeAsset::register($view);
  118. }
  119. return 'yii.validation.email(value, messages, ' . Json::htmlEncode($options) . ');';
  120. }
  121. }