These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace Egulias\EmailValidator\Parser; |
||
4 | |||
5 | use Egulias\EmailValidator\EmailLexer; |
||
6 | use Egulias\EmailValidator\Exception\AtextAfterCFWS; |
||
7 | use Egulias\EmailValidator\Exception\ConsecutiveDot; |
||
8 | use Egulias\EmailValidator\Exception\CRLFAtTheEnd; |
||
9 | use Egulias\EmailValidator\Exception\CRLFX2; |
||
10 | use Egulias\EmailValidator\Exception\CRNoLF; |
||
11 | use Egulias\EmailValidator\Exception\ExpectingQPair; |
||
12 | use Egulias\EmailValidator\Exception\ExpectingATEXT; |
||
13 | use Egulias\EmailValidator\Exception\ExpectingCTEXT; |
||
14 | use Egulias\EmailValidator\Exception\UnclosedComment; |
||
15 | use Egulias\EmailValidator\Exception\UnclosedQuotedString; |
||
16 | use Egulias\EmailValidator\Warning\CFWSNearAt; |
||
17 | use Egulias\EmailValidator\Warning\CFWSWithFWS; |
||
18 | use Egulias\EmailValidator\Warning\Comment; |
||
19 | use Egulias\EmailValidator\Warning\QuotedPart; |
||
20 | use Egulias\EmailValidator\Warning\QuotedString; |
||
21 | |||
22 | abstract class Parser |
||
23 | { |
||
24 | /** |
||
25 | * @var \Egulias\EmailValidator\Warning\Warning[] |
||
26 | */ |
||
27 | protected $warnings = []; |
||
28 | |||
29 | /** |
||
30 | * @var EmailLexer |
||
31 | */ |
||
32 | protected $lexer; |
||
33 | |||
34 | /** |
||
35 | * @var int |
||
36 | */ |
||
37 | protected $openedParenthesis = 0; |
||
38 | |||
39 | 130 | public function __construct(EmailLexer $lexer) |
|
40 | { |
||
41 | 130 | $this->lexer = $lexer; |
|
42 | 130 | } |
|
43 | |||
44 | /** |
||
45 | * @return \Egulias\EmailValidator\Warning\Warning[] |
||
46 | */ |
||
47 | 52 | public function getWarnings() |
|
48 | { |
||
49 | 52 | return $this->warnings; |
|
50 | } |
||
51 | |||
52 | /** |
||
53 | * @param string $str |
||
54 | */ |
||
55 | abstract public function parse($str); |
||
56 | |||
57 | /** @return int */ |
||
58 | 6 | public function getOpenedParenthesis() |
|
59 | { |
||
60 | 6 | return $this->openedParenthesis; |
|
61 | } |
||
62 | |||
63 | /** |
||
64 | * validateQuotedPair |
||
65 | */ |
||
66 | protected function validateQuotedPair() |
||
67 | { |
||
68 | View Code Duplication | if (!($this->lexer->token['type'] === EmailLexer::INVALID |
|
69 | || $this->lexer->token['type'] === EmailLexer::C_DEL)) { |
||
70 | throw new ExpectingQPair(); |
||
71 | } |
||
72 | |||
73 | $this->warnings[QuotedPart::CODE] = |
||
74 | new QuotedPart($this->lexer->getPrevious()['type'], $this->lexer->token['type']); |
||
75 | } |
||
76 | |||
77 | 10 | protected function parseComments() |
|
78 | { |
||
79 | 10 | $this->openedParenthesis = 1; |
|
80 | 10 | $this->isUnclosedComment(); |
|
81 | 6 | $this->warnings[Comment::CODE] = new Comment(); |
|
82 | 6 | while (!$this->lexer->isNextToken(EmailLexer::S_CLOSEPARENTHESIS)) { |
|
83 | 6 | if ($this->lexer->isNextToken(EmailLexer::S_OPENPARENTHESIS)) { |
|
84 | 1 | $this->openedParenthesis++; |
|
85 | 1 | } |
|
86 | 6 | $this->warnEscaping(); |
|
87 | 6 | $this->lexer->moveNext(); |
|
88 | 6 | } |
|
89 | |||
90 | 6 | $this->lexer->moveNext(); |
|
91 | 6 | if ($this->lexer->isNextTokenAny(array(EmailLexer::GENERIC, EmailLexer::S_EMPTY))) { |
|
92 | throw new ExpectingATEXT(); |
||
93 | } |
||
94 | |||
95 | 6 | if ($this->lexer->isNextToken(EmailLexer::S_AT)) { |
|
96 | 1 | $this->warnings[CFWSNearAt::CODE] = new CFWSNearAt(); |
|
97 | 1 | } |
|
98 | 6 | } |
|
99 | |||
100 | /** |
||
101 | * @return bool |
||
102 | */ |
||
103 | 13 | protected function isUnclosedComment() |
|
104 | { |
||
105 | try { |
||
106 | 13 | $this->lexer->find(EmailLexer::S_CLOSEPARENTHESIS); |
|
107 | 7 | return true; |
|
108 | 6 | } catch (\RuntimeException $e) { |
|
109 | 6 | throw new UnclosedComment(); |
|
110 | } |
||
111 | } |
||
112 | |||
113 | 16 | protected function parseFWS() |
|
114 | { |
||
115 | 16 | $previous = $this->lexer->getPrevious(); |
|
116 | |||
117 | 16 | $this->checkCRLFInFWS(); |
|
118 | |||
119 | 16 | if ($this->lexer->token['type'] === EmailLexer::S_CR) { |
|
120 | 2 | throw new CRNoLF(); |
|
121 | } |
||
122 | |||
123 | 14 | View Code Duplication | if ($this->lexer->isNextToken(EmailLexer::GENERIC) && $previous['type'] !== EmailLexer::S_AT) { |
0 ignored issues
–
show
|
|||
124 | 7 | throw new AtextAfterCFWS(); |
|
125 | } |
||
126 | |||
127 | 10 | View Code Duplication | if ($this->lexer->token['type'] === EmailLexer::S_LF || $this->lexer->token['type'] === EmailLexer::C_NUL) { |
128 | throw new ExpectingCTEXT(); |
||
129 | } |
||
130 | |||
131 | 10 | if ($this->lexer->isNextToken(EmailLexer::S_AT) || $previous['type'] === EmailLexer::S_AT) { |
|
132 | 3 | $this->warnings[CFWSNearAt::CODE] = new CFWSNearAt(); |
|
133 | 3 | } else { |
|
134 | 8 | $this->warnings[CFWSWithFWS::CODE] = new CFWSWithFWS(); |
|
135 | } |
||
136 | 10 | } |
|
137 | |||
138 | 115 | protected function checkConsecutiveDots() |
|
139 | { |
||
140 | 115 | View Code Duplication | if ($this->lexer->token['type'] === EmailLexer::S_DOT && $this->lexer->isNextToken(EmailLexer::S_DOT)) { |
141 | 3 | throw new ConsecutiveDot(); |
|
142 | } |
||
143 | 115 | } |
|
144 | |||
145 | /** |
||
146 | * @return bool |
||
147 | */ |
||
148 | 109 | protected function isFWS() |
|
149 | { |
||
150 | 109 | if ($this->escaped()) { |
|
151 | 1 | return false; |
|
152 | } |
||
153 | |||
154 | 109 | if ($this->lexer->token['type'] === EmailLexer::S_SP || |
|
155 | 109 | $this->lexer->token['type'] === EmailLexer::S_HTAB || |
|
156 | 109 | $this->lexer->token['type'] === EmailLexer::S_CR || |
|
157 | 109 | $this->lexer->token['type'] === EmailLexer::S_LF || |
|
158 | 109 | $this->lexer->token['type'] === EmailLexer::CRLF |
|
159 | 109 | ) { |
|
160 | 16 | return true; |
|
161 | } |
||
162 | |||
163 | 109 | return false; |
|
164 | } |
||
165 | |||
166 | /** |
||
167 | * @return bool |
||
168 | */ |
||
169 | 116 | protected function escaped() |
|
170 | { |
||
171 | 116 | $previous = $this->lexer->getPrevious(); |
|
172 | |||
173 | 116 | if ($previous['type'] === EmailLexer::S_BACKSLASH |
|
174 | 116 | && |
|
175 | 3 | $this->lexer->token['type'] !== EmailLexer::GENERIC |
|
176 | 116 | ) { |
|
177 | 2 | return true; |
|
178 | } |
||
179 | |||
180 | 116 | return false; |
|
181 | } |
||
182 | |||
183 | /** |
||
184 | * @return bool |
||
185 | */ |
||
186 | 115 | protected function warnEscaping() |
|
187 | { |
||
188 | 115 | if ($this->lexer->token['type'] !== EmailLexer::S_BACKSLASH) { |
|
189 | 110 | return false; |
|
190 | } |
||
191 | |||
192 | 7 | if ($this->lexer->isNextToken(EmailLexer::GENERIC)) { |
|
193 | 6 | throw new ExpectingATEXT(); |
|
194 | } |
||
195 | |||
196 | 1 | if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB, EmailLexer::C_DEL))) { |
|
197 | return false; |
||
198 | } |
||
199 | |||
200 | 1 | $this->warnings[QuotedPart::CODE] = |
|
201 | 1 | new QuotedPart($this->lexer->getPrevious()['type'], $this->lexer->token['type']); |
|
202 | 1 | return true; |
|
203 | |||
204 | } |
||
205 | |||
206 | /** |
||
207 | * @param bool $hasClosingQuote |
||
208 | * |
||
209 | * @return bool |
||
210 | */ |
||
211 | 127 | protected function checkDQUOTE($hasClosingQuote) |
|
212 | { |
||
213 | 127 | if ($this->lexer->token['type'] !== EmailLexer::S_DQUOTE) { |
|
214 | 106 | return $hasClosingQuote; |
|
215 | } |
||
216 | 22 | if ($hasClosingQuote) { |
|
217 | return $hasClosingQuote; |
||
218 | } |
||
219 | 22 | $previous = $this->lexer->getPrevious(); |
|
220 | 22 | View Code Duplication | if ($this->lexer->isNextToken(EmailLexer::GENERIC) && $previous['type'] === EmailLexer::GENERIC) { |
221 | 1 | throw new ExpectingATEXT(); |
|
222 | } |
||
223 | |||
224 | try { |
||
225 | 21 | $this->lexer->find(EmailLexer::S_DQUOTE); |
|
226 | 20 | $hasClosingQuote = true; |
|
227 | 21 | } catch (\Exception $e) { |
|
228 | 1 | throw new UnclosedQuotedString(); |
|
229 | } |
||
230 | 20 | $this->warnings[QuotedString::CODE] = new QuotedString($previous['value'], $this->lexer->token['value']); |
|
231 | |||
232 | 20 | return $hasClosingQuote; |
|
233 | } |
||
234 | |||
235 | 16 | protected function checkCRLFInFWS() |
|
236 | { |
||
237 | 16 | if ($this->lexer->token['type'] !== EmailLexer::CRLF) { |
|
238 | 16 | return; |
|
239 | } |
||
240 | |||
241 | if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB))) { |
||
242 | throw new CRLFX2(); |
||
243 | } |
||
244 | |||
245 | if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB))) { |
||
246 | throw new CRLFAtTheEnd(); |
||
247 | } |
||
248 | } |
||
249 | } |
||
250 |
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.