-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathEmailValidator.php
More file actions
83 lines (73 loc) · 3.28 KB
/
EmailValidator.php
File metadata and controls
83 lines (73 loc) · 3.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
<?php
declare(strict_types=1);
namespace AssoConnect\ValidatorBundle\Validator\Constraints;
use Egulias\EmailValidator\Validation\DNSCheckValidation;
use Pdp\Domain;
use Pdp\Storage\PublicSuffixListClient;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Constraints\Email as _Email;
use Symfony\Component\Validator\Constraints\EmailValidator as _EmailValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
/**
* The 4 steps for validation are:
* 1. PHP filter_var() function
* 2. Does the domain use a valid public suffix?
* 3. Is there at least one MX server for the domain?
* 4. Default Symfony validation
*/
class EmailValidator extends _EmailValidator
{
public const PUBLIC_SUFFIX_LIST_URI = 'https://publicsuffix.org/list/public_suffix_list.dat';
private PublicSuffixListClient $publicSuffixListClient;
public function __construct(
PublicSuffixListClient $publicSuffixListClient,
string $defaultMode = 'html5'
) {
parent::__construct($defaultMode);
$this->publicSuffixListClient = $publicSuffixListClient;
}
public function validate(mixed $value, Constraint $constraint): void
{
if (!$constraint instanceof Email) {
throw new UnexpectedTypeException($constraint, __NAMESPACE__ . '\Email');
}
if ($value === null || $value === '') {
return;
}
// 1. PHP filter_var() function
// First one because it is a quick one
if (false === filter_var($value, FILTER_VALIDATE_EMAIL)) {
$this->context->buildViolation($constraint->message)
->setParameter('{{ value }}', $this->formatValue($value))
->setCode(_Email::INVALID_FORMAT_ERROR)
->addViolation();
return;
}
// 2. Does the domain use a valid public suffix?
// See https://en.wikipedia.org/wiki/Public_Suffix_List
$publicSuffixList = $this->publicSuffixListClient->get(self::PUBLIC_SUFFIX_LIST_URI);
$domainName = explode('@', $value)[1];
// If the domain is actually a public suffix (like @notaires.fr) then there is no suffix
// So we add the "sub." prefix to ensure the method ->suffix() will always return a non-empty dto
$result = $publicSuffixList->resolve(Domain::fromIDNA2008('sub.' . $domainName));
if (!$result->suffix()->isKnown()) {
$this->context->buildViolation($constraint->tldMessage)
->setParameter('{{ domain }}', $this->formatValue($domainName))
->setParameter('{{ value }}', $this->formatValue($value))
->setCode(Email::INVALID_TLD_ERROR)
->addViolation();
return;
}
// 3. DNS check
$validator = new \Egulias\EmailValidator\EmailValidator();
if ($constraint->checkDNS && !$validator->isValid($value, new DNSCheckValidation())) {
$this->context->buildViolation($constraint->dnsMessage)
->setParameter('{{ domain }}', $this->formatValue($domainName))
->setParameter('{{ value }}', $this->formatValue($value))
->setCode(Email::INVALID_DNS_ERROR)
->addViolation();
return;
}
parent::validate($value, $constraint);
}
}