EmailValidator::validate()   B
last analyzed

Complexity

Conditions 9
Paths 9

Size

Total Lines 28
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 20
c 1
b 0
f 0
dl 0
loc 28
rs 8.0555
cc 9
nc 9
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace EmailValidator;
6
7
use EmailValidator\Validator\AValidator;
8
use EmailValidator\Validator\BannedListValidator;
9
use EmailValidator\Validator\BasicValidator;
10
use EmailValidator\Validator\DisposableEmailValidator;
11
use EmailValidator\Validator\FreeEmailValidator;
12
use EmailValidator\Validator\GmailValidator;
13
use EmailValidator\Validator\MxValidator;
14
use EmailValidator\Validator\Rfc5322Validator;
15
16
class EmailValidator
17
{
18
    public const NO_ERROR = 0;
19
20
    public const FAIL_BASIC = 1;
21
22
    public const FAIL_MX_RECORD = 2;
23
24
    public const FAIL_BANNED_DOMAIN = 3;
25
26
    public const FAIL_DISPOSABLE_DOMAIN = 4;
27
28
    public const FAIL_FREE_PROVIDER = 5;
29
30
    public const FAIL_CUSTOM = 6;
31
32
    public const FAIL_RFC5322 = 7;
33
34
    /**
35
     * @var BasicValidator
36
     */
37
    private BasicValidator $basicValidator;
38
39
    /**
40
     * @var Rfc5322Validator
41
     */
42
    private Rfc5322Validator $rfc5322Validator;
43
44
    /**
45
     * @var MxValidator
46
     */
47
    private MxValidator $mxValidator;
48
49
    /**
50
     * @var BannedListValidator
51
     */
52
    private BannedListValidator $bannedListValidator;
53
54
    /**
55
     * @var DisposableEmailValidator
56
     */
57
    private DisposableEmailValidator $disposableEmailValidator;
58
59
    /**
60
     * @var FreeEmailValidator
61
     */
62
    private FreeEmailValidator $freeEmailValidator;
63
64
    /**
65
     * @var GmailValidator
66
     */
67
    private GmailValidator $gmailValidator;
68
69
    /**
70
     * @var array<AValidator>
71
     * @since 2.0.0
72
     */
73
    private array $customValidators = [];
74
75
    /**
76
     * @var int
77
     */
78
    private int $reason;
79
80
    /**
81
     * @var EmailAddress|null
82
     * @since 1.1.0
83
     */
84
    private ?EmailAddress $emailAddress = null;
85
86
    public function __construct(array $config = [])
87
    {
88
        $this->reason = self::NO_ERROR;
89
90
        $policy = new Policy($config);
91
92
        $this->mxValidator = new MxValidator($policy);
93
        $this->basicValidator = new BasicValidator($policy);
94
        $this->rfc5322Validator = new Rfc5322Validator($policy);
0 ignored issues
show
Unused Code introduced by
The call to EmailValidator\Validator...alidator::__construct() has too many arguments starting with $policy. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

94
        $this->rfc5322Validator = /** @scrutinizer ignore-call */ new Rfc5322Validator($policy);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
95
        $this->bannedListValidator = new BannedListValidator($policy);
96
        $this->disposableEmailValidator = new DisposableEmailValidator($policy);
97
        $this->freeEmailValidator = new FreeEmailValidator($policy);
98
        $this->gmailValidator = new GmailValidator($policy);
99
    }
100
101
    /**
102
     * Register a custom validator
103
     *
104
     * @param AValidator $validator
105
     * @return void
106
     * @since 2.0.0
107
     */
108
    public function registerValidator(AValidator $validator): void
109
    {
110
        $this->customValidators[] = $validator;
111
    }
112
113
    /**
114
     * Validate an email address by the rules set forth in the Policy
115
     *
116
     * @param string $email
117
     * @return bool
118
     */
119
    public function validate(string $email): bool
120
    {
121
        $this->resetErrorCode();
122
123
        $this->emailAddress = new EmailAddress($email);
124
125
        if (!$this->basicValidator->validate($this->emailAddress)) {
126
            $this->reason = self::FAIL_BASIC;
127
        } elseif (!$this->rfc5322Validator->validate($this->emailAddress)) {
128
            $this->reason = self::FAIL_RFC5322;
129
        } elseif (!$this->mxValidator->validate($this->emailAddress)) {
130
            $this->reason = self::FAIL_MX_RECORD;
131
        } elseif (!$this->bannedListValidator->validate($this->emailAddress)) {
132
            $this->reason = self::FAIL_BANNED_DOMAIN;
133
        } elseif (!$this->disposableEmailValidator->validate($this->emailAddress)) {
134
            $this->reason = self::FAIL_DISPOSABLE_DOMAIN;
135
        } elseif (!$this->freeEmailValidator->validate($this->emailAddress)) {
136
            $this->reason = self::FAIL_FREE_PROVIDER;
137
        } else {
138
            foreach ($this->customValidators as $validator) {
139
                if (!$validator->validate($this->emailAddress)) {
140
                    $this->reason = self::FAIL_CUSTOM;
141
                    break;
142
                }
143
            }
144
        }
145
146
        return $this->reason === self::NO_ERROR;
147
    }
148
149
    /**
150
     * Returns the error code constant value for invalid email addresses.
151
     *
152
     * For use by integrating systems to create their own error messages.
153
     *
154
     * @since 1.0.1
155
     * @return int
156
     */
157
    public function getErrorCode(): int
158
    {
159
        return $this->reason;
160
    }
161
162
    /**
163
     * Returns an error message for invalid email addresses
164
     *
165
     * @return string
166
     */
167
    public function getErrorReason(): string
168
    {
169
        switch ($this->reason) {
170
            case self::FAIL_BASIC:
171
                $msg = 'Invalid format';
172
                break;
173
            case self::FAIL_RFC5322:
174
                $msg = 'Does not comply with RFC 5322';
175
                break;
176
            case self::FAIL_MX_RECORD:
177
                $msg = 'Domain does not accept email';
178
                break;
179
            case self::FAIL_BANNED_DOMAIN:
180
                $msg = 'Domain is banned';
181
                break;
182
            case self::FAIL_DISPOSABLE_DOMAIN:
183
                $msg = 'Domain is used by disposable email providers';
184
                break;
185
            case self::FAIL_FREE_PROVIDER:
186
                $msg = 'Domain is used by free email providers';
187
                break;
188
            case self::FAIL_CUSTOM:
189
                $msg = 'Failed custom validation';
190
                break;
191
            case self::NO_ERROR:
192
            default:
193
                $msg = '';
194
        }
195
196
        return $msg;
197
    }
198
199
    /**
200
     * Resets the error code so each validation starts off defaulting to "valid"
201
     *
202
     * @since 1.0.2
203
     * @return void
204
     */
205
    private function resetErrorCode(): void
206
    {
207
        $this->reason = self::NO_ERROR;
208
    }
209
210
    /**
211
     * Determines if a gmail account is using the "plus trick".
212
     *
213
     * @codeCoverageIgnore
214
     * @since 1.1.0
215
     * @return bool
216
     */
217
    public function isGmailWithPlusChar(): bool
218
    {
219
        return $this->emailAddress !== null && $this->gmailValidator->isGmailWithPlusChar($this->emailAddress);
220
    }
221
222
    /**
223
     * Returns a gmail address with the "plus trick" portion of the email address.
224
     *
225
     * @codeCoverageIgnore
226
     * @since 1.1.0
227
     * @return string
228
     */
229
    public function getGmailAddressWithoutPlus(): string
230
    {
231
        if ($this->emailAddress === null) {
232
            return '';
233
        }
234
        return $this->gmailValidator->getGmailAddressWithoutPlus($this->emailAddress);
235
    }
236
237
    /**
238
     * Returns a sanitized gmail address (plus trick removed and dots removed).
239
     *
240
     * @codeCoverageIgnore
241
     * @since 1.1.4
242
     * @return string
243
     */
244
    public function getSanitizedGmailAddress(): string
245
    {
246
        if ($this->emailAddress === null) {
247
            return '';
248
        }
249
        return $this->gmailValidator->getSanitizedGmailAddress($this->emailAddress);
250
    }
251
}
252