Test Setup Failed
Push — parse-domain-literal ( 97f1d2 )
by Eduardo Gulias
01:49
created

DomainLiteral::parse()   C

Complexity

Conditions 11
Paths 52

Size

Total Lines 71

Duplication

Lines 9
Ratio 12.68 %

Importance

Changes 0
Metric Value
dl 9
loc 71
rs 6.486
c 0
b 0
f 0
cc 11
nc 52
nop 1

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
namespace Egulias\EmailValidator\Parser;
3
4
use Egulias\EmailValidator\EmailLexer;
5
use Egulias\EmailValidator\Result\Reason\CRNoLF;
6
use Egulias\EmailValidator\Result\Reason\ExpectingDTEXT;
7
use Egulias\EmailValidator\Result\ValidEmail;
8
use Egulias\EmailValidator\Result\InvalidEmail;
9
use Egulias\EmailValidator\Warning\DomainLiteral as WarningDomainLiteral;
10
use Egulias\EmailValidator\Warning\CFWSWithFWS;
11
use Egulias\EmailValidator\Warning\IPV6BadChar;
12
use Egulias\EmailValidator\Warning\IPV6ColonEnd;
13
use Egulias\EmailValidator\Warning\IPV6MaxGroups;
14
use Egulias\EmailValidator\Warning\ObsoleteDTEXT;
15
use Egulias\EmailValidator\Warning\AddressLiteral;
16
use Egulias\EmailValidator\Warning\IPV6ColonStart;
17
use Egulias\EmailValidator\Warning\IPV6Deprecated;
18
use Egulias\EmailValidator\Warning\IPV6GroupCount;
19
use Egulias\EmailValidator\Warning\IPV6DoubleColon;
20
21
class DomainLiteral extends Parser
22
{
23
    public function parse($remove)
24
    {
25
        $this->addTagWarnings();
26
27
        $IPv6TAG = false;
28
        $addressLiteral = '';
29
        do {
30 View Code Duplication
            if ($this->lexer->token['type'] === EmailLexer::C_NUL) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
31
                return new InvalidEmail(new ExpectingDTEXT(), $this->lexer->token['value']);
32
            }
33
34
            $this->addObsoleteWarnings();
35
36 View Code Duplication
            if ($this->lexer->isNextTokenAny(array(EmailLexer::S_OPENQBRACKET, EmailLexer::S_OPENBRACKET))) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
37
                return new InvalidEmail(new ExpectingDTEXT(), $this->lexer->token['value']);
38
            }
39
40
            if ($this->lexer->isNextTokenAny(
41
                array(EmailLexer::S_HTAB, EmailLexer::S_SP, $this->lexer->token['type'] === EmailLexer::CRLF)
42
            )) {
43
                $this->warnings[CFWSWithFWS::CODE] = new CFWSWithFWS();
44
                $this->parseFWS();
45
            }
46
47 View Code Duplication
            if ($this->lexer->isNextToken(EmailLexer::S_CR)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
48
                return new InvalidEmail(new CRNoLF(), $this->lexer->token['value']);
49
            }
50
51
            if ($this->lexer->token['type'] === EmailLexer::S_BACKSLASH) {
52
                $this->warnings[ObsoleteDTEXT::CODE] = new ObsoleteDTEXT();
53
                $addressLiteral .= $this->lexer->token['value'];
54
                $this->lexer->moveNext();
55
                $this->validateQuotedPair();
56
            }
57
            if ($this->lexer->token['type'] === EmailLexer::S_IPV6TAG) {
58
                $IPv6TAG = true;
59
            }
60
61
            if ($this->lexer->token['type'] === EmailLexer::S_CLOSEQBRACKET) {
62
                break;
63
            }
64
65
            $addressLiteral .= $this->lexer->token['value'];
66
67
        } while ($this->lexer->moveNext());
68
69
70
        //Encapsulate
71
        $addressLiteral = str_replace('[', '', $addressLiteral);
72
        $addressLiteralIPv4 = $this->checkIPV4Tag($addressLiteral);
73
74
        if ($addressLiteralIPv4 === $addressLiteral) {
75
            //return $addressLiteral;
76
            return new ValidEmail();
77
        }
78
79
        if (!$IPv6TAG) {
80
            $this->warnings[WarningDomainLiteral::CODE] = new WarningDomainLiteral();
81
            return new ValidEmail();
82
            //return $addressLiteral;
83
        }
84
85
        $this->warnings[AddressLiteral::CODE] = new AddressLiteral();
86
87
        $this->checkIPV6Tag($addressLiteralIPv4);
88
89
        //return $addressLiteralIPv4;
90
91
        return new ValidEmail();
92
93
    }
94
95
    /**
96
     * @param string $addressLiteral
97
     * @param int $maxGroups
98
     */
99
    public function checkIPV6Tag($addressLiteral, $maxGroups = 8)
100
    {
101
        $prev = $this->lexer->getPrevious();
102
        if ($prev['type'] === EmailLexer::S_COLON) {
103
            $this->warnings[IPV6ColonEnd::CODE] = new IPV6ColonEnd();
104
        }
105
106
        $IPv6       = substr($addressLiteral, 5);
107
        //Daniel Marschall's new IPv6 testing strategy
108
        $matchesIP  = explode(':', $IPv6);
109
        $groupCount = count($matchesIP);
110
        $colons     = strpos($IPv6, '::');
111
112
        if (count(preg_grep('/^[0-9A-Fa-f]{0,4}$/', $matchesIP, PREG_GREP_INVERT)) !== 0) {
113
            $this->warnings[IPV6BadChar::CODE] = new IPV6BadChar();
114
        }
115
116
        if ($colons === false) {
117
            // We need exactly the right number of groups
118
            if ($groupCount !== $maxGroups) {
119
                $this->warnings[IPV6GroupCount::CODE] = new IPV6GroupCount();
120
            }
121
            return;
122
        }
123
124
        if ($colons !== strrpos($IPv6, '::')) {
125
            $this->warnings[IPV6DoubleColon::CODE] = new IPV6DoubleColon();
126
            return;
127
        }
128
129
        if ($colons === 0 || $colons === (strlen($IPv6) - 2)) {
130
            // RFC 4291 allows :: at the start or end of an address
131
            //with 7 other groups in addition
132
            ++$maxGroups;
133
        }
134
135
        if ($groupCount > $maxGroups) {
136
            $this->warnings[IPV6MaxGroups::CODE] = new IPV6MaxGroups();
137
        } elseif ($groupCount === $maxGroups) {
138
            $this->warnings[IPV6Deprecated::CODE] = new IPV6Deprecated();
139
        }
140
    }
141
142
    /**
143
     * @param string $addressLiteral
144
     *
145
     * @return string
146
     */
147
    protected function checkIPV4Tag($addressLiteral) : string
148
    {
149
        $matchesIP  = array();
150
        $IPv4Match = preg_match(
151
            '/\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/',
152
            $addressLiteral,
153
            $matchesIP);
154
155
        // Extract IPv4 part from the end of the address-literal (if there is one)
156
157
        if ($IPv4Match > 0) {
158
            $index = strrpos($addressLiteral, $matchesIP[0]);
159
            //There's a match but it is at the start
160
            if ($index === 0) {
161
                $this->warnings[AddressLiteral::CODE] = new AddressLiteral();
162
                return $addressLiteral;
163
            }
164
            // Convert IPv4 part to IPv6 format for further testing
165
            $addressLiteral = substr($addressLiteral, 0, (int) $index) . '0:0';
166
        }
167
168
        return $addressLiteral;
169
    }
170
171
    private function addObsoleteWarnings()
172
    {
173
        if ($this->lexer->token['type'] === EmailLexer::INVALID ||
174
            $this->lexer->token['type'] === EmailLexer::C_DEL   ||
175
            $this->lexer->token['type'] === EmailLexer::S_LF
176
        ) {
177
            $this->warnings[ObsoleteDTEXT::CODE] = new ObsoleteDTEXT();
178
        }
179
    }
180
181
    private function addTagWarnings()
182
    {
183
        if ($this->lexer->isNextToken(EmailLexer::S_COLON)) {
184
            $this->warnings[IPV6ColonStart::CODE] = new IPV6ColonStart();
185
        }
186
        if ($this->lexer->isNextToken(EmailLexer::S_IPV6TAG)) {
187
            $lexer = clone $this->lexer;
188
            $lexer->moveNext();
189
            if ($lexer->isNextToken(EmailLexer::S_DOUBLECOLON)) {
190
                $this->warnings[IPV6ColonStart::CODE] = new IPV6ColonStart();
191
            }
192
        }
193
    }
194
195
}