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

DomainLiteral   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 175
Duplicated Lines 5.14 %

Coupling/Cohesion

Components 1
Dependencies 17

Importance

Changes 0
Metric Value
wmc 32
lcom 1
cbo 17
dl 9
loc 175
rs 9.84
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
C parse() 9 71 11
B checkIPV6Tag() 0 42 10
A checkIPV4Tag() 0 23 3
A addObsoleteWarnings() 0 9 4
A addTagWarnings() 0 13 4

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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
}