EmailValidator.php 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Validator\Constraints;
  11. use Symfony\Component\Validator\Constraint;
  12. use Symfony\Component\Validator\ConstraintValidator;
  13. use Symfony\Component\Validator\Context\ExecutionContextInterface;
  14. use Symfony\Component\Validator\Exception\RuntimeException;
  15. use Symfony\Component\Validator\Exception\UnexpectedTypeException;
  16. /**
  17. * @author Bernhard Schussek <bschussek@gmail.com>
  18. */
  19. class EmailValidator extends ConstraintValidator
  20. {
  21. private $isStrict;
  22. /**
  23. * @param bool $strict
  24. */
  25. public function __construct($strict = false)
  26. {
  27. $this->isStrict = $strict;
  28. }
  29. /**
  30. * {@inheritdoc}
  31. */
  32. public function validate($value, Constraint $constraint)
  33. {
  34. if (!$constraint instanceof Email) {
  35. throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Email');
  36. }
  37. if (null === $value || '' === $value) {
  38. return;
  39. }
  40. if (!is_scalar($value) && !(\is_object($value) && method_exists($value, '__toString'))) {
  41. throw new UnexpectedTypeException($value, 'string');
  42. }
  43. $value = (string) $value;
  44. if (null === $constraint->strict) {
  45. $constraint->strict = $this->isStrict;
  46. }
  47. if ($constraint->strict) {
  48. if (!class_exists('\Egulias\EmailValidator\EmailValidator') || interface_exists('\Egulias\EmailValidator\Validation\EmailValidation')) {
  49. throw new RuntimeException('Strict email validation requires egulias/email-validator:~1.2');
  50. }
  51. $strictValidator = new \Egulias\EmailValidator\EmailValidator();
  52. if (!$strictValidator->isValid($value, false, true)) {
  53. if ($this->context instanceof ExecutionContextInterface) {
  54. $this->context->buildViolation($constraint->message)
  55. ->setParameter('{{ value }}', $this->formatValue($value))
  56. ->setCode(Email::INVALID_FORMAT_ERROR)
  57. ->addViolation();
  58. } else {
  59. $this->buildViolation($constraint->message)
  60. ->setParameter('{{ value }}', $this->formatValue($value))
  61. ->setCode(Email::INVALID_FORMAT_ERROR)
  62. ->addViolation();
  63. }
  64. return;
  65. }
  66. } elseif (!preg_match('/^.+\@\S+\.\S+$/', $value)) {
  67. if ($this->context instanceof ExecutionContextInterface) {
  68. $this->context->buildViolation($constraint->message)
  69. ->setParameter('{{ value }}', $this->formatValue($value))
  70. ->setCode(Email::INVALID_FORMAT_ERROR)
  71. ->addViolation();
  72. } else {
  73. $this->buildViolation($constraint->message)
  74. ->setParameter('{{ value }}', $this->formatValue($value))
  75. ->setCode(Email::INVALID_FORMAT_ERROR)
  76. ->addViolation();
  77. }
  78. return;
  79. }
  80. $host = (string) substr($value, strrpos($value, '@') + 1);
  81. // Check for host DNS resource records
  82. if ($constraint->checkMX) {
  83. if (!$this->checkMX($host)) {
  84. if ($this->context instanceof ExecutionContextInterface) {
  85. $this->context->buildViolation($constraint->message)
  86. ->setParameter('{{ value }}', $this->formatValue($value))
  87. ->setCode(Email::MX_CHECK_FAILED_ERROR)
  88. ->addViolation();
  89. } else {
  90. $this->buildViolation($constraint->message)
  91. ->setParameter('{{ value }}', $this->formatValue($value))
  92. ->setCode(Email::MX_CHECK_FAILED_ERROR)
  93. ->addViolation();
  94. }
  95. }
  96. return;
  97. }
  98. if ($constraint->checkHost && !$this->checkHost($host)) {
  99. if ($this->context instanceof ExecutionContextInterface) {
  100. $this->context->buildViolation($constraint->message)
  101. ->setParameter('{{ value }}', $this->formatValue($value))
  102. ->setCode(Email::HOST_CHECK_FAILED_ERROR)
  103. ->addViolation();
  104. } else {
  105. $this->buildViolation($constraint->message)
  106. ->setParameter('{{ value }}', $this->formatValue($value))
  107. ->setCode(Email::HOST_CHECK_FAILED_ERROR)
  108. ->addViolation();
  109. }
  110. }
  111. }
  112. /**
  113. * Check DNS Records for MX type.
  114. *
  115. * @param string $host Host
  116. *
  117. * @return bool
  118. */
  119. private function checkMX($host)
  120. {
  121. return '' !== $host && checkdnsrr($host, 'MX');
  122. }
  123. /**
  124. * Check if one of MX, A or AAAA DNS RR exists.
  125. *
  126. * @param string $host Host
  127. *
  128. * @return bool
  129. */
  130. private function checkHost($host)
  131. {
  132. return '' !== $host && ($this->checkMX($host) || (checkdnsrr($host, 'A') || checkdnsrr($host, 'AAAA')));
  133. }
  134. }