1 | <?php |
||||||
2 | /** |
||||||
3 | * SPDX-License-Identifier: BSD-3-Clause. |
||||||
4 | * |
||||||
5 | * RFC 822 Email address list validation Utility |
||||||
6 | * |
||||||
7 | * PHP version 5 |
||||||
8 | * |
||||||
9 | * LICENSE: |
||||||
10 | * |
||||||
11 | * Copyright (c) 2001-2017, Chuck Hagenbuch & Richard Heyes |
||||||
12 | * All rights reserved. |
||||||
13 | * |
||||||
14 | * Redistribution and use in source and binary forms, with or without |
||||||
15 | * modification, are permitted provided that the following conditions |
||||||
16 | * are met: |
||||||
17 | * |
||||||
18 | * 1. Redistributions of source code must retain the above copyright |
||||||
19 | * notice, this list of conditions and the following disclaimer. |
||||||
20 | * |
||||||
21 | * 2. Redistributions in binary form must reproduce the above copyright |
||||||
22 | * notice, this list of conditions and the following disclaimer in the |
||||||
23 | * documentation and/or other materials provided with the distribution. |
||||||
24 | * |
||||||
25 | * 3. Neither the name of the copyright holder nor the names of its |
||||||
26 | * contributors may be used to endorse or promote products derived from |
||||||
27 | * this software without specific prior written permission. |
||||||
28 | * |
||||||
29 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
30 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||||
31 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||||
32 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||||
33 | * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||||
34 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||||
35 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||||
36 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||||
37 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||||
38 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||||
39 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
40 | * |
||||||
41 | * @category Mail |
||||||
42 | * |
||||||
43 | * @author Richard Heyes <[email protected]> |
||||||
44 | * @author Chuck Hagenbuch <[email protected] |
||||||
45 | * @copyright 2001-2017 Richard Heyes |
||||||
46 | * @license http://opensource.org/licenses/BSD-3-Clause New BSD License |
||||||
47 | * |
||||||
48 | * @version CVS: $Id$ |
||||||
49 | * |
||||||
50 | * @see http://pear.php.net/package/Mail/ |
||||||
51 | */ |
||||||
52 | |||||||
53 | /** |
||||||
54 | * RFC 822 Email address list validation Utility. |
||||||
55 | * |
||||||
56 | * What is it? |
||||||
57 | * |
||||||
58 | * This class will take an address string, and parse it into it's constituent |
||||||
59 | * parts, be that either addresses, groups, or combinations. Nested groups |
||||||
60 | * are not supported. The structure it returns is pretty straight forward, |
||||||
61 | * and is similar to that provided by the imap_rfc822_parse_adrlist(). Use |
||||||
62 | * print_r() to view the structure. |
||||||
63 | * |
||||||
64 | * How do I use it? |
||||||
65 | * |
||||||
66 | * $address_string = 'My Group: "Richard" <richard@localhost> (A comment), [email protected] (Ted Bloggs), Barney;'; |
||||||
67 | * $structure = Mail_RFC822::parseAddressList($address_string, 'example.com', true) |
||||||
68 | * print_r($structure); |
||||||
69 | * |
||||||
70 | * @author Richard Heyes <[email protected]> |
||||||
71 | * @author Chuck Hagenbuch <[email protected]> |
||||||
72 | * |
||||||
73 | * @version $Revision$ |
||||||
74 | * |
||||||
75 | * @license BSD |
||||||
76 | */ |
||||||
77 | class Mail_RFC822 { |
||||||
78 | /** |
||||||
79 | * The address being parsed by the RFC822 object. |
||||||
80 | * |
||||||
81 | * @var string |
||||||
82 | */ |
||||||
83 | public $address = ''; |
||||||
84 | |||||||
85 | /** |
||||||
86 | * The default domain to use for unqualified addresses. |
||||||
87 | * |
||||||
88 | * @var string |
||||||
89 | */ |
||||||
90 | public $default_domain = 'localhost'; |
||||||
91 | |||||||
92 | /** |
||||||
93 | * Should we return a nested array showing groups, or flatten everything? |
||||||
94 | * |
||||||
95 | * @var bool |
||||||
96 | */ |
||||||
97 | public $nestGroups = true; |
||||||
98 | |||||||
99 | /** |
||||||
100 | * Whether or not to validate atoms for non-ascii characters. |
||||||
101 | * |
||||||
102 | * @var bool |
||||||
103 | */ |
||||||
104 | public $validate = true; |
||||||
105 | |||||||
106 | /** |
||||||
107 | * The array of raw addresses built up as we parse. |
||||||
108 | * |
||||||
109 | * @var array |
||||||
110 | */ |
||||||
111 | public $addresses = []; |
||||||
112 | |||||||
113 | /** |
||||||
114 | * The final array of parsed address information that we build up. |
||||||
115 | * |
||||||
116 | * @var array |
||||||
117 | */ |
||||||
118 | public $structure = []; |
||||||
119 | |||||||
120 | /** |
||||||
121 | * The current error message, if any. |
||||||
122 | * |
||||||
123 | * @var string |
||||||
124 | */ |
||||||
125 | public $error; |
||||||
126 | |||||||
127 | /** |
||||||
128 | * An internal counter/pointer. |
||||||
129 | * |
||||||
130 | * @var int |
||||||
131 | */ |
||||||
132 | public $index; |
||||||
133 | |||||||
134 | /** |
||||||
135 | * The number of groups that have been found in the address list. |
||||||
136 | * |
||||||
137 | * @var int |
||||||
138 | */ |
||||||
139 | public $num_groups = 0; |
||||||
140 | |||||||
141 | /** |
||||||
142 | * A variable so that we can tell whether or not we're inside a |
||||||
143 | * Mail_RFC822 object. |
||||||
144 | * |
||||||
145 | * @var bool |
||||||
146 | */ |
||||||
147 | public $mailRFC822 = true; |
||||||
148 | |||||||
149 | /** |
||||||
150 | * A limit after which processing stops. |
||||||
151 | * |
||||||
152 | * @var int |
||||||
153 | */ |
||||||
154 | public $limit; |
||||||
155 | |||||||
156 | /** |
||||||
157 | * Sets up the object. The address must either be set here or when |
||||||
158 | * calling parseAddressList(). One or the other. |
||||||
159 | * |
||||||
160 | * @param string $address the address(es) to validate |
||||||
161 | * @param string $default_domain Default domain/host etc. If not supplied, will be set to localhost. |
||||||
162 | * @param bool $nest_groups whether to return the structure with groups nested for easier viewing |
||||||
163 | * @param bool $validate Whether to validate atoms. Turn this off if you need to run addresses through before encoding the personal names, for instance. |
||||||
164 | * @param null|mixed $limit |
||||||
165 | * |
||||||
166 | * @return object mail_RFC822 A new Mail_RFC822 object |
||||||
167 | */ |
||||||
168 | public function __construct($address = null, $default_domain = null, $nest_groups = null, $validate = null, $limit = null) { |
||||||
169 | if (isset($address)) { |
||||||
170 | $this->address = $address; |
||||||
171 | } |
||||||
172 | if (isset($default_domain)) { |
||||||
173 | $this->default_domain = $default_domain; |
||||||
174 | } |
||||||
175 | if (isset($nest_groups)) { |
||||||
176 | $this->nestGroups = $nest_groups; |
||||||
177 | } |
||||||
178 | if (isset($validate)) { |
||||||
179 | $this->validate = $validate; |
||||||
180 | } |
||||||
181 | if (isset($limit)) { |
||||||
182 | $this->limit = $limit; |
||||||
183 | } |
||||||
184 | } |
||||||
185 | |||||||
186 | /** |
||||||
187 | * Starts the whole process. The address must either be set here |
||||||
188 | * or when creating the object. One or the other. |
||||||
189 | * |
||||||
190 | * @param string $address the address(es) to validate |
||||||
191 | * @param string $default_domain default domain/host etc |
||||||
192 | * @param bool $nest_groups whether to return the structure with groups nested for easier viewing |
||||||
193 | * @param bool $validate Whether to validate atoms. Turn this off if you need to run addresses through before encoding the personal names, for instance. |
||||||
194 | * @param null|mixed $limit |
||||||
195 | * |
||||||
196 | * @return array a structured array of addresses |
||||||
197 | */ |
||||||
198 | public function parseAddressList($address = null, $default_domain = null, $nest_groups = null, $validate = null, $limit = null) { |
||||||
199 | if (!isset($this) || !isset($this->mailRFC822)) { |
||||||
200 | $obj = new Mail_RFC822($address, $default_domain, $nest_groups, $validate, $limit); |
||||||
201 | |||||||
202 | return $obj->parseAddressList(); |
||||||
203 | } |
||||||
204 | |||||||
205 | if (isset($address)) { |
||||||
206 | $this->address = $address; |
||||||
207 | } |
||||||
208 | // grommunio-sync addition |
||||||
209 | if (strlen(trim($this->address)) == 0) { |
||||||
210 | return []; |
||||||
211 | } |
||||||
212 | if (isset($default_domain)) { |
||||||
213 | $this->default_domain = $default_domain; |
||||||
214 | } |
||||||
215 | if (isset($nest_groups)) { |
||||||
216 | $this->nestGroups = $nest_groups; |
||||||
217 | } |
||||||
218 | if (isset($validate)) { |
||||||
219 | $this->validate = $validate; |
||||||
220 | } |
||||||
221 | if (isset($limit)) { |
||||||
222 | $this->limit = $limit; |
||||||
223 | } |
||||||
224 | |||||||
225 | $this->structure = []; |
||||||
226 | $this->addresses = []; |
||||||
227 | $this->error = null; |
||||||
228 | $this->index = null; |
||||||
229 | |||||||
230 | // Unfold any long lines in $this->address. |
||||||
231 | $this->address = preg_replace('/\r?\n/', "\r\n", $this->address); |
||||||
232 | $this->address = preg_replace('/\r\n(\t| )+/', ' ', $this->address); |
||||||
233 | |||||||
234 | while ($this->address = $this->_splitAddresses($this->address)); |
||||||
0 ignored issues
–
show
|
|||||||
235 | |||||||
236 | if ($this->address === false || isset($this->error)) { |
||||||
0 ignored issues
–
show
|
|||||||
237 | // require_once 'PEAR.php'; |
||||||
238 | return $this->raiseError($this->error); |
||||||
0 ignored issues
–
show
|
|||||||
239 | } |
||||||
240 | |||||||
241 | // Validate each address individually. If we encounter an invalid |
||||||
242 | // address, stop iterating and return an error immediately. |
||||||
243 | foreach ($this->addresses as $address) { |
||||||
244 | $valid = $this->_validateAddress($address); |
||||||
245 | |||||||
246 | if ($valid === false || isset($this->error)) { |
||||||
247 | // require_once 'PEAR.php'; |
||||||
248 | return $this->raiseError($this->error); |
||||||
249 | } |
||||||
250 | |||||||
251 | if (!$this->nestGroups) { |
||||||
252 | $this->structure = array_merge($this->structure, $valid); |
||||||
253 | } |
||||||
254 | else { |
||||||
255 | $this->structure[] = $valid; |
||||||
256 | } |
||||||
257 | } |
||||||
258 | |||||||
259 | return $this->structure; |
||||||
260 | } |
||||||
261 | |||||||
262 | /** |
||||||
263 | * Splits an address into separate addresses. |
||||||
264 | * |
||||||
265 | * @param string $address the addresses to split |
||||||
266 | * |
||||||
267 | * @return bool success or failure |
||||||
268 | */ |
||||||
269 | protected function _splitAddresses($address) { |
||||||
270 | if (!empty($this->limit) && count($this->addresses) == $this->limit) { |
||||||
271 | return ''; |
||||||
0 ignored issues
–
show
|
|||||||
272 | } |
||||||
273 | |||||||
274 | if ($this->_isGroup($address) && !isset($this->error)) { |
||||||
275 | $split_char = ';'; |
||||||
276 | $is_group = true; |
||||||
277 | } |
||||||
278 | elseif (!isset($this->error)) { |
||||||
279 | $split_char = ','; |
||||||
280 | $is_group = false; |
||||||
281 | } |
||||||
282 | elseif (isset($this->error)) { |
||||||
283 | return false; |
||||||
284 | } |
||||||
285 | |||||||
286 | // Split the string based on the above ten or so lines. |
||||||
287 | $parts = explode($split_char, $address); |
||||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||||
288 | $string = $this->_splitCheck($parts, $split_char); |
||||||
289 | |||||||
290 | // If a group... |
||||||
291 | if ($is_group) { |
||||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||||
292 | // If $string does not contain a colon outside of |
||||||
293 | // brackets/quotes etc then something's fubar. |
||||||
294 | |||||||
295 | // First check there's a colon at all: |
||||||
296 | if (strpos($string, ':') === false) { |
||||||
0 ignored issues
–
show
It seems like
$string can also be of type false ; however, parameter $haystack of strpos() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
297 | $this->error = 'Invalid address: ' . $string; |
||||||
0 ignored issues
–
show
Are you sure
$string of type false|string can be used in concatenation ?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
298 | |||||||
299 | return false; |
||||||
300 | } |
||||||
301 | |||||||
302 | // Now check it's outside of brackets/quotes: |
||||||
303 | if (!$this->_splitCheck(explode(':', $string), ':')) { |
||||||
0 ignored issues
–
show
It seems like
$string can also be of type false ; however, parameter $string of explode() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
304 | return false; |
||||||
305 | } |
||||||
306 | |||||||
307 | // We must have a group at this point, so increase the counter: |
||||||
308 | ++$this->num_groups; |
||||||
309 | } |
||||||
310 | |||||||
311 | // $string now contains the first full address/group. |
||||||
312 | // Add to the addresses array. |
||||||
313 | $this->addresses[] = [ |
||||||
314 | 'address' => trim($string), |
||||||
0 ignored issues
–
show
It seems like
$string can also be of type false ; however, parameter $string of trim() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
315 | 'group' => $is_group, |
||||||
316 | ]; |
||||||
317 | |||||||
318 | // Remove the now stored address from the initial line, the +1 |
||||||
319 | // is to account for the explode character. |
||||||
320 | $address = trim(substr($address, strlen($string) + 1)); |
||||||
0 ignored issues
–
show
It seems like
$string can also be of type false ; however, parameter $string of strlen() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
321 | |||||||
322 | // If the next char is a comma and this was a group, then |
||||||
323 | // there are more addresses, otherwise, if there are any more |
||||||
324 | // chars, then there is another address. |
||||||
325 | if ($is_group && substr($address, 0, 1) == ',') { |
||||||
326 | return trim(substr($address, 1)); |
||||||
0 ignored issues
–
show
|
|||||||
327 | } |
||||||
328 | if (strlen($address) > 0) { |
||||||
329 | return $address; |
||||||
0 ignored issues
–
show
|
|||||||
330 | } |
||||||
331 | |||||||
332 | return ''; |
||||||
0 ignored issues
–
show
|
|||||||
333 | // If you got here then something's off |
||||||
334 | return false; |
||||||
0 ignored issues
–
show
return false is not reachable.
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed. Unreachable code is most often the result of function fx() {
try {
doSomething();
return true;
}
catch (\Exception $e) {
return false;
}
return false;
}
In the above example, the last ![]() |
|||||||
335 | } |
||||||
336 | |||||||
337 | /** |
||||||
338 | * Checks for a group at the start of the string. |
||||||
339 | * |
||||||
340 | * @param string $address the address to check |
||||||
341 | * |
||||||
342 | * @return bool whether or not there is a group at the start of the string |
||||||
343 | */ |
||||||
344 | protected function _isGroup($address) { |
||||||
345 | // First comma not in quotes, angles or escaped: |
||||||
346 | $parts = explode(',', $address); |
||||||
347 | $string = $this->_splitCheck($parts, ','); |
||||||
348 | |||||||
349 | // Now we have the first address, we can reliably check for a |
||||||
350 | // group by searching for a colon that's not escaped or in |
||||||
351 | // quotes or angle brackets. |
||||||
352 | if (count($parts = explode(':', $string)) > 1) { |
||||||
0 ignored issues
–
show
It seems like
$string can also be of type false ; however, parameter $string of explode() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
353 | $string2 = $this->_splitCheck($parts, ':'); |
||||||
354 | |||||||
355 | return $string2 !== $string; |
||||||
356 | } |
||||||
357 | |||||||
358 | return false; |
||||||
359 | } |
||||||
360 | |||||||
361 | /** |
||||||
362 | * A common function that will check an exploded string. |
||||||
363 | * |
||||||
364 | * @param array $parts the exloded string |
||||||
365 | * @param string $char the char that was exploded on |
||||||
366 | * |
||||||
367 | * @return mixed false if the string contains unclosed quotes/brackets, or the string on success |
||||||
368 | */ |
||||||
369 | protected function _splitCheck($parts, $char) { |
||||||
370 | $string = $parts[0]; |
||||||
371 | $partsCount = count($parts); |
||||||
372 | |||||||
373 | for ($i = 0; $i < $partsCount; ++$i) { |
||||||
374 | if ($this->_hasUnclosedQuotes($string) || |
||||||
375 | $this->_hasUnclosedBrackets($string, '<>') || |
||||||
376 | $this->_hasUnclosedBrackets($string, '[]') || |
||||||
377 | $this->_hasUnclosedBrackets($string, '()') || |
||||||
378 | substr($string, -1) == '\\') { |
||||||
379 | if (isset($parts[$i + 1])) { |
||||||
380 | $string = $string . $char . $parts[$i + 1]; |
||||||
381 | } |
||||||
382 | else { |
||||||
383 | $this->error = 'Invalid address spec. Unclosed bracket or quotes'; |
||||||
384 | |||||||
385 | return false; |
||||||
386 | } |
||||||
387 | } |
||||||
388 | else { |
||||||
389 | $this->index = $i; |
||||||
390 | |||||||
391 | break; |
||||||
392 | } |
||||||
393 | } |
||||||
394 | |||||||
395 | return $string; |
||||||
396 | } |
||||||
397 | |||||||
398 | /** |
||||||
399 | * Checks if a string has unclosed quotes or not. |
||||||
400 | * |
||||||
401 | * @param string $string the string to check |
||||||
402 | * |
||||||
403 | * @return bool true if there are unclosed quotes inside the string, |
||||||
404 | * false otherwise |
||||||
405 | */ |
||||||
406 | protected function _hasUnclosedQuotes($string) { |
||||||
407 | $string = trim($string); |
||||||
408 | $iMax = strlen($string); |
||||||
409 | $in_quote = false; |
||||||
410 | $i = $slashes = 0; |
||||||
411 | |||||||
412 | for (; $i < $iMax; ++$i) { |
||||||
413 | switch ($string[$i]) { |
||||||
414 | case '\\': |
||||||
415 | ++$slashes; |
||||||
416 | |||||||
417 | break; |
||||||
418 | |||||||
419 | case '"': |
||||||
420 | if ($slashes % 2 == 0) { |
||||||
421 | $in_quote = !$in_quote; |
||||||
0 ignored issues
–
show
|
|||||||
422 | } |
||||||
423 | // Fall through to default action below. |
||||||
424 | |||||||
425 | // no break |
||||||
426 | default: |
||||||
427 | $slashes = 0; |
||||||
428 | |||||||
429 | break; |
||||||
430 | } |
||||||
431 | } |
||||||
432 | |||||||
433 | return $in_quote; |
||||||
434 | } |
||||||
435 | |||||||
436 | /** |
||||||
437 | * Checks if a string has an unclosed brackets or not. IMPORTANT: |
||||||
438 | * This function handles both angle brackets and square brackets;. |
||||||
439 | * |
||||||
440 | * @param string $string the string to check |
||||||
441 | * @param string $chars the characters to check for |
||||||
442 | * |
||||||
443 | * @return bool true if there are unclosed brackets inside the string, false otherwise |
||||||
444 | */ |
||||||
445 | protected function _hasUnclosedBrackets($string, $chars) { |
||||||
446 | $num_angle_start = substr_count($string, $chars[0]); |
||||||
447 | $num_angle_end = substr_count($string, $chars[1]); |
||||||
448 | |||||||
449 | $this->_hasUnclosedBracketsSub($string, $num_angle_start, $chars[0]); |
||||||
450 | $this->_hasUnclosedBracketsSub($string, $num_angle_end, $chars[1]); |
||||||
451 | |||||||
452 | if ($num_angle_start < $num_angle_end) { |
||||||
453 | $this->error = 'Invalid address spec. Unmatched quote or bracket (' . $chars . ')'; |
||||||
454 | |||||||
455 | return false; |
||||||
456 | } |
||||||
457 | |||||||
458 | return $num_angle_start > $num_angle_end; |
||||||
459 | } |
||||||
460 | |||||||
461 | /** |
||||||
462 | * Sub function that is used only by hasUnclosedBrackets(). |
||||||
463 | * |
||||||
464 | * @param string $string the string to check |
||||||
465 | * @param int &$num The number of occurrences |
||||||
466 | * @param string $char the character to count |
||||||
467 | * |
||||||
468 | * @return int the number of occurrences of $char in $string, adjusted for backslashes |
||||||
469 | */ |
||||||
470 | protected function _hasUnclosedBracketsSub($string, &$num, $char) { |
||||||
471 | $parts = explode($char, $string); |
||||||
472 | $partsCount = count($parts); |
||||||
473 | |||||||
474 | for ($i = 0; $i < $partsCount; ++$i) { |
||||||
475 | if (substr($parts[$i], -1) == '\\' || $this->_hasUnclosedQuotes($parts[$i])) { |
||||||
476 | --$num; |
||||||
477 | } |
||||||
478 | if (isset($parts[$i + 1])) { |
||||||
479 | $parts[$i + 1] = $parts[$i] . $char . $parts[$i + 1]; |
||||||
480 | } |
||||||
481 | } |
||||||
482 | |||||||
483 | return $num; |
||||||
484 | } |
||||||
485 | |||||||
486 | /** |
||||||
487 | * Function to begin checking the address. |
||||||
488 | * |
||||||
489 | * @param string $address the address to validate |
||||||
490 | * |
||||||
491 | * @return mixed false on failure, or a structured array of address information on success |
||||||
492 | */ |
||||||
493 | protected function _validateAddress($address) { |
||||||
494 | $is_group = false; |
||||||
495 | $addresses = []; |
||||||
496 | |||||||
497 | if ($address['group']) { |
||||||
498 | $is_group = true; |
||||||
499 | |||||||
500 | // Get the group part of the name |
||||||
501 | $parts = explode(':', $address['address']); |
||||||
502 | $groupname = $this->_splitCheck($parts, ':'); |
||||||
503 | $structure = []; |
||||||
504 | |||||||
505 | // And validate the group part of the name. |
||||||
506 | if (!$this->_validatePhrase($groupname)) { |
||||||
0 ignored issues
–
show
It seems like
$groupname can also be of type false ; however, parameter $phrase of Mail_RFC822::_validatePhrase() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
507 | $this->error = 'Group name did not validate.'; |
||||||
508 | |||||||
509 | return false; |
||||||
510 | } |
||||||
511 | // Don't include groups if we are not nesting |
||||||
512 | // them. This avoids returning invalid addresses. |
||||||
513 | if ($this->nestGroups) { |
||||||
514 | $structure = new stdClass(); |
||||||
515 | $structure->groupname = $groupname; |
||||||
516 | } |
||||||
517 | |||||||
518 | $address['address'] = ltrim(substr($address['address'], strlen($groupname . ':'))); |
||||||
0 ignored issues
–
show
Are you sure
$groupname of type false|string can be used in concatenation ?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
519 | } |
||||||
520 | |||||||
521 | // If a group then split on comma and put into an array. |
||||||
522 | // Otherwise, Just put the whole address in an array. |
||||||
523 | if ($is_group) { |
||||||
524 | while (strlen($address['address']) > 0) { |
||||||
525 | $parts = explode(',', $address['address']); |
||||||
526 | $addresses[] = $this->_splitCheck($parts, ','); |
||||||
527 | $address['address'] = trim(substr($address['address'], strlen(end($addresses) . ','))); |
||||||
528 | } |
||||||
529 | } |
||||||
530 | else { |
||||||
531 | $addresses[] = $address['address']; |
||||||
532 | } |
||||||
533 | |||||||
534 | // Trim the whitespace from all of the address strings. |
||||||
535 | array_map('trim', $addresses); |
||||||
536 | |||||||
537 | // Validate each mailbox. |
||||||
538 | // Format could be one of: name <[email protected]> |
||||||
539 | // [email protected] |
||||||
540 | // geezer |
||||||
541 | // ... or any other format valid by RFC 822. |
||||||
542 | $addressesCount = count($addresses); |
||||||
543 | |||||||
544 | for ($i = 0; $i < $addressesCount; ++$i) { |
||||||
545 | if (!$this->validateMailbox($addresses[$i])) { |
||||||
546 | if (empty($this->error)) { |
||||||
547 | $this->error = 'Validation failed for: ' . $addresses[$i]; |
||||||
548 | } |
||||||
549 | |||||||
550 | return false; |
||||||
551 | } |
||||||
552 | } |
||||||
553 | |||||||
554 | // Nested format |
||||||
555 | if ($this->nestGroups) { |
||||||
556 | if ($is_group) { |
||||||
557 | $structure->addresses = $addresses; |
||||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||||
558 | } |
||||||
559 | else { |
||||||
560 | $structure = $addresses[0]; |
||||||
561 | } |
||||||
562 | |||||||
563 | // Flat format |
||||||
564 | } |
||||||
565 | else { |
||||||
566 | if ($is_group) { |
||||||
567 | $structure = array_merge($structure, $addresses); |
||||||
568 | } |
||||||
569 | else { |
||||||
570 | $structure = $addresses; |
||||||
571 | } |
||||||
572 | } |
||||||
573 | |||||||
574 | return $structure; |
||||||
575 | } |
||||||
576 | |||||||
577 | /** |
||||||
578 | * Function to validate a phrase. |
||||||
579 | * |
||||||
580 | * @param string $phrase the phrase to check |
||||||
581 | * |
||||||
582 | * @return bool success or failure |
||||||
583 | */ |
||||||
584 | protected function _validatePhrase($phrase) { |
||||||
585 | // Splits on one or more Tab or space. |
||||||
586 | $parts = preg_split('/[ \\x09]+/', $phrase, -1, PREG_SPLIT_NO_EMPTY); |
||||||
587 | |||||||
588 | $phrase_parts = []; |
||||||
589 | while (count($parts) > 0) { |
||||||
590 | $phrase_parts[] = $this->_splitCheck($parts, ' '); |
||||||
591 | for ($i = 0; $i < $this->index + 1; ++$i) { |
||||||
592 | array_shift($parts); |
||||||
593 | } |
||||||
594 | } |
||||||
595 | |||||||
596 | foreach ($phrase_parts as $part) { |
||||||
597 | // If quoted string: |
||||||
598 | if (substr($part, 0, 1) == '"') { |
||||||
599 | if (!$this->_validateQuotedString($part)) { |
||||||
600 | return false; |
||||||
601 | } |
||||||
602 | |||||||
603 | continue; |
||||||
604 | } |
||||||
605 | |||||||
606 | // Otherwise it's an atom: |
||||||
607 | if (!$this->_validateAtom($part)) { |
||||||
608 | return false; |
||||||
609 | } |
||||||
610 | } |
||||||
611 | |||||||
612 | return true; |
||||||
613 | } |
||||||
614 | |||||||
615 | /** |
||||||
616 | * Function to validate an atom which from rfc822 is: |
||||||
617 | * atom = 1*<any CHAR except specials, SPACE and CTLs>. |
||||||
618 | * |
||||||
619 | * If validation ($this->validate) has been turned off, then |
||||||
620 | * validateAtom() doesn't actually check anything. This is so that you |
||||||
621 | * can split a list of addresses up before encoding personal names |
||||||
622 | * (umlauts, etc.), for example. |
||||||
623 | * |
||||||
624 | * @param string $atom the string to check |
||||||
625 | * |
||||||
626 | * @return bool success or failure |
||||||
627 | */ |
||||||
628 | protected function _validateAtom($atom) { |
||||||
629 | if (!$this->validate) { |
||||||
630 | // Validation has been turned off; assume the atom is okay. |
||||||
631 | return true; |
||||||
632 | } |
||||||
633 | |||||||
634 | // Check for any char from ASCII 0 - ASCII 127 |
||||||
635 | if (!preg_match('/^[\\x00-\\x7E]+$/i', $atom, $matches)) { |
||||||
636 | return false; |
||||||
637 | } |
||||||
638 | |||||||
639 | // Check for specials: |
||||||
640 | if (preg_match('/[][()<>@,;\\:". ]/', $atom)) { |
||||||
641 | return false; |
||||||
642 | } |
||||||
643 | |||||||
644 | // Check for control characters (ASCII 0-31): |
||||||
645 | if (preg_match('/[\\x00-\\x1F]+/', $atom)) { |
||||||
646 | return false; |
||||||
647 | } |
||||||
648 | |||||||
649 | return true; |
||||||
650 | } |
||||||
651 | |||||||
652 | /** |
||||||
653 | * Function to validate quoted string, which is: |
||||||
654 | * quoted-string = <"> *(qtext/quoted-pair) <">. |
||||||
655 | * |
||||||
656 | * @param string $qstring The string to check |
||||||
657 | * |
||||||
658 | * @return bool success or failure |
||||||
659 | */ |
||||||
660 | protected function _validateQuotedString($qstring) { |
||||||
661 | // Leading and trailing " |
||||||
662 | $qstring = substr($qstring, 1, -1); |
||||||
663 | |||||||
664 | // Perform check, removing quoted characters first. |
||||||
665 | return !preg_match('/[\x0D\\\\"]/', preg_replace('/\\\\./', '', $qstring)); |
||||||
666 | } |
||||||
667 | |||||||
668 | /** |
||||||
669 | * Function to validate a mailbox, which is: |
||||||
670 | * mailbox = addr-spec ; simple address |
||||||
671 | * / phrase route-addr ; name and route-addr. |
||||||
672 | * |
||||||
673 | * @param string &$mailbox The string to check |
||||||
674 | * |
||||||
675 | * @return bool success or failure |
||||||
676 | */ |
||||||
677 | public function validateMailbox(&$mailbox) { |
||||||
678 | // A couple of defaults. |
||||||
679 | $phrase = ''; |
||||||
680 | $comment = ''; |
||||||
0 ignored issues
–
show
|
|||||||
681 | $comments = []; |
||||||
682 | |||||||
683 | // Catch any RFC822 comments and store them separately. |
||||||
684 | $_mailbox = $mailbox; |
||||||
685 | while (strlen(trim($_mailbox)) > 0) { |
||||||
686 | $parts = explode('(', $_mailbox); |
||||||
687 | $before_comment = $this->_splitCheck($parts, '('); |
||||||
688 | if ($before_comment != $_mailbox) { |
||||||
689 | // First char should be a (. |
||||||
690 | $comment = substr(str_replace($before_comment, '', $_mailbox), 1); |
||||||
0 ignored issues
–
show
It seems like
$before_comment can also be of type false ; however, parameter $search of str_replace() does only seem to accept string|string[] , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
691 | $parts = explode(')', $comment); |
||||||
692 | $comment = $this->_splitCheck($parts, ')'); |
||||||
693 | $comments[] = $comment; |
||||||
694 | |||||||
695 | // +2 is for the brackets |
||||||
696 | $_mailbox = substr($_mailbox, strpos($_mailbox, '(' . $comment) + strlen($comment) + 2); |
||||||
0 ignored issues
–
show
It seems like
$comment can also be of type false ; however, parameter $string of strlen() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() Are you sure
$comment of type false|string can be used in concatenation ?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
697 | } |
||||||
698 | else { |
||||||
699 | break; |
||||||
700 | } |
||||||
701 | } |
||||||
702 | |||||||
703 | foreach ($comments as $comment) { |
||||||
704 | $mailbox = str_replace("({$comment})", '', $mailbox); |
||||||
705 | } |
||||||
706 | |||||||
707 | $mailbox = trim($mailbox); |
||||||
708 | |||||||
709 | // Check for name + route-addr |
||||||
710 | if (substr($mailbox, -1) == '>' && substr($mailbox, 0, 1) != '<') { |
||||||
711 | $parts = explode('<', $mailbox); |
||||||
712 | $name = $this->_splitCheck($parts, '<'); |
||||||
713 | |||||||
714 | $phrase = trim($name); |
||||||
0 ignored issues
–
show
It seems like
$name can also be of type false ; however, parameter $string of trim() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
715 | $route_addr = trim(substr($mailbox, strlen($name . '<'), -1)); |
||||||
0 ignored issues
–
show
Are you sure
$name of type false|string can be used in concatenation ?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
716 | |||||||
717 | // grommunio-sync fix for umlauts and other special chars |
||||||
718 | if (substr($phrase, 0, 1) != '"' && substr($phrase, -1) != '"') { |
||||||
719 | $phrase = '"' . $phrase . '"'; |
||||||
720 | } |
||||||
721 | |||||||
722 | if ($this->_validatePhrase($phrase) === false || ($route_addr = $this->_validateRouteAddr($route_addr)) === false) { |
||||||
723 | return false; |
||||||
724 | } |
||||||
725 | |||||||
726 | // Only got addr-spec |
||||||
727 | } |
||||||
728 | else { |
||||||
729 | // First snip angle brackets if present. |
||||||
730 | if (substr($mailbox, 0, 1) == '<' && substr($mailbox, -1) == '>') { |
||||||
731 | $addr_spec = substr($mailbox, 1, -1); |
||||||
732 | } |
||||||
733 | else { |
||||||
734 | $addr_spec = $mailbox; |
||||||
735 | } |
||||||
736 | |||||||
737 | if (($addr_spec = $this->_validateAddrSpec($addr_spec)) === false) { |
||||||
738 | return false; |
||||||
739 | } |
||||||
740 | } |
||||||
741 | |||||||
742 | // Construct the object that will be returned. |
||||||
743 | $mbox = new stdClass(); |
||||||
744 | |||||||
745 | // Add the phrase (even if empty) and comments |
||||||
746 | $mbox->personal = $phrase; |
||||||
747 | $mbox->comment = isset($comments) ? $comments : []; |
||||||
748 | |||||||
749 | if (isset($route_addr)) { |
||||||
750 | $mbox->mailbox = $route_addr['local_part']; |
||||||
751 | $mbox->host = $route_addr['domain']; |
||||||
752 | $route_addr['adl'] !== '' ? $mbox->adl = $route_addr['adl'] : ''; |
||||||
753 | } |
||||||
754 | else { |
||||||
755 | $mbox->mailbox = $addr_spec['local_part']; |
||||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||||
756 | $mbox->host = $addr_spec['domain']; |
||||||
757 | } |
||||||
758 | |||||||
759 | $mailbox = $mbox; |
||||||
760 | |||||||
761 | return true; |
||||||
762 | } |
||||||
763 | |||||||
764 | /** |
||||||
765 | * This function validates a route-addr which is: |
||||||
766 | * route-addr = "<" [route] addr-spec ">". |
||||||
767 | * |
||||||
768 | * Angle brackets have already been removed at the point of |
||||||
769 | * getting to this function. |
||||||
770 | * |
||||||
771 | * @param string $route_addr the string to check |
||||||
772 | * |
||||||
773 | * @return mixed false on failure, or an array containing validated address/route information on success |
||||||
774 | */ |
||||||
775 | protected function _validateRouteAddr($route_addr) { |
||||||
776 | // Check for colon. |
||||||
777 | if (strpos($route_addr, ':') !== false) { |
||||||
778 | $parts = explode(':', $route_addr); |
||||||
779 | $route = $this->_splitCheck($parts, ':'); |
||||||
780 | } |
||||||
781 | else { |
||||||
782 | $route = $route_addr; |
||||||
783 | } |
||||||
784 | |||||||
785 | // If $route is same as $route_addr then the colon was in |
||||||
786 | // quotes or brackets or, of course, non existent. |
||||||
787 | if ($route === $route_addr) { |
||||||
788 | unset($route); |
||||||
789 | $addr_spec = $route_addr; |
||||||
790 | if (($addr_spec = $this->_validateAddrSpec($addr_spec)) === false) { |
||||||
791 | return false; |
||||||
792 | } |
||||||
793 | } |
||||||
794 | else { |
||||||
795 | // Validate route part. |
||||||
796 | if (($route = $this->_validateRoute($route)) === false) { |
||||||
0 ignored issues
–
show
It seems like
$route can also be of type false ; however, parameter $route of Mail_RFC822::_validateRoute() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
797 | return false; |
||||||
798 | } |
||||||
799 | |||||||
800 | $addr_spec = substr($route_addr, strlen($route . ':')); |
||||||
801 | |||||||
802 | // Validate addr-spec part. |
||||||
803 | if (($addr_spec = $this->_validateAddrSpec($addr_spec)) === false) { |
||||||
804 | return false; |
||||||
805 | } |
||||||
806 | } |
||||||
807 | |||||||
808 | if (isset($route)) { |
||||||
809 | $return['adl'] = $route; |
||||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||||
810 | } |
||||||
811 | else { |
||||||
812 | $return['adl'] = ''; |
||||||
813 | } |
||||||
814 | |||||||
815 | return array_merge($return, $addr_spec); |
||||||
816 | } |
||||||
817 | |||||||
818 | /** |
||||||
819 | * Function to validate a route, which is: |
||||||
820 | * route = 1#("@" domain) ":". |
||||||
821 | * |
||||||
822 | * @param string $route the string to check |
||||||
823 | * |
||||||
824 | * @return mixed false on failure, or the validated $route on success |
||||||
825 | */ |
||||||
826 | protected function _validateRoute($route) { |
||||||
827 | // Split on comma. |
||||||
828 | $domains = explode(',', trim($route)); |
||||||
829 | |||||||
830 | foreach ($domains as $domain) { |
||||||
831 | $domain = str_replace('@', '', trim($domain)); |
||||||
832 | if (!$this->_validateDomain($domain)) { |
||||||
833 | return false; |
||||||
834 | } |
||||||
835 | } |
||||||
836 | |||||||
837 | return $route; |
||||||
838 | } |
||||||
839 | |||||||
840 | /** |
||||||
841 | * Function to validate a domain, though this is not quite what |
||||||
842 | * you expect of a strict internet domain. |
||||||
843 | * |
||||||
844 | * domain = sub-domain *("." sub-domain) |
||||||
845 | * |
||||||
846 | * @param string $domain the string to check |
||||||
847 | * |
||||||
848 | * @return mixed false on failure, or the validated domain on success |
||||||
849 | */ |
||||||
850 | protected function _validateDomain($domain) { |
||||||
851 | // Note the different use of $subdomains and $sub_domains |
||||||
852 | $subdomains = explode('.', $domain); |
||||||
853 | |||||||
854 | while (count($subdomains) > 0) { |
||||||
855 | $sub_domains[] = $this->_splitCheck($subdomains, '.'); |
||||||
856 | for ($i = 0; $i < $this->index + 1; ++$i) { |
||||||
857 | array_shift($subdomains); |
||||||
858 | } |
||||||
859 | } |
||||||
860 | |||||||
861 | foreach ($sub_domains as $sub_domain) { |
||||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||||
862 | if (!$this->_validateSubdomain(trim($sub_domain))) { |
||||||
863 | return false; |
||||||
864 | } |
||||||
865 | } |
||||||
866 | |||||||
867 | // Managed to get here, so return input. |
||||||
868 | return $domain; |
||||||
869 | } |
||||||
870 | |||||||
871 | /** |
||||||
872 | * Function to validate a subdomain: |
||||||
873 | * subdomain = domain-ref / domain-literal. |
||||||
874 | * |
||||||
875 | * @param string $subdomain the string to check |
||||||
876 | * |
||||||
877 | * @return bool success or failure |
||||||
878 | */ |
||||||
879 | protected function _validateSubdomain($subdomain) { |
||||||
880 | if (preg_match('|^\[(.*)]$|', $subdomain, $arr)) { |
||||||
881 | if (!$this->_validateDliteral($arr[1])) { |
||||||
882 | return false; |
||||||
883 | } |
||||||
884 | } |
||||||
885 | else { |
||||||
886 | if (!$this->_validateAtom($subdomain)) { |
||||||
887 | return false; |
||||||
888 | } |
||||||
889 | } |
||||||
890 | |||||||
891 | // Got here, so return successful. |
||||||
892 | return true; |
||||||
893 | } |
||||||
894 | |||||||
895 | /** |
||||||
896 | * Function to validate a domain literal: |
||||||
897 | * domain-literal = "[" *(dtext / quoted-pair) "]". |
||||||
898 | * |
||||||
899 | * @param string $dliteral the string to check |
||||||
900 | * |
||||||
901 | * @return bool success or failure |
||||||
902 | */ |
||||||
903 | protected function _validateDliteral($dliteral) { |
||||||
904 | return !preg_match('/(.)[][\x0D\\\\]/', $dliteral, $matches) && ((!isset($matches[1])) || $matches[1] != '\\'); |
||||||
905 | } |
||||||
906 | |||||||
907 | /** |
||||||
908 | * Function to validate an addr-spec. |
||||||
909 | * |
||||||
910 | * addr-spec = local-part "@" domain |
||||||
911 | * |
||||||
912 | * @param string $addr_spec the string to check |
||||||
913 | * |
||||||
914 | * @return mixed false on failure, or the validated addr-spec on success |
||||||
915 | */ |
||||||
916 | protected function _validateAddrSpec($addr_spec) { |
||||||
917 | $addr_spec = trim($addr_spec); |
||||||
918 | |||||||
919 | // Split on @ sign if there is one. |
||||||
920 | if (strpos($addr_spec, '@') !== false) { |
||||||
921 | $parts = explode('@', $addr_spec); |
||||||
922 | $local_part = $this->_splitCheck($parts, '@'); |
||||||
923 | $domain = substr($addr_spec, strlen($local_part . '@')); |
||||||
0 ignored issues
–
show
Are you sure
$local_part of type false|string can be used in concatenation ?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
924 | |||||||
925 | // No @ sign so assume the default domain. |
||||||
926 | } |
||||||
927 | else { |
||||||
928 | $local_part = $addr_spec; |
||||||
929 | $domain = $this->default_domain; |
||||||
930 | } |
||||||
931 | |||||||
932 | if (($local_part = $this->_validateLocalPart($local_part)) === false) { |
||||||
0 ignored issues
–
show
It seems like
$local_part can also be of type false ; however, parameter $local_part of Mail_RFC822::_validateLocalPart() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
933 | return false; |
||||||
934 | } |
||||||
935 | if (($domain = $this->_validateDomain($domain)) === false) { |
||||||
936 | return false; |
||||||
937 | } |
||||||
938 | |||||||
939 | // Got here so return successful. |
||||||
940 | return ['local_part' => $local_part, 'domain' => $domain]; |
||||||
941 | } |
||||||
942 | |||||||
943 | /** |
||||||
944 | * Function to validate the local part of an address: |
||||||
945 | * local-part = word *("." word). |
||||||
946 | * |
||||||
947 | * @param string $local_part |
||||||
948 | * |
||||||
949 | * @return mixed false on failure, or the validated local part on success |
||||||
950 | */ |
||||||
951 | protected function _validateLocalPart($local_part) { |
||||||
952 | $parts = explode('.', $local_part); |
||||||
953 | $words = []; |
||||||
954 | |||||||
955 | // Split the local_part into words. |
||||||
956 | while (count($parts) > 0) { |
||||||
957 | $words[] = $this->_splitCheck($parts, '.'); |
||||||
958 | for ($i = 0; $i < $this->index + 1; ++$i) { |
||||||
959 | array_shift($parts); |
||||||
960 | } |
||||||
961 | } |
||||||
962 | |||||||
963 | // Validate each word. |
||||||
964 | foreach ($words as $word) { |
||||||
965 | // word cannot be empty (#17317) |
||||||
966 | if ($word === '') { |
||||||
967 | return false; |
||||||
968 | } |
||||||
969 | // If this word contains an unquoted space, it is invalid. (6.2.4) |
||||||
970 | if (strpos($word, ' ') && $word[0] !== '"') { |
||||||
971 | return false; |
||||||
972 | } |
||||||
973 | |||||||
974 | if ($this->_validatePhrase(trim($word)) === false) { |
||||||
975 | return false; |
||||||
976 | } |
||||||
977 | } |
||||||
978 | |||||||
979 | // Managed to get here, so return the input. |
||||||
980 | return $local_part; |
||||||
981 | } |
||||||
982 | |||||||
983 | /** |
||||||
984 | * Returns an approximate count of how many addresses are in the |
||||||
985 | * given string. This is APPROXIMATE as it only splits based on a |
||||||
986 | * comma which has no preceding backslash. Could be useful as |
||||||
987 | * large amounts of addresses will end up producing *large* |
||||||
988 | * structures when used with parseAddressList(). |
||||||
989 | * |
||||||
990 | * @param string $data Addresses to count |
||||||
991 | * |
||||||
992 | * @return int Approximate count |
||||||
993 | */ |
||||||
994 | public function approximateCount($data) { |
||||||
995 | return count(preg_split('/(?<!\\\\),/', $data)); |
||||||
996 | } |
||||||
997 | |||||||
998 | /** |
||||||
999 | * This is a email validating function separate to the rest of the |
||||||
1000 | * class. It simply validates whether an email is of the common |
||||||
1001 | * internet form: <user>@<domain>. This can be sufficient for most |
||||||
1002 | * people. Optional stricter mode can be utilised which restricts |
||||||
1003 | * mailbox characters allowed to alphanumeric, full stop, hyphen |
||||||
1004 | * and underscore. |
||||||
1005 | * |
||||||
1006 | * @param string $data Address to check |
||||||
1007 | * @param bool $strict Optional stricter mode |
||||||
1008 | * |
||||||
1009 | * @return mixed False if it fails, an indexed array |
||||||
1010 | * username/domain if it matches |
||||||
1011 | */ |
||||||
1012 | public function isValidInetAddress($data, $strict = false) { |
||||||
1013 | $regex = $strict ? '/^([.0-9a-z_+-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})$/i' : '/^([*+!.&#$|\'\\%\/0-9a-z^_`{}=?~:-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})$/i'; |
||||||
1014 | if (preg_match($regex, trim($data), $matches)) { |
||||||
1015 | return [$matches[1], $matches[2]]; |
||||||
1016 | } |
||||||
1017 | |||||||
1018 | return false; |
||||||
1019 | } |
||||||
1020 | |||||||
1021 | /** |
||||||
1022 | * grommunio-sync helper for error logging |
||||||
1023 | * removing PEAR dependency. |
||||||
1024 | * |
||||||
1025 | * @param string debug message |
||||||
0 ignored issues
–
show
The type
debug was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths ![]() |
|||||||
1026 | * @param mixed $message |
||||||
1027 | * |
||||||
1028 | * @return bool always false as there was an error |
||||||
1029 | */ |
||||||
1030 | public function raiseError($message) { |
||||||
1031 | SLog::Write(LOGLEVEL_ERROR, "z_RFC822 error: " . $message); |
||||||
1032 | |||||||
1033 | return false; |
||||||
1034 | } |
||||||
1035 | } |
||||||
1036 |
This check looks for assignments to scalar types that may be of the wrong type.
To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.