Subversion-Projekte lars-tiefland.laravel_shop

Revision

Zur aktuellen Revision | Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
namespace Egulias\EmailValidator\Parser;
3
 
4
use Egulias\EmailValidator\EmailLexer;
5
use Egulias\EmailValidator\Result\Result;
6
use Egulias\EmailValidator\Result\ValidEmail;
7
use Egulias\EmailValidator\Result\InvalidEmail;
8
use Egulias\EmailValidator\Warning\CFWSWithFWS;
9
use Egulias\EmailValidator\Warning\IPV6BadChar;
10
use Egulias\EmailValidator\Result\Reason\CRNoLF;
11
use Egulias\EmailValidator\Warning\IPV6ColonEnd;
12
use Egulias\EmailValidator\Warning\IPV6MaxGroups;
13
use Egulias\EmailValidator\Warning\ObsoleteDTEXT;
14
use Egulias\EmailValidator\Warning\AddressLiteral;
15
use Egulias\EmailValidator\Warning\IPV6ColonStart;
16
use Egulias\EmailValidator\Warning\IPV6Deprecated;
17
use Egulias\EmailValidator\Warning\IPV6GroupCount;
18
use Egulias\EmailValidator\Warning\IPV6DoubleColon;
19
use Egulias\EmailValidator\Result\Reason\ExpectingDTEXT;
20
use Egulias\EmailValidator\Result\Reason\UnusualElements;
21
use Egulias\EmailValidator\Warning\DomainLiteral as WarningDomainLiteral;
22
 
23
class DomainLiteral extends PartParser
24
{
25
    public const IPV4_REGEX = '/\\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]?)$/';
26
 
27
    public const OBSOLETE_WARNINGS = [
28
        EmailLexer::INVALID,
29
        EmailLexer::C_DEL,
30
        EmailLexer::S_LF,
31
        EmailLexer::S_BACKSLASH
32
    ];
33
 
34
    public function parse() : Result
35
    {
36
        $this->addTagWarnings();
37
 
38
        $IPv6TAG = false;
39
        $addressLiteral = '';
40
 
41
        do {
42
            if ($this->lexer->token['type'] === EmailLexer::C_NUL) {
43
                return new InvalidEmail(new ExpectingDTEXT(), $this->lexer->token['value']);
44
            }
45
 
46
            $this->addObsoleteWarnings();
47
 
48
            if ($this->lexer->isNextTokenAny(array(EmailLexer::S_OPENBRACKET, EmailLexer::S_OPENBRACKET))) {
49
                return new InvalidEmail(new ExpectingDTEXT(), $this->lexer->token['value']);
50
            }
51
 
52
            if ($this->lexer->isNextTokenAny(
53
                array(EmailLexer::S_HTAB, EmailLexer::S_SP, EmailLexer::CRLF)
54
            )) {
55
                $this->warnings[CFWSWithFWS::CODE] = new CFWSWithFWS();
56
                $this->parseFWS();
57
            }
58
 
59
            if ($this->lexer->isNextToken(EmailLexer::S_CR)) {
60
                return new InvalidEmail(new CRNoLF(), $this->lexer->token['value']);
61
            }
62
 
63
            if ($this->lexer->token['type'] === EmailLexer::S_BACKSLASH) {
64
                return new InvalidEmail(new UnusualElements($this->lexer->token['value']), $this->lexer->token['value']);
65
            }
66
            if ($this->lexer->token['type'] === EmailLexer::S_IPV6TAG) {
67
                $IPv6TAG = true;
68
            }
69
 
70
            if ($this->lexer->token['type'] === EmailLexer::S_CLOSEBRACKET) {
71
                break;
72
            }
73
 
74
            $addressLiteral .= $this->lexer->token['value'];
75
 
76
        } while ($this->lexer->moveNext());
77
 
78
 
79
        //Encapsulate
80
        $addressLiteral = str_replace('[', '', $addressLiteral);
81
        $isAddressLiteralIPv4 = $this->checkIPV4Tag($addressLiteral);
82
 
83
        if (!$isAddressLiteralIPv4) {
84
            return new ValidEmail();
85
        } else {
86
            $addressLiteral = $this->convertIPv4ToIPv6($addressLiteral);
87
        }
88
 
89
        if (!$IPv6TAG) {
90
            $this->warnings[WarningDomainLiteral::CODE] = new WarningDomainLiteral();
91
            return new ValidEmail();
92
        }
93
 
94
        $this->warnings[AddressLiteral::CODE] = new AddressLiteral();
95
 
96
        $this->checkIPV6Tag($addressLiteral);
97
 
98
        return new ValidEmail();
99
    }
100
 
101
    /**
102
     * @param string $addressLiteral
103
     * @param int $maxGroups
104
     */
105
    public function checkIPV6Tag($addressLiteral, $maxGroups = 8) : void
106
    {
107
        $prev = $this->lexer->getPrevious();
108
        if ($prev['type'] === EmailLexer::S_COLON) {
109
            $this->warnings[IPV6ColonEnd::CODE] = new IPV6ColonEnd();
110
        }
111
 
112
        $IPv6       = substr($addressLiteral, 5);
113
        //Daniel Marschall's new IPv6 testing strategy
114
        $matchesIP  = explode(':', $IPv6);
115
        $groupCount = count($matchesIP);
116
        $colons     = strpos($IPv6, '::');
117
 
118
        if (count(preg_grep('/^[0-9A-Fa-f]{0,4}$/', $matchesIP, PREG_GREP_INVERT)) !== 0) {
119
            $this->warnings[IPV6BadChar::CODE] = new IPV6BadChar();
120
        }
121
 
122
        if ($colons === false) {
123
            // We need exactly the right number of groups
124
            if ($groupCount !== $maxGroups) {
125
                $this->warnings[IPV6GroupCount::CODE] = new IPV6GroupCount();
126
            }
127
            return;
128
        }
129
 
130
        if ($colons !== strrpos($IPv6, '::')) {
131
            $this->warnings[IPV6DoubleColon::CODE] = new IPV6DoubleColon();
132
            return;
133
        }
134
 
135
        if ($colons === 0 || $colons === (strlen($IPv6) - 2)) {
136
            // RFC 4291 allows :: at the start or end of an address
137
            //with 7 other groups in addition
138
            ++$maxGroups;
139
        }
140
 
141
        if ($groupCount > $maxGroups) {
142
            $this->warnings[IPV6MaxGroups::CODE] = new IPV6MaxGroups();
143
        } elseif ($groupCount === $maxGroups) {
144
            $this->warnings[IPV6Deprecated::CODE] = new IPV6Deprecated();
145
        }
146
    }
147
 
148
    public function convertIPv4ToIPv6(string $addressLiteralIPv4) : string
149
    {
150
        $matchesIP  = [];
151
        $IPv4Match = preg_match(self::IPV4_REGEX, $addressLiteralIPv4, $matchesIP);
152
 
153
        // Extract IPv4 part from the end of the address-literal (if there is one)
154
        if ($IPv4Match > 0) {
155
            $index = (int) strrpos($addressLiteralIPv4, $matchesIP[0]);
156
            //There's a match but it is at the start
157
            if ($index > 0) {
158
                // Convert IPv4 part to IPv6 format for further testing
159
                return substr($addressLiteralIPv4, 0, $index) . '0:0';
160
            }
161
        }
162
 
163
        return $addressLiteralIPv4;
164
    }
165
 
166
    /**
167
     * @param string $addressLiteral
168
     *
169
     * @return bool
170
     */
171
    protected function checkIPV4Tag($addressLiteral) : bool
172
    {
173
        $matchesIP  = [];
174
        $IPv4Match = preg_match(self::IPV4_REGEX, $addressLiteral, $matchesIP);
175
 
176
        // Extract IPv4 part from the end of the address-literal (if there is one)
177
 
178
        if ($IPv4Match > 0) {
179
            $index = strrpos($addressLiteral, $matchesIP[0]);
180
            //There's a match but it is at the start
181
            if ($index === 0) {
182
                $this->warnings[AddressLiteral::CODE] = new AddressLiteral();
183
                return false;
184
            }
185
        }
186
 
187
        return true;
188
    }
189
 
190
    private function addObsoleteWarnings() : void
191
    {
192
        if(in_array($this->lexer->token['type'], self::OBSOLETE_WARNINGS)) {
193
            $this->warnings[ObsoleteDTEXT::CODE] = new ObsoleteDTEXT();
194
        }
195
    }
196
 
197
    private function addTagWarnings() : void
198
    {
199
        if ($this->lexer->isNextToken(EmailLexer::S_COLON)) {
200
            $this->warnings[IPV6ColonStart::CODE] = new IPV6ColonStart();
201
        }
202
        if ($this->lexer->isNextToken(EmailLexer::S_IPV6TAG)) {
203
            $lexer = clone $this->lexer;
204
            $lexer->moveNext();
205
            if ($lexer->isNextToken(EmailLexer::S_DOUBLECOLON)) {
206
                $this->warnings[IPV6ColonStart::CODE] = new IPV6ColonStart();
207
            }
208
        }
209
    }
210
 
211
}