Subversion-Projekte lars-tiefland.laravel_shop

Revision

Revision 148 | Details | Vergleich mit vorheriger | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
150 lars 2
 
148 lars 3
namespace Egulias\EmailValidator\Parser;
4
 
5
use Egulias\EmailValidator\EmailLexer;
6
use Egulias\EmailValidator\Result\Result;
7
use Egulias\EmailValidator\Result\ValidEmail;
8
use Egulias\EmailValidator\Result\InvalidEmail;
9
use Egulias\EmailValidator\Warning\CFWSWithFWS;
10
use Egulias\EmailValidator\Warning\IPV6BadChar;
11
use Egulias\EmailValidator\Result\Reason\CRNoLF;
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
use Egulias\EmailValidator\Result\Reason\ExpectingDTEXT;
21
use Egulias\EmailValidator\Result\Reason\UnusualElements;
22
use Egulias\EmailValidator\Warning\DomainLiteral as WarningDomainLiteral;
23
 
24
class DomainLiteral extends PartParser
25
{
26
    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]?)$/';
27
 
28
    public const OBSOLETE_WARNINGS = [
29
        EmailLexer::INVALID,
30
        EmailLexer::C_DEL,
31
        EmailLexer::S_LF,
32
        EmailLexer::S_BACKSLASH
33
    ];
34
 
150 lars 35
    public function parse(): Result
148 lars 36
    {
37
        $this->addTagWarnings();
38
 
39
        $IPv6TAG = false;
40
        $addressLiteral = '';
41
 
42
        do {
150 lars 43
            if ($this->lexer->current->isA(EmailLexer::C_NUL)) {
44
                return new InvalidEmail(new ExpectingDTEXT(), $this->lexer->current->value);
148 lars 45
            }
46
 
47
            $this->addObsoleteWarnings();
48
 
49
            if ($this->lexer->isNextTokenAny(array(EmailLexer::S_OPENBRACKET, EmailLexer::S_OPENBRACKET))) {
150 lars 50
                return new InvalidEmail(new ExpectingDTEXT(), $this->lexer->current->value);
148 lars 51
            }
52
 
53
            if ($this->lexer->isNextTokenAny(
54
                array(EmailLexer::S_HTAB, EmailLexer::S_SP, EmailLexer::CRLF)
55
            )) {
56
                $this->warnings[CFWSWithFWS::CODE] = new CFWSWithFWS();
57
                $this->parseFWS();
58
            }
59
 
60
            if ($this->lexer->isNextToken(EmailLexer::S_CR)) {
150 lars 61
                return new InvalidEmail(new CRNoLF(), $this->lexer->current->value);
148 lars 62
            }
63
 
150 lars 64
            if ($this->lexer->current->isA(EmailLexer::S_BACKSLASH)) {
65
                return new InvalidEmail(new UnusualElements($this->lexer->current->value), $this->lexer->current->value);
148 lars 66
            }
150 lars 67
            if ($this->lexer->current->isA(EmailLexer::S_IPV6TAG)) {
148 lars 68
                $IPv6TAG = true;
69
            }
70
 
150 lars 71
            if ($this->lexer->current->isA(EmailLexer::S_CLOSEBRACKET)) {
148 lars 72
                break;
73
            }
74
 
150 lars 75
            $addressLiteral .= $this->lexer->current->value;
148 lars 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
     */
150 lars 105
    public function checkIPV6Tag($addressLiteral, $maxGroups = 8): void
148 lars 106
    {
107
        $prev = $this->lexer->getPrevious();
150 lars 108
        if ($prev->isA(EmailLexer::S_COLON)) {
148 lars 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
    }
150 lars 147
 
148
    public function convertIPv4ToIPv6(string $addressLiteralIPv4): string
148 lars 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
     */
150 lars 171
    protected function checkIPV4Tag($addressLiteral): bool
148 lars 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
 
150 lars 190
    private function addObsoleteWarnings(): void
148 lars 191
    {
150 lars 192
        if (in_array($this->lexer->current->type, self::OBSOLETE_WARNINGS)) {
148 lars 193
            $this->warnings[ObsoleteDTEXT::CODE] = new ObsoleteDTEXT();
194
        }
195
    }
196
 
150 lars 197
    private function addTagWarnings(): void
148 lars 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
}