EmailHandler   A
last analyzed

Complexity

Total Complexity 16

Size/Duplication

Total Lines 77
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 16
eloc 43
c 1
b 0
f 0
dl 0
loc 77
ccs 35
cts 35
cp 1
rs 10

1 Method

Rating   Name   Duplication   Size   Complexity  
C validate() 0 75 16
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Validator\Rule;
6
7
use Yiisoft\Validator\Exception\UnexpectedRuleException;
8
use Yiisoft\Validator\Result;
9
use Yiisoft\Validator\RuleHandlerInterface;
10
use Yiisoft\Validator\ValidationContext;
11
12
use function is_string;
13
use function strlen;
14
15
/**
16
 * Validates that the value is a valid email address.
17
 */
18
final class EmailHandler implements RuleHandlerInterface
19
{
20 100
    public function validate(mixed $value, object $rule, ValidationContext $context): Result
21
    {
22 100
        if (!$rule instanceof Email) {
23 1
            throw new UnexpectedRuleException(Email::class, $rule);
24
        }
25
26 99
        $result = new Result();
27 99
        if (!is_string($value)) {
28 5
            return $result->addError($rule->getIncorrectInputMessage(), [
29 5
                'attribute' => $context->getTranslatedAttribute(),
30 5
                'type' => get_debug_type($value),
31
            ]);
32
        }
33
34 94
        $originalValue = $value;
35
36 94
        if (!preg_match(
0 ignored issues
show
Coding Style introduced by
The first expression of a multi-line control structure must be on the line after the opening parenthesis
Loading history...
37
            '/^(?P<name>(?:"?([^"]*)"?\s)?)(?:\s+)?((?P<open><?)((?P<local>.+)@(?P<domain>[^>]+))(?P<close>>?))/',
38
            $value,
39
            $matches
40
        )) {
0 ignored issues
show
Coding Style introduced by
Each line in a multi-line control structure must be indented at least once; expected at least 12 spaces, but found 8
Loading history...
Coding Style introduced by
The closing parenthesis of a multi-line control structure must be on the line after the last expression
Loading history...
41 7
            $valid = false;
42
        } else {
43
            /** @var array{name:string,local:string,open:string,domain:string,close:string} $matches */
44 87
            if ($rule->isIdnEnabled()) {
45 28
                $matches['local'] = idn_to_ascii($matches['local']);
46 28
                $matches['domain'] = idn_to_ascii($matches['domain']);
47 28
                $value = implode('', [
48 28
                    $matches['name'],
49 28
                    $matches['open'],
50 28
                    $matches['local'],
51
                    '@',
52 28
                    $matches['domain'],
53 28
                    $matches['close'],
54
                ]);
55
            }
56
57 87
            if (is_string($matches['local']) && strlen($matches['local']) > 64) {
58
                // The maximum total length of a user name or other local-part is 64 octets. RFC 5322 section 4.5.3.1.1
59
                // https://www.rfc-editor.org/rfc/rfc5321#section-4.5.3.1.1
60 2
                $valid = false;
61
            } elseif (
62 85
                is_string($matches['local']) &&
63 85
                strlen($matches['local']) + strlen((string) $matches['domain']) > 253
64
            ) {
65
                // There is a restriction in RFC 2821 on the length of an address in MAIL and RCPT commands
66
                // of 254 characters. Since addresses that do not fit in those fields are not normally useful, the
67
                // upper limit on address lengths should normally be considered to be 254.
68
                //
69
                // Dominic Sayers, RFC 3696 erratum 1690
70
                // https://www.rfc-editor.org/errata_search.php?eid=1690
71 2
                $valid = false;
72
            } else {
73 83
                $valid = preg_match($rule->getPattern(), $value) || ($rule->isNameAllowed() && preg_match(
74 48
                    $rule->getFullPattern(),
75
                    $value
76
                ));
77 83
                if ($valid && $rule->shouldCheckDns()) {
78 8
                    $valid = checkdnsrr($matches['domain']);
79
                }
80
            }
81
        }
82
83 94
        if ($valid === false && $rule->isIdnEnabled()) {
84 10
            $valid = (bool) preg_match($rule->getIdnEmailPattern(), $originalValue);
85
        }
86
87 94
        if ($valid === false) {
88 49
            $result->addError($rule->getMessage(), [
89 49
                'attribute' => $context->getTranslatedAttribute(),
90
                'value' => $originalValue,
91
            ]);
92
        }
93
94 94
        return $result;
95
    }
96
}
97