Passed
Pull Request — master (#222)
by Alexander
04:47 queued 02:23
created

EmailValidator::validate()   C

Complexity

Conditions 16
Paths 96

Size

Total Lines 60
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 28
CRAP Score 16.0105

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 16
eloc 35
c 1
b 0
f 0
nc 96
nop 4
dl 0
loc 60
ccs 28
cts 29
cp 0.9655
crap 16.0105
rs 5.5666

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Validator\Rule\Email;
6
7
use Yiisoft\Validator\Result;
8
use Yiisoft\Validator\Rule\RuleValidatorInterface;
9
use Yiisoft\Validator\ValidationContext;
10
use Yiisoft\Validator\ValidatorInterface;
11
use function is_string;
12
use function strlen;
13
14
/**
15
 * Validates that the value is a valid email address.
16
 */
17
final class EmailValidator implements RuleValidatorInterface
18
{
19 83
    public function validate(mixed $value, object $rule, ValidatorInterface $validator, ?ValidationContext $context = null): Result
20
    {
21 83
        $originalValue = $value;
22 83
        $result = new Result();
23
24 83
        if (!is_string($value)) {
25 3
            $valid = false;
26 80
        } elseif (!preg_match(
27
            '/^(?P<name>(?:"?([^"]*)"?\s)?)(?:\s+)?((?P<open><?)((?P<local>.+)@(?P<domain>[^>]+))(?P<close>>?))$/i',
28
            $value,
29
            $matches
30
        )) {
31 6
            $valid = false;
32
        } else {
33
            /** @psalm-var array{name:string,local:string,open:string,domain:string,close:string} $matches */
34 74
            if ($rule->enableIDN) {
35 27
                $matches['local'] = $this->idnToAscii($matches['local']);
36 27
                $matches['domain'] = $this->idnToAscii($matches['domain']);
37 27
                $value = implode([
38 27
                    $matches['name'],
39 27
                    $matches['open'],
40 27
                    $matches['local'],
41
                    '@',
42 27
                    $matches['domain'],
43 27
                    $matches['close'],
44
                ]);
45
            }
46
47 74
            if (is_string($matches['local']) && strlen($matches['local']) > 64) {
48
                // The maximum total length of a user name or other local-part is 64 octets. RFC 5322 section 4.5.3.1.1
49
                // http://tools.ietf.org/html/rfc5321#section-4.5.3.1.1
50 1
                $valid = false;
51 73
            } elseif (is_string($matches['local']) && strlen($matches['local'] . '@' . $matches['domain']) > 254) {
52
                // There is a restriction in RFC 2821 on the length of an address in MAIL and RCPT commands
53
                // of 254 characters. Since addresses that do not fit in those fields are not normally useful, the
54
                // upper limit on address lengths should normally be considered to be 254.
55
                //
56
                // Dominic Sayers, RFC 3696 erratum 1690
57
                // http://www.rfc-editor.org/errata_search.php?eid=1690
58
                $valid = false;
59
            } else {
60 73
                $valid = preg_match($rule->pattern, $value) || ($rule->allowName && preg_match(
61 47
                    $rule->fullPattern,
62
                    $value
63
                ));
64 73
                if ($valid && $rule->checkDNS) {
65 5
                    $valid = checkdnsrr($matches['domain'] . '.', 'MX') || checkdnsrr($matches['domain'] . '.', 'A');
66
                }
67
            }
68
        }
69
70 83
        if ($rule->enableIDN && $valid === false) {
71 10
            $valid = (bool) preg_match($rule->idnEmailPattern, $originalValue);
72
        }
73
74 83
        if ($valid === false) {
75 45
            $result->addError($rule->message);
76
        }
77
78 83
        return $result;
79
    }
80
81 27
    private function idnToAscii($idn)
82
    {
83 27
        return idn_to_ascii($idn, 0, INTL_IDNA_VARIANT_UTS46);
84
    }
85
}
86