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.

118 lines
4.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. // make sure string length is limited to avoid DOS attacks
  68. if (!is_string($value) || strlen($value) >= 320) {
  69. $valid = false;
  70. } elseif (!preg_match('/^(.*<?)(.*)@(.*?)(>?)$/', $value, $matches)) {
  71. $valid = false;
  72. } else {
  73. $domain = $matches[3];
  74. if ($this->enableIDN) {
  75. $value = $matches[1] . idn_to_ascii($matches[2]) . '@' . idn_to_ascii($domain) . $matches[4];
  76. }
  77. $valid = preg_match($this->pattern, $value) || $this->allowName && preg_match($this->fullPattern, $value);
  78. if ($valid && $this->checkDNS) {
  79. $valid = checkdnsrr($domain, 'MX') || checkdnsrr($domain, 'A');
  80. }
  81. }
  82. return $valid ? null : [$this->message, []];
  83. }
  84. /**
  85. * @inheritdoc
  86. */
  87. public function clientValidateAttribute($model, $attribute, $view)
  88. {
  89. $options = [
  90. 'pattern' => new JsExpression($this->pattern),
  91. 'fullPattern' => new JsExpression($this->fullPattern),
  92. 'allowName' => $this->allowName,
  93. 'message' => Yii::$app->getI18n()->format($this->message, [
  94. 'attribute' => $model->getAttributeLabel($attribute),
  95. ], Yii::$app->language),
  96. 'enableIDN' => (boolean) $this->enableIDN,
  97. ];
  98. if ($this->skipOnEmpty) {
  99. $options['skipOnEmpty'] = 1;
  100. }
  101. ValidationAsset::register($view);
  102. if ($this->enableIDN) {
  103. PunycodeAsset::register($view);
  104. }
  105. return 'yii.validation.email(value, messages, ' . Json::encode($options) . ');';
  106. }
  107. }