This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
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 PHPDaemon\Clients\IMAP; |
||
4 | |||
5 | use PHPDaemon\Network\ClientConnection; |
||
6 | use PHPDaemon\Core\Daemon; |
||
7 | |||
8 | class Connection extends ClientConnection |
||
9 | { |
||
10 | const STATE_CONNECTING = 0; |
||
11 | const STATE_CONNECTED = 1; |
||
12 | const STATE_CREDS_SENT = 2; |
||
13 | const STATE_AUTHORIZED = 3; |
||
14 | |||
15 | const FLAG_PASSED = '\Passed'; |
||
16 | const FLAG_ANSWERED = '\Answered'; |
||
17 | const FLAG_SEEN = '\Seen'; |
||
18 | const FLAG_UNSEEN = '\Unseen'; |
||
19 | const FLAG_DELETED = '\Deleted'; |
||
20 | const FLAG_DRAFT = '\Draft'; |
||
21 | const FLAG_FLAGGED = '\Flagged'; |
||
22 | |||
23 | /** |
||
24 | * IMAP flags to search criteria |
||
25 | * @var array |
||
26 | */ |
||
27 | protected $searchFlags = [ |
||
28 | '\Recent' => 'RECENT', |
||
29 | '\Answered' => 'ANSWERED', |
||
30 | '\Seen' => 'SEEN', |
||
31 | '\Unseen' => 'UNSEEN', |
||
32 | '\Deleted' => 'DELETED', |
||
33 | '\Draft' => 'DRAFT', |
||
34 | '\Flagged' => 'FLAGGED', |
||
35 | ]; |
||
36 | |||
37 | const TAG_LOGIN = 'a01'; |
||
38 | const TAG_LIST = 'a02'; |
||
39 | const TAG_SELECT = 'a03'; |
||
40 | const TAG_FETCH = 'a04'; |
||
41 | const TAG_SEARCH = 'a05'; |
||
42 | const TAG_COUNT = 'a06'; |
||
43 | const TAG_SIZE = 'a07'; |
||
44 | const TAG_GETRAWMESSAGE = 'a08'; |
||
45 | const TAG_GETRAWHEADER = 'a09'; |
||
46 | const TAG_GETRAWCONTENT = 'a10'; |
||
47 | const TAG_GETUID = 'a11'; |
||
48 | const TAG_CREATEFOLDER = 'a12'; |
||
49 | const TAG_DELETEFOLDER = 'a13'; |
||
50 | const TAG_RENAMEFOLDER = 'a14'; |
||
51 | const TAG_STORE = 'a15'; |
||
52 | const TAG_DELETEMESSAGE = 'a16'; |
||
53 | const TAG_EXPUNGE = 'a17'; |
||
54 | const TAG_LOGOUT = 'a18'; |
||
55 | const TAG_STARTTLS = 'a19'; |
||
56 | |||
57 | protected $EOL = "\r\n"; |
||
58 | |||
59 | protected $state; |
||
60 | protected $lines = []; |
||
61 | protected $blob = ''; |
||
62 | protected $blobOctetsLeft = 0; |
||
63 | |||
64 | public function onReady() |
||
65 | { |
||
66 | $this->state = self::STATE_CONNECTING; |
||
67 | } |
||
68 | |||
69 | /** |
||
70 | * escape a single literal |
||
71 | * @param $string |
||
72 | * @return string escaped list for imap |
||
73 | */ |
||
74 | protected function escapeString($string) |
||
75 | { |
||
76 | return '"' . strtr($string, ['\\' => '\\\\', '"' => '\\"']) . '"'; |
||
77 | } |
||
78 | |||
79 | /** |
||
80 | * escape a list with literals or lists |
||
81 | * |
||
82 | * @param array $list list with literals or lists as PHP array |
||
83 | * @return string escaped list for imap |
||
84 | */ |
||
85 | protected function escapeList($list) |
||
86 | { |
||
87 | $result = []; |
||
88 | foreach ($list as $v) { |
||
89 | if (!is_array($v)) { |
||
90 | $result[] = $v; |
||
91 | continue; |
||
92 | } |
||
93 | $result[] = $this->escapeList($v); |
||
94 | } |
||
95 | return '(' . implode(' ', $result) . ')'; |
||
96 | } |
||
97 | |||
98 | /** |
||
99 | * split a given line in tokens. a token is literal of any form or a list |
||
100 | * |
||
101 | * @param string $line line to decode |
||
102 | * @return array tokens, literals are returned as string, lists as array |
||
103 | */ |
||
104 | protected function decodeLine($line) |
||
105 | { |
||
106 | $tokens = []; |
||
107 | $stack = []; |
||
108 | /* |
||
109 | We start to decode the response here. The understood tokens are: |
||
110 | literal |
||
111 | "literal" or also "lit\\er\"al" |
||
112 | (literals*) |
||
113 | All tokens are returned in an array. Literals in braces (the last understood |
||
114 | token in the list) are returned as an array of tokens. I.e. the following response: |
||
115 | "foo" baz bar ("f\\\"oo" bar) |
||
116 | would be returned as: |
||
117 | array('foo', 'baz', 'bar', array('f\\\"oo', 'bar')); |
||
118 | */ |
||
119 | // replace any trailing <NL> including spaces with a single space |
||
120 | $line = rtrim($line) . ' '; |
||
121 | while (($pos = strpos($line, ' ')) !== false) { |
||
122 | $token = substr($line, 0, $pos); |
||
123 | if (!strlen($token)) { |
||
124 | continue; |
||
125 | } |
||
126 | while ($token[0] === '(') { |
||
127 | array_push($stack, $tokens); |
||
128 | $tokens = []; |
||
129 | $token = substr($token, 1); |
||
130 | } |
||
131 | if ($token[0] === '"') { |
||
132 | if (preg_match('%^\(*"((.|\\\\|\\")*?)" *%', $line, $matches)) { |
||
133 | $tokens[] = $matches[1]; |
||
134 | $line = substr($line, strlen($matches[0])); |
||
135 | continue; |
||
136 | } |
||
137 | } |
||
138 | if ($stack && $token[strlen($token) - 1] === ')') { |
||
0 ignored issues
–
show
|
|||
139 | // closing braces are not separated by spaces, so we need to count them |
||
140 | $braces = strlen($token); |
||
141 | $token = rtrim($token, ')'); |
||
142 | // only count braces if more than one |
||
143 | $braces -= strlen($token) + 1; |
||
144 | // only add if token had more than just closing braces |
||
145 | if (rtrim($token) != '') { |
||
146 | $tokens[] = rtrim($token); |
||
147 | } |
||
148 | $token = $tokens; |
||
149 | $tokens = array_pop($stack); |
||
150 | // special handline if more than one closing brace |
||
151 | while ($braces-- > 0) { |
||
152 | $tokens[] = $token; |
||
153 | $token = $tokens; |
||
154 | $tokens = array_pop($stack); |
||
155 | } |
||
156 | } |
||
157 | $tokens[] = $token; |
||
158 | $line = substr($line, $pos + 1); |
||
159 | } |
||
160 | // maybe the server forgot to send some closing braces |
||
161 | while ($stack) { |
||
0 ignored issues
–
show
The expression
$stack of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||
162 | $child = $tokens; |
||
163 | $tokens = array_pop($stack); |
||
164 | $tokens[] = $child; |
||
165 | } |
||
166 | return $tokens; |
||
167 | } |
||
168 | |||
169 | /** |
||
170 | * @param array $items |
||
171 | * @param string $from |
||
172 | * @param string $to |
||
0 ignored issues
–
show
Should the type for parameter
$to not be string|null ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types. ![]() |
|||
173 | * @param bool $uid |
||
174 | * @param string $tag |
||
175 | */ |
||
176 | protected function fetch($items, $from, $to = null, $uid = false, $tag = self::TAG_FETCH) |
||
177 | { |
||
178 | if (is_array($from)) { |
||
179 | $set = implode(',', $from); |
||
180 | } elseif ($to === null) { |
||
181 | $set = (int) $from; |
||
182 | } elseif ($to === INF) { |
||
183 | $set = (int) $from . ':*'; |
||
184 | } else { |
||
185 | $set = (int) $from . ':' . (int) $to; |
||
186 | } |
||
187 | $this->writeln($tag .($uid ? ' UID' : '')." FETCH $set ". $this->escapeList((array)$items) ); |
||
188 | } |
||
189 | |||
190 | /** |
||
191 | * @param array $flags |
||
192 | * @param string $from |
||
193 | * @param string $to |
||
0 ignored issues
–
show
Should the type for parameter
$to not be string|null ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types. ![]() |
|||
194 | * @param string $mode (+/-) |
||
0 ignored issues
–
show
Should the type for parameter
$mode not be string|null ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types. ![]() |
|||
195 | * @param bool $silent |
||
196 | * @param string $tag |
||
197 | */ |
||
198 | protected function store(array $flags, $from, $to = null, $mode = null, $silent = true, $tag = self::TAG_STORE) |
||
199 | { |
||
200 | $item = 'FLAGS'; |
||
201 | if ($mode == '+' || $mode == '-') { |
||
202 | $item = $mode . $item; |
||
203 | } |
||
204 | if ($silent) { |
||
205 | $item .= '.SILENT'; |
||
206 | } |
||
207 | $flags = $this->escapeList($flags); |
||
208 | $set = (int)$from; |
||
209 | if ($to !== null) { |
||
210 | $set .= ':' . ($to == INF ? '*' : (int)$to); |
||
211 | } |
||
212 | $this->writeln($tag . ' UID STORE ' . $set . ' ' . $item . ' ' . $flags ); |
||
213 | } |
||
214 | |||
215 | /** |
||
216 | * @param string $reference |
||
217 | * @param string $mailbox |
||
218 | */ |
||
219 | public function listFolders($cb, $reference = '', $mailbox = '*') |
||
220 | { |
||
221 | $this->onResponse->push($cb); |
||
222 | $this->writeln(self::TAG_LIST .' LIST ' . $this->escapeString($reference) |
||
223 | . ' ' . $this->escapeString($mailbox) ); |
||
224 | } |
||
225 | |||
226 | /** |
||
227 | * @param string $box |
||
228 | */ |
||
229 | public function selectBox($cb, $box = 'INBOX') |
||
230 | { |
||
231 | $this->onResponse->push($cb); |
||
232 | $this->writeln(self::TAG_SELECT .' SELECT ' . $this->escapeString($box)); |
||
233 | } |
||
234 | |||
235 | /** |
||
236 | * @param string $tag |
||
237 | */ |
||
238 | protected function expunge($tag = self::TAG_EXPUNGE) |
||
239 | { |
||
240 | $this->writeln($tag .' EXPUNGE'); |
||
241 | } |
||
242 | |||
243 | /** |
||
244 | * @param string $haystack |
||
0 ignored issues
–
show
There is no parameter named
$haystack . Was it maybe removed?
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. Consider the following example. The parameter /**
* @param array $germany
* @param array $island
* @param array $italy
*/
function finale($germany, $island) {
return "2:1";
}
The most likely cause is that the parameter was removed, but the annotation was not. ![]() |
|||
245 | * @param string $needle |
||
0 ignored issues
–
show
There is no parameter named
$needle . Was it maybe removed?
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. Consider the following example. The parameter /**
* @param array $germany
* @param array $island
* @param array $italy
*/
function finale($germany, $island) {
return "2:1";
}
The most likely cause is that the parameter was removed, but the annotation was not. ![]() |
|||
246 | */ |
||
247 | public function auth($cb, $login, $password) |
||
248 | { |
||
249 | $this->onResponse->push($cb); |
||
250 | $this->writeln(self::TAG_LOGIN . " LOGIN $login $password"); |
||
251 | } |
||
252 | |||
253 | /** |
||
254 | * @param array $params |
||
255 | * @param string $tag |
||
256 | */ |
||
257 | protected function searchMessages($params, $tag = self::TAG_SEARCH) |
||
258 | { |
||
259 | $this->writeln("$tag UID SEARCH ".implode(' ', $params)); |
||
260 | } |
||
261 | |||
262 | /** |
||
263 | * @param string $haystack |
||
264 | * @param string $needle |
||
265 | */ |
||
266 | protected function startsWith($haystack, $needle) |
||
267 | { |
||
268 | // search backwards starting from haystack length characters from the end |
||
269 | return $needle === '' || strrpos($haystack, $needle, -strlen($haystack)) !== false; |
||
270 | } |
||
271 | |||
272 | /** |
||
273 | * @param array $lines |
||
274 | */ |
||
275 | protected function decodeList($lines) |
||
276 | { |
||
277 | $list = []; |
||
278 | foreach (array_map([$this, 'decodeLine'], $lines) as $tokens) { |
||
279 | $folderEntry = []; |
||
280 | if (!isset($tokens[0]) || $tokens[0] !== 'LIST') { |
||
281 | continue; |
||
282 | } |
||
283 | if (isset($tokens[3])) { |
||
284 | $folderEntry['name'] = $tokens[3]; |
||
285 | } else { |
||
286 | continue; |
||
287 | } |
||
288 | if (isset($tokens[1])) { |
||
289 | $folderEntry['flags'] = $tokens[1]; |
||
290 | } else { |
||
291 | continue; |
||
292 | } |
||
293 | $list[] = $folderEntry; |
||
294 | } |
||
295 | return $list; |
||
296 | } |
||
297 | |||
298 | /** |
||
299 | * @param array $lines |
||
300 | */ |
||
301 | protected function decodeCount($lines) |
||
302 | { |
||
303 | foreach (array_map([$this, 'decodeLine'], $lines) as $tokens) { |
||
304 | if (!isset($tokens[0]) || $tokens[0] !== 'SEARCH') { |
||
305 | continue; |
||
306 | } |
||
307 | return count($tokens) - 1; |
||
308 | } |
||
309 | return 0; |
||
310 | } |
||
311 | |||
312 | /** |
||
313 | * @param array $lines |
||
314 | */ |
||
315 | protected function decodeGetUniqueId($lines) |
||
316 | { |
||
317 | $uids = []; |
||
318 | foreach (array_map([$this, 'decodeLine'], $lines) as $tokens) { |
||
319 | if (!isset($tokens[1]) || $tokens[1] !== 'FETCH') { |
||
320 | continue; |
||
321 | } |
||
322 | View Code Duplication | if (!isset($tokens[2][0]) || $tokens[2][0] !== 'UID') { |
|
0 ignored issues
–
show
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. ![]() |
|||
323 | continue; |
||
324 | } |
||
325 | if (!isset($tokens[0]) || !isset($tokens[2][1])) { |
||
326 | continue; |
||
327 | } |
||
328 | $uids[$tokens[0]] = $tokens[2][1]; |
||
329 | } |
||
330 | return $uids; |
||
331 | } |
||
332 | |||
333 | /* |
||
334 | * @param array $lines |
||
335 | */ |
||
336 | protected function decodeSize($lines) |
||
337 | { |
||
338 | $sizes = []; |
||
339 | foreach (array_map([$this, 'decodeLine'], $lines) as $tokens) { |
||
340 | if (!isset($tokens[1]) || $tokens[1] !== 'FETCH') { |
||
341 | continue; |
||
342 | } |
||
343 | View Code Duplication | if (!isset($tokens[2][0]) || $tokens[2][0] !== 'UID') { |
|
0 ignored issues
–
show
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. ![]() |
|||
344 | continue; |
||
345 | } |
||
346 | View Code Duplication | if (!isset($tokens[2][2]) || $tokens[2][2] !== 'RFC822.SIZE') { |
|
0 ignored issues
–
show
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. ![]() |
|||
347 | continue; |
||
348 | } |
||
349 | View Code Duplication | if (!isset($tokens[2][1]) || !isset($tokens[2][3])) { |
|
0 ignored issues
–
show
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. ![]() |
|||
350 | continue; |
||
351 | } |
||
352 | $sizes[$tokens[2][1]] = $tokens[2][3]; |
||
353 | } |
||
354 | return $sizes; |
||
355 | } |
||
356 | |||
357 | /** |
||
358 | * |
||
359 | * @param string $tag response tag |
||
360 | * @param string $type OK, NO, BAD |
||
361 | * @param string $line last response line |
||
362 | * @param array $lines full response |
||
363 | * @param string $blob |
||
364 | */ |
||
365 | protected function onCommand($tag, $type, $line, $lines, $blob) |
||
366 | { |
||
367 | $ok = $type === 'OK'; |
||
368 | $no = $type === 'NO'; |
||
369 | if ($type === 'BAD') { |
||
370 | $this->log("Server said: " . $line); |
||
371 | } |
||
372 | $raw = ['lines' => $lines, 'blob' => $blob]; |
||
373 | switch ($tag) { |
||
374 | case self::TAG_LOGIN: |
||
375 | if ($ok) { |
||
376 | $this->state = self::STATE_AUTHORIZED; |
||
377 | $this->onResponse->executeOne($this, $line); |
||
378 | } elseif ($no) { |
||
379 | $this->log("Failed to login: " . $line); |
||
380 | $this->finish(); |
||
381 | } |
||
382 | break; |
||
383 | |||
384 | case self::TAG_LIST: |
||
385 | $this->onResponse->executeOne($this, $ok, $this->decodeList($lines)); |
||
386 | break; |
||
387 | |||
388 | case self::TAG_GETUID: |
||
389 | $this->onResponse->executeOne($this, $ok, $this->decodeGetUniqueId($lines)); |
||
390 | break; |
||
391 | |||
392 | case self::TAG_COUNT: |
||
393 | $this->onResponse->executeOne($this, $ok, $this->decodeCount($lines)); |
||
394 | break; |
||
395 | |||
396 | case self::TAG_SIZE: |
||
397 | $this->onResponse->executeOne($this, $ok, $this->decodeSize($lines)); |
||
398 | break; |
||
399 | |||
400 | case self::TAG_DELETEMESSAGE: |
||
401 | $this->expunge(); |
||
402 | break; |
||
403 | |||
404 | case self::TAG_EXPUNGE: |
||
405 | $this->onResponse->executeOne($this, count($lines) - 1, $raw); |
||
406 | break; |
||
407 | |||
408 | case self::TAG_GETRAWMESSAGE: |
||
409 | $this->onResponse->executeOne($this, !empty($blob), $raw); |
||
410 | break; |
||
411 | |||
412 | case self::TAG_GETRAWHEADER: |
||
413 | $this->onResponse->executeOne($this, !empty($blob), $raw); |
||
414 | break; |
||
415 | |||
416 | case self::TAG_GETRAWCONTENT: |
||
417 | $this->onResponse->executeOne($this, !empty($blob), $raw); |
||
418 | break; |
||
419 | |||
420 | default: |
||
421 | $this->onResponse->executeOne($this, $ok, $raw); |
||
422 | break; |
||
423 | } |
||
424 | } |
||
425 | |||
426 | public function onRead() |
||
427 | { |
||
428 | while (($rawLine = $this->readLine(\EventBuffer::EOL_CRLF_STRICT)) !== null) { |
||
429 | if ($this->blobOctetsLeft > 0) { |
||
430 | $this->blob .= $rawLine . "\r\n"; |
||
431 | $this->blobOctetsLeft -= strlen($rawLine) + 2; |
||
432 | continue; |
||
433 | } |
||
434 | if (preg_match('~\{([0-9]+)\}$~', $rawLine, $matches)) { |
||
435 | $this->blob = ''; |
||
436 | $this->blobOctetsLeft = $matches[1]; |
||
0 ignored issues
–
show
The property
$blobOctetsLeft was declared of type integer , but $matches[1] is of type string . Maybe add a type cast?
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. $answer = 42;
$correct = false;
$correct = (bool) $answer;
![]() |
|||
437 | } |
||
438 | @list($tag, $line) = @explode(' ', $rawLine, 2); |
||
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||
439 | @list($type, $restLine) = @explode(' ', $line, 2); |
||
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||
440 | |||
441 | if ($this->state == self::STATE_CONNECTING) { |
||
442 | if ($this->startsWith($rawLine, '* OK')) { |
||
443 | $this->state = self::STATE_CONNECTED; |
||
444 | $this->connected = true; |
||
445 | } else { |
||
446 | $this->log("IMAP hello failed"); |
||
447 | $this->finish(); |
||
448 | return; |
||
449 | } |
||
450 | if ($this->onConnected) { |
||
451 | $this->onConnected->executeAll($this->connected ? $this : false); |
||
452 | $this->onConnected = null; |
||
453 | } |
||
454 | return; |
||
455 | } elseif ($this->state != self::STATE_CONNECTING) { |
||
456 | if ($tag === '*') { |
||
457 | $this->lines[] = $line; |
||
458 | continue; |
||
459 | } |
||
460 | if (!in_array($type, ['OK', 'BAD', 'NO'])) { |
||
461 | $this->lines[] = $rawLine; |
||
462 | continue; |
||
463 | } |
||
464 | $this->lines[] = $line; |
||
465 | $this->onCommand($tag, $type, $line, $this->lines, $this->blob); |
||
466 | $this->lines = []; |
||
467 | } |
||
468 | } |
||
469 | } |
||
470 | |||
471 | /** |
||
472 | * Count messages all messages in current box |
||
473 | * @param null $flags |
||
474 | */ |
||
475 | public function countMessages($cb, $flags = null) |
||
476 | { |
||
477 | $this->onResponse->push($cb); |
||
478 | if ($flags === null) { |
||
479 | $this->searchMessages(['ALL'], self::TAG_COUNT); |
||
480 | return; |
||
481 | } |
||
482 | $params = []; |
||
483 | foreach ((array) $flags as $flag) { |
||
484 | if (isset($this->searchFlags[$flag])) { |
||
485 | $params[] = $this->searchFlags[$flag]; |
||
486 | } else { |
||
487 | $params[] = 'KEYWORD'; |
||
488 | $params[] = $this->escapeString($flag); |
||
489 | } |
||
490 | } |
||
491 | $this->searchMessages($params, self::TAG_COUNT); |
||
492 | } |
||
493 | |||
494 | /** |
||
495 | * get a list of messages with number and size |
||
496 | * @param int $uid number of message |
||
0 ignored issues
–
show
Should the type for parameter
$uid not be integer|null ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types. ![]() |
|||
497 | */ |
||
498 | View Code Duplication | public function getSize($cb, $uid = null) |
|
0 ignored issues
–
show
This method seems to be duplicated in 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. ![]() |
|||
499 | { |
||
500 | $this->onResponse->push($cb); |
||
501 | if ($uid) { |
||
0 ignored issues
–
show
The expression
$uid of type integer|null is loosely compared to true ; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.
In PHP, under loose comparison (like For 0 == false // true
0 == null // true
123 == false // false
123 == null // false
// It is often better to use strict comparison
0 === false // false
0 === null // false
![]() |
|||
502 | $this->fetch('RFC822.SIZE', $uid, null, true, self::TAG_SIZE); |
||
0 ignored issues
–
show
'RFC822.SIZE' is of type string , but the function expects a array .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
503 | } else { |
||
504 | $this->fetch('RFC822.SIZE', 1, INF, true, self::TAG_SIZE); |
||
0 ignored issues
–
show
'RFC822.SIZE' is of type string , but the function expects a array .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
505 | } |
||
506 | } |
||
507 | |||
508 | /** |
||
509 | * Fetch a message |
||
510 | * @param int $uid unique number of message |
||
511 | */ |
||
512 | public function getRawMessage($cb, $uid, $byUid = true) |
||
513 | { |
||
514 | $this->onResponse->push($cb); |
||
515 | $this->fetch(['FLAGS', 'BODY[]'], $uid, null, $byUid, self::TAG_GETRAWMESSAGE); |
||
516 | } |
||
517 | |||
518 | /* |
||
519 | * Get raw header of message or part |
||
520 | * @param int $uid unique number of message |
||
521 | */ |
||
522 | public function getRawHeader($cb, $uid, $byUid = true) |
||
523 | { |
||
524 | $this->onResponse->push($cb); |
||
525 | $this->fetch(['FLAGS', 'RFC822.HEADER'], $uid, null, $byUid, self::TAG_GETRAWHEADER); |
||
526 | } |
||
527 | |||
528 | /* |
||
529 | * Get raw content of message or part |
||
530 | * |
||
531 | * @param int $uid number of message |
||
532 | */ |
||
533 | public function getRawContent($cb, $uid, $byUid = true) |
||
534 | { |
||
535 | $this->onResponse->push($cb); |
||
536 | $this->fetch(['FLAGS', 'RFC822.TEXT'], $uid, null, $byUid, self::TAG_GETRAWCONTENT); |
||
537 | } |
||
538 | |||
539 | /** |
||
540 | * get unique id for one or all messages |
||
541 | * |
||
542 | * @param int|null $id message number |
||
543 | */ |
||
544 | View Code Duplication | public function getUniqueId($cb, $id = null) |
|
0 ignored issues
–
show
This method seems to be duplicated in 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. ![]() |
|||
545 | { |
||
546 | $this->onResponse->push($cb); |
||
547 | if ($id) { |
||
0 ignored issues
–
show
The expression
$id of type integer|null is loosely compared to true ; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.
In PHP, under loose comparison (like For 0 == false // true
0 == null // true
123 == false // false
123 == null // false
// It is often better to use strict comparison
0 === false // false
0 === null // false
![]() |
|||
548 | $this->fetch('UID', $id, null, false, self::TAG_GETUID); |
||
0 ignored issues
–
show
'UID' is of type string , but the function expects a array .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
549 | } else { |
||
550 | $this->fetch('UID', 1, INF, false, self::TAG_GETUID); |
||
0 ignored issues
–
show
'UID' is of type string , but the function expects a array .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
551 | } |
||
552 | } |
||
553 | |||
554 | /** |
||
555 | * create a new folder (and parent folders if needed) |
||
556 | * |
||
557 | * @param string $folder folder name |
||
558 | * @return bool success |
||
0 ignored issues
–
show
|
|||
559 | */ |
||
560 | public function createFolder($cb, $folder, $parentFolder = null) |
||
561 | { |
||
562 | $this->onResponse->push($cb); |
||
563 | if ($parentFolder) { |
||
564 | $folder = $parentFolder . '/' . $folder ; |
||
565 | } |
||
566 | $this->writeln(self::TAG_CREATEFOLDER . " CREATE ".$this->escapeString($folder)); |
||
567 | } |
||
568 | |||
569 | /** |
||
570 | * remove a folder |
||
571 | * |
||
572 | * @param string $name name or instance of folder |
||
0 ignored issues
–
show
There is no parameter named
$name . Was it maybe removed?
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. Consider the following example. The parameter /**
* @param array $germany
* @param array $island
* @param array $italy
*/
function finale($germany, $island) {
return "2:1";
}
The most likely cause is that the parameter was removed, but the annotation was not. ![]() |
|||
573 | */ |
||
574 | public function removeFolder($cb, $folder) |
||
575 | { |
||
576 | $this->onResponse->push($cb); |
||
577 | $this->writeln(self::TAG_DELETEFOLDER . " DELETE ".$this->escapeString($folder)); |
||
578 | } |
||
579 | |||
580 | /** |
||
581 | * rename and/or move folder |
||
582 | * @param string $oldName name or instance of folder |
||
583 | * @param string $newName new global name of folder |
||
584 | */ |
||
585 | public function renameFolder($cb, $oldName, $newName) |
||
586 | { |
||
587 | $this->onResponse->push($cb); |
||
588 | $this->writeln(self::TAG_RENAMEFOLDER . " RENAME " |
||
589 | .$this->escapeString($oldName)." ".$this->escapeString($newName)); |
||
590 | } |
||
591 | |||
592 | /** |
||
593 | * Remove a message from server. |
||
594 | * @param int $uid unique number of message |
||
595 | */ |
||
596 | public function removeMessage($cb, $uid) |
||
597 | { |
||
598 | $this->onResponse->push($cb); |
||
599 | $this->store([self::FLAG_DELETED], $uid, null, '+', true, self::TAG_DELETEMESSAGE); |
||
600 | } |
||
601 | |||
602 | /** |
||
603 | * logout of imap server |
||
604 | */ |
||
605 | public function logout($cb = null) |
||
606 | { |
||
607 | if ($cb) { |
||
608 | $this->onResponse->push($cb); |
||
609 | } |
||
610 | $this->writeln(self::TAG_LOGOUT . " LOGOUT"); |
||
611 | } |
||
612 | |||
613 | public function onFinish() |
||
614 | { |
||
615 | $this->onResponse->executeAll(false); |
||
616 | parent::onFinish(); |
||
617 | } |
||
618 | } |
||
619 |
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.