Completed
Push — master ( ce0d07...ed5780 )
by Lars
04:08
created

BounceMailHandler   D

Complexity

Total Complexity 95

Size/Duplication

Total Lines 809
Duplicated Lines 5.56 %

Coupling/Cohesion

Components 1
Dependencies 0

Test Coverage

Coverage 36.72%

Importance

Changes 10
Bugs 4 Features 3
Metric Value
wmc 95
c 10
b 4
f 3
lcom 1
cbo 0
dl 45
loc 809
ccs 123
cts 335
cp 0.3672
rs 4.4444

9 Methods

Rating   Name   Duplication   Size   Complexity  
A getVersion() 0 4 1
C openMailbox() 0 35 7
C globalDelete() 0 50 7
A output() 0 10 3
B openLocal() 0 21 5
F processMailbox() 0 182 36
A isParameter() 0 14 4
F processBounce() 45 146 23
C mailboxExist() 0 47 9

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like BounceMailHandler often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use BounceMailHandler, and based on these observations, apply Extract Interface, too.

1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 32 and the first side effect is on line 19.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 * Bounce Mail Handler (formerly known as BMH and PHPMailer-BMH)
4
 *
5
 * @copyright 2008-2009 Andry Prevost. All Rights Reserved.
6
 * @copyright 2011-2012 Anthon Pang.
7
 * @copyright 2015-2015 Lars Moelleken.
8
 *
9
 * @license   GPL
10
 *
11
 * @package   BounceMailHandler
12
 *
13
 * @author    Andy Prevost <[email protected]>
14
 * @author    Anthon Pang <[email protected]>
15
 * @author    Lars Moelleken <[email protected]>
16
 */
17
namespace BounceMailHandler;
18
19
require_once __DIR__ . '/phpmailer-bmh_rules.php';
20
21
/**
22
 * BounceMailHandler class
23
 *
24
 * BounceMailHandler is a PHP program to check your IMAP/POP3 inbox and
25
 * delete all 'hard' bounced emails. It features a callback function where
26
 * you can create a custom action. This provides you the ability to write
27
 * a script to match your database records and either set inactive or
28
 * delete records with email addresses that match the 'hard' bounce results.
29
 *
30
 * @package BounceMailHandler
31
 */
32
class BounceMailHandler
33
{
34
  const VERBOSE_QUIET  = 0; // suppress output
35
  const VERBOSE_SIMPLE = 1; // simple report
36
  const VERBOSE_REPORT = 2; // detailed report
37
  const VERBOSE_DEBUG  = 3; // detailed report plus debug info
38
39
  /**
40
   * mail-server
41
   *
42
   * @var string
43
   */
44
  public $mailhost = 'localhost';
45
46
  /**
47
   * the username of mailbox
48
   *
49
   * @var string
50
   */
51
  public $mailboxUserName;
52
53
  /**
54
   * the password needed to access mailbox
55
   *
56
   * @var string
57
   */
58
  public $mailboxPassword;
59
60
  /**
61
   * the last error msg
62
   *
63
   * @var string
64
   */
65
  public $errorMessage;
66
67
  /**
68
   * maximum limit messages processed in one batch
69
   *
70
   * @var int
71
   */
72
  public $maxMessages = 3000;
73
74
  /**
75
   * callback Action function name the function that handles the bounce mail. Parameters:
76
   *
77
   * int     $msgnum        the message number returned by Bounce Mail Handler
78
   * string  $bounce_type   the bounce type:
79
   *       'antispam',
80
   *       'autoreply',
81
   *       'concurrent',
82
   *       'content_reject',
83
   *       'command_reject',
84
   *       'internal_error',
85
   *       'defer',
86
   *       'delayed'
87
   *       =>
88
   *       array(
89
   *           'remove' => 0,
90
   *           'bounce_type' => 'temporary'
91
   *       ),
92
   *       'dns_loop',
93
   *       'dns_unknown',
94
   *       'full',
95
   *       'inactive',
96
   *       'latin_only',
97
   *       'other',
98
   *       'oversize',
99
   *       'outofoffice',
100
   *       'unknown',
101
   *       'unrecognized',
102
   *       'user_reject',
103
   *       'warning'
104
   * string  $email         the target email address string  $subject       the subject, ignore now string  $xheader
105
   * the XBounceHeader from the mail
106
   * 1 or 0  $remove        delete status, 0 is not deleted, 1 is deleted
107
   * string  $rule_no       bounce mail detect rule no.
108
   * string  $rule_cat      bounce mail detect rule category
109
   * int     $totalFetched  total number of messages in the mailbox
110
   *
111
   * @var mixed
112
   */
113
  public $actionFunction = 'callbackAction';
114
115
  /**
116
   * test-mode, if true will not delete messages
117
   *
118
   * @var boolean
119
   */
120
  public $testMode = false;
121
122
  /**
123
   * purge the unknown messages (or not)
124
   *
125
   * @var boolean
126
   */
127
  public $purgeUnprocessed = false;
128
129
  /**
130
   * control the debug output, default is VERBOSE_SIMPLE
131
   *
132
   * @var int
133
   */
134
  public $verbose = self::VERBOSE_SIMPLE;
135
136
  /**
137
   * control the failed DSN rules output
138
   *
139
   * @var boolean
140
   */
141
  public $debugDsnRule = false;
142
143
  /**
144
   * control the failed BODY rules output
145
   *
146
   * @var boolean
147
   */
148
  public $debugBodyRule = false;
149
150
  /**
151
   * Control the method to process the mail header
152
   * if set true, uses the imap_fetchstructure function
153
   * otherwise, detect message type directly from headers,
154
   * a bit faster than imap_fetchstructure function and take less resources.
155
   *
156
   * however - the difference is negligible
157
   *
158
   * @var boolean
159
   */
160
  public $useFetchstructure = true;
161
162
  /**
163
   * If disableDelete is equal to true, it will disable the delete function.
164
   *
165
   * @var boolean
166
   */
167
  public $disableDelete = false;
168
169
  /**
170
   * defines new line ending
171
   *
172
   * @var string
173
   */
174
  public $bmhNewLine = "<br />\n";
175
176
  /**
177
   * defines port number, default is '143', other common choices are '110' (pop3), '993' (gmail)
178
   *
179
   * @var integer
180
   */
181
  public $port = 143;
182
183
  /**
184
   * defines service, default is 'imap', choice includes 'pop3'
185
   *
186
   * @var string
187
   */
188
  public $service = 'imap';
189
190
  /**
191
   * defines service option, default is 'notls', other choices are 'tls', 'ssl'
192
   *
193
   * @var string
194
   */
195
  public $serviceOption = 'notls';
196
197
  /**
198
   * mailbox type, default is 'INBOX', other choices are (Tasks, Spam, Replies, etc.)
199
   *
200
   * @var string
201
   */
202
  public $boxname = 'INBOX';
203
204
  /**
205
   * determines if soft bounces will be moved to another mailbox folder
206
   *
207
   * @var boolean
208
   */
209
  public $moveSoft = false;
210
211
  /**
212
   * mailbox folder to move soft bounces to, default is 'soft'
213
   *
214
   * @var string
215
   */
216
  public $softMailbox = 'INBOX.soft';
217
218
  /**
219
   * determines if hard bounces will be moved to another mailbox folder
220
   *
221
   * NOTE: If true, this will disable delete and perform a move operation instead
222
   *
223
   * @var boolean
224
   */
225
  public $moveHard = false;
226
227
  /**
228
   * mailbox folder to move hard bounces to, default is 'hard'
229
   *
230
   * @var string
231
   */
232
  public $hardMailbox = 'INBOX.hard';
233
234
  /**
235
   * deletes messages globally prior to date in variable
236
   *
237
   * NOTE: excludes any message folder that includes 'sent' in mailbox name
238
   * format is same as MySQL: 'yyyy-mm-dd'
239
   * if variable is blank, will not process global delete
240
   *
241
   * @var string
242
   */
243
  public $deleteMsgDate = '';
244
245
  /**
246
   * Holds Bounce Mail Handler version.
247
   *
248
   * @var string
249
   */
250
  private $version = '5.3-dev';
251
252
  /**
253
   * (internal variable)
254
   *
255
   * The resource handler for the opened mailbox (POP3/IMAP/NNTP/etc.)
256
   *
257
   * @var resource
258
   */
259
  private $mailboxLink = false;
260
261
  /**
262
   * get version
263
   *
264
   * @return string
265
   */
266
  public function getVersion()
267
  {
268
    return $this->version;
269
  }
270
271
  /**
272
   * open a mail box
273
   *
274
   * @return boolean
275
   */
276
  public function openMailbox()
277
  {
278
    // before starting the processing, let's check the delete flag and do global deletes if true
279
    if (trim($this->deleteMsgDate) != '') {
280
      echo 'processing global delete based on date of ' . $this->deleteMsgDate . '<br />';
281
      $this->globalDelete();
282
    }
283
284
    // disable move operations if server is Gmail ... Gmail does not support mailbox creation
285
    if (stristr($this->mailhost, 'gmail')) {
286
      $this->moveSoft = false;
287
      $this->moveHard = false;
288
    }
289
290
    $port = $this->port . '/' . $this->service . '/' . $this->serviceOption;
291
292
    set_time_limit(6000);
293
294
    if (!$this->testMode) {
295
      $this->mailboxLink = imap_open('{' . $this->mailhost . ':' . $port . '}' . $this->boxname, $this->mailboxUserName, $this->mailboxPassword, CL_EXPUNGE | ($this->testMode ? OP_READONLY : 0));
296
    } else {
297
      $this->mailboxLink = imap_open('{' . $this->mailhost . ':' . $port . '}' . $this->boxname, $this->mailboxUserName, $this->mailboxPassword, ($this->testMode ? OP_READONLY : 0));
298
    }
299
300
    if (!$this->mailboxLink) {
301
      $this->errorMessage = 'Cannot create ' . $this->service . ' connection to ' . $this->mailhost . $this->bmhNewLine . 'Error MSG: ' . imap_last_error();
302
      $this->output();
303
304
      return false;
305
    } else {
306
      $this->output('Connected to: ' . $this->mailhost . ' (' . $this->mailboxUserName . ')');
0 ignored issues
show
Documentation introduced by
'Connected to: ' . $this...->mailboxUserName . ')' is of type string, but the function expects a boolean.

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);
Loading history...
307
308
      return true;
309
    }
310
  }
311
312
  /**
313
   * Function to delete messages in a mailbox, based on date
314
   *
315
   * NOTE: this is global ... will affect all mailboxes except any that have 'sent' in the mailbox name
316
   */
317
  public function globalDelete()
318
  {
319
    $dateArr = explode('-', $this->deleteMsgDate); // date format is yyyy-mm-dd
320
    $delDate = mktime(0, 0, 0, $dateArr[1], $dateArr[2], $dateArr[0]);
321
322
    $port = $this->port . '/' . $this->service . '/' . $this->serviceOption;
323
    $mboxt = imap_open('{' . $this->mailhost . ':' . $port . '}', $this->mailboxUserName, $this->mailboxPassword, OP_HALFOPEN);
324
325
    if ($mboxt === false) {
326
      return false;
327
    }
328
329
    $list = imap_getmailboxes($mboxt, '{' . $this->mailhost . ':' . $port . '}', '*');
330
331
    if (is_array($list)) {
332
      foreach ($list as $key => $val) {
333
        // get the mailbox name only
334
        $nameArr = explode('}', imap_utf7_decode($val->name));
335
        $nameRaw = $nameArr[count($nameArr) - 1];
336
337
        if (!stristr($nameRaw, 'sent')) {
338
          $mboxd = imap_open('{' . $this->mailhost . ':' . $port . '}' . $nameRaw, $this->mailboxUserName, $this->mailboxPassword, CL_EXPUNGE);
339
          $messages = imap_sort($mboxd, SORTDATE, 0);
340
          $i = 0;
341
342
          foreach ($messages as $message) {
343
            $header = imap_header($mboxd, $message);
344
345
            // purge if prior to global delete date
346
            if ($header->udate < $delDate) {
347
              imap_delete($mboxd, $message);
348
            }
349
            $i++;
350
          }
351
352
          imap_expunge($mboxd);
353
          imap_close($mboxd);
354
        }
355
      }
356
357
      imap_close($mboxt);
358
359
      return true;
360
361
    } else {
362
      imap_close($mboxt);
363
364
      return false;
365
    }
366
  }
367
368
  /**
369
   * output additional msg for debug
370
   *
371
   * @param bool|false $msg          if not given, output the last error msg
372
   * @param int        $verboseLevel the output level of this message
373
   */
374 2
  public function output($msg = false, $verboseLevel = self::VERBOSE_SIMPLE)
375
  {
376 2
    if ($this->verbose >= $verboseLevel) {
377 2
      if (empty($msg)) {
378
        echo $this->errorMessage . $this->bmhNewLine;
379
      } else {
380 2
        echo $msg . $this->bmhNewLine;
381
      }
382 2
    }
383 2
  }
384
385
  /**
386
   * open a mail box in local file system
387
   *
388
   * @param string $filePath The local mailbox file path
389
   *
390
   * @return boolean
391
   */
392 2
  public function openLocal($filePath)
393
  {
394 2
    set_time_limit(6000);
395
396 2
    if (!$this->testMode) {
397
      $this->mailboxLink = imap_open($filePath, '', '', CL_EXPUNGE | ($this->testMode ? OP_READONLY : 0));
398
    } else {
399 2
      $this->mailboxLink = imap_open($filePath, '', '', ($this->testMode ? OP_READONLY : 0));
400
    }
401
402 2
    if (!$this->mailboxLink) {
403
      $this->errorMessage = 'Cannot open the mailbox file to ' . $filePath . $this->bmhNewLine . 'Error MSG: ' . imap_last_error();
404
      $this->output();
405
406
      return false;
407
    } else {
408 2
      $this->output('Opened ' . $filePath);
0 ignored issues
show
Documentation introduced by
'Opened ' . $filePath is of type string, but the function expects a boolean.

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);
Loading history...
409
410 2
      return true;
411
    }
412
  }
413
414
  /**
415
   * process the messages in a mailbox
416
   *
417
   * @param bool|false $max $max maximum limit messages processed in one batch, if not given uses the property
418
   *                        $maxMessages
419
   *
420
   * @return bool
421
   */
422 2
  public function processMailbox($max = false)
423
  {
424 2
    if (empty($this->actionFunction) || !is_callable($this->actionFunction)) {
425
      $this->errorMessage = 'Action function not found!';
426
      $this->output();
427
428
      return false;
429
    }
430
431 2
    if ($this->moveHard && ($this->disableDelete === false)) {
432
      $this->disableDelete = true;
433
    }
434
435 2
    if (!empty($max)) {
436
      $this->maxMessages = $max;
0 ignored issues
show
Documentation Bug introduced by
The property $maxMessages was declared of type integer, but $max is of type boolean. 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;
Loading history...
437
    }
438
439
    // initialize counters
440 2
    $totalCount = imap_num_msg($this->mailboxLink);
441 2
    $fetchedCount = $totalCount;
442 2
    $processedCount = 0;
443 2
    $unprocessedCount = 0;
444 2
    $deletedCount = 0;
445 2
    $movedCount = 0;
446 2
    $this->output('Total: ' . $totalCount . ' messages ');
0 ignored issues
show
Documentation introduced by
'Total: ' . $totalCount . ' messages ' is of type string, but the function expects a boolean.

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);
Loading history...
447
448
    // process maximum number of messages
449 2
    if ($fetchedCount > $this->maxMessages) {
450
      $fetchedCount = $this->maxMessages;
451
      $this->output('Processing first ' . $fetchedCount . ' messages ');
0 ignored issues
show
Documentation introduced by
'Processing first ' . $f...hedCount . ' messages ' is of type string, but the function expects a boolean.

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);
Loading history...
452
    }
453
454 2
    if ($this->testMode) {
455 2
      $this->output('Running in test mode, not deleting messages from mailbox<br />');
0 ignored issues
show
Documentation introduced by
'Running in test mode, n...ges from mailbox<br />' is of type string, but the function expects a boolean.

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);
Loading history...
456 2
    } else {
457
      if ($this->disableDelete) {
458
        if ($this->moveHard) {
459
          $this->output('Running in move mode<br />');
0 ignored issues
show
Documentation introduced by
'Running in move mode<br />' is of type string, but the function expects a boolean.

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);
Loading history...
460
        } else {
461
          $this->output('Running in disableDelete mode, not deleting messages from mailbox<br />');
0 ignored issues
show
Documentation introduced by
'Running in disableDelet...ges from mailbox<br />' is of type string, but the function expects a boolean.

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);
Loading history...
462
        }
463
      } else {
464
        $this->output('Processed messages will be deleted from mailbox<br />');
0 ignored issues
show
Documentation introduced by
'Processed messages will...ted from mailbox<br />' is of type string, but the function expects a boolean.

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);
Loading history...
465
      }
466
    }
467
468 2
    for ($x = 1; $x <= $fetchedCount; $x++) {
469
470
      // fetch the messages one at a time
471 2
      if ($this->useFetchstructure) {
472 2
        $structure = imap_fetchstructure($this->mailboxLink, $x);
473
474
        if (
475 2
            $structure->type == 1
476 2
            &&
477 2
            $structure->ifsubtype
478 2
            &&
479 2
            strtoupper($structure->subtype) == 'REPORT'
480 2
            &&
481 2
            $structure->ifparameters
482 2
            &&
483 2
            $this->isParameter($structure->parameters, 'REPORT-TYPE', 'delivery-status')
484 2
        ) {
485 2
          $processed = $this->processBounce($x, 'DSN', $totalCount);
486 2
        } else {
487
          // not standard DSN msg
488 2
          $this->output('Msg #' . $x . ' is not a standard DSN message', self::VERBOSE_REPORT);
0 ignored issues
show
Documentation introduced by
'Msg #' . $x . ' is not a standard DSN message' is of type string, but the function expects a boolean.

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);
Loading history...
489
490 2
          if ($this->debugBodyRule) {
491
            if ($structure->ifdescription) {
492
              $this->output("  Content-Type : {$structure->description}", self::VERBOSE_DEBUG);
493
            } else {
494
              $this->output('  Content-Type : unsupported', self::VERBOSE_DEBUG);
0 ignored issues
show
Documentation introduced by
' Content-Type : unsupported' is of type string, but the function expects a boolean.

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);
Loading history...
495
            }
496
          }
497
498 2
          $processed = $this->processBounce($x, 'BODY', $totalCount);
499
        }
500 2
      } else {
501
        $header = imap_fetchheader($this->mailboxLink, $x);
502
503
        // Could be multi-line, if the new line begins with SPACE or HTAB
504
        if (preg_match("/Content-Type:((?:[^\n]|\n[\t ])+)(?:\n[^\t ]|$)/i", $header, $match)) {
505
          if (preg_match("/multipart\/report/i", $match[1]) && preg_match("/report-type=[\"']?delivery-status[\"']?/i", $match[1])) {
506
            // standard DSN msg
507
            $processed = $this->processBounce($x, 'DSN', $totalCount);
508
          } else {
509
            // not standard DSN msg
510
            $this->output('Msg #' . $x . ' is not a standard DSN message', self::VERBOSE_REPORT);
0 ignored issues
show
Documentation introduced by
'Msg #' . $x . ' is not a standard DSN message' is of type string, but the function expects a boolean.

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);
Loading history...
511
512
            if ($this->debugBodyRule) {
513
              $this->output("  Content-Type : {$match[1]}", self::VERBOSE_DEBUG);
514
            }
515
516
            $processed = $this->processBounce($x, 'BODY', $totalCount);
517
          }
518
        } else {
519
          // didn't get content-type header
520
          $this->output('Msg #' . $x . ' is not a well-formatted MIME mail, missing Content-Type', self::VERBOSE_REPORT);
0 ignored issues
show
Documentation introduced by
'Msg #' . $x . ' is not ..., missing Content-Type' is of type string, but the function expects a boolean.

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);
Loading history...
521
522
          if ($this->debugBodyRule) {
523
            $this->output('  Headers: ' . $this->bmhNewLine . $header . $this->bmhNewLine, self::VERBOSE_DEBUG);
0 ignored issues
show
Documentation introduced by
' Headers: ' . $this->b...der . $this->bmhNewLine is of type string, but the function expects a boolean.

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);
Loading history...
524
          }
525
526
          $processed = $this->processBounce($x, 'BODY', $totalCount);
527
        }
528
      }
529
530 2
      $deleteFlag[$x] = false;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$deleteFlag was never initialized. Although not strictly required by PHP, it is generally a good practice to add $deleteFlag = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
531 2
      $moveFlag[$x] = false;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$moveFlag was never initialized. Although not strictly required by PHP, it is generally a good practice to add $moveFlag = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
532
533 2
      if ($processed) {
534 2
        $processedCount++;
535
536 2
        if (!$this->disableDelete) {
537
          // delete the bounce if not in disableDelete mode
538 2
          if (!$this->testMode) {
539
            /** @noinspection PhpUsageOfSilenceOperatorInspection */
540
            @imap_delete($this->mailboxLink, $x);
0 ignored issues
show
Security Best Practice introduced by
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.');
}
Loading history...
541
          }
542
543 2
          $deleteFlag[$x] = true;
0 ignored issues
show
Bug introduced by
The variable $deleteFlag does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
544 2
          $deletedCount++;
545 2
        } elseif ($this->moveHard) {
546
          // check if the move directory exists, if not create it
547
          if (!$this->testMode) {
548
            $this->mailboxExist($this->hardMailbox);
549
          }
550
551
          // move the message
552
          if (!$this->testMode) {
553
            /** @noinspection PhpUsageOfSilenceOperatorInspection */
554
            @imap_mail_move($this->mailboxLink, $x, $this->hardMailbox);
0 ignored issues
show
Security Best Practice introduced by
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.');
}
Loading history...
555
          }
556
557
          $moveFlag[$x] = true;
0 ignored issues
show
Bug introduced by
The variable $moveFlag does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
558
          $movedCount++;
559
        } elseif ($this->moveSoft) {
560
          // check if the move directory exists, if not create it
561
          if (!$this->testMode) {
562
            $this->mailboxExist($this->softMailbox);
563
          }
564
565
          // move the message
566
          if (!$this->testMode) {
567
            /** @noinspection PhpUsageOfSilenceOperatorInspection */
568
            @imap_mail_move($this->mailboxLink, $x, $this->softMailbox);
0 ignored issues
show
Security Best Practice introduced by
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.');
}
Loading history...
569
          }
570
571
          $moveFlag[$x] = true;
572
          $movedCount++;
573
        }
574 2
      } else {
575
        // not processed
576 2
        $unprocessedCount++;
577 2
        if (!$this->disableDelete && $this->purgeUnprocessed) {
578
          // delete this bounce if not in disableDelete mode, and the flag BOUNCE_PURGE_UNPROCESSED is set
579
          if (!$this->testMode) {
580
            /** @noinspection PhpUsageOfSilenceOperatorInspection */
581
            @imap_delete($this->mailboxLink, $x);
0 ignored issues
show
Security Best Practice introduced by
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.');
}
Loading history...
582
          }
583
584
          $deleteFlag[$x] = true;
585
          $deletedCount++;
586
        }
587
      }
588
589 2
      flush();
590 2
    }
591
592 2
    $this->output($this->bmhNewLine . 'Closing mailbox, and purging messages');
0 ignored issues
show
Documentation introduced by
$this->bmhNewLine . 'Clo..., and purging messages' is of type string, but the function expects a boolean.

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);
Loading history...
593
594 2
    imap_close($this->mailboxLink);
595
596 2
    $this->output('Read: ' . $fetchedCount . ' messages');
0 ignored issues
show
Documentation introduced by
'Read: ' . $fetchedCount . ' messages' is of type string, but the function expects a boolean.

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);
Loading history...
597 2
    $this->output($processedCount . ' action taken');
0 ignored issues
show
Documentation introduced by
$processedCount . ' action taken' is of type string, but the function expects a boolean.

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);
Loading history...
598 2
    $this->output($unprocessedCount . ' no action taken');
0 ignored issues
show
Documentation introduced by
$unprocessedCount . ' no action taken' is of type string, but the function expects a boolean.

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);
Loading history...
599 2
    $this->output($deletedCount . ' messages deleted');
0 ignored issues
show
Documentation introduced by
$deletedCount . ' messages deleted' is of type string, but the function expects a boolean.

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);
Loading history...
600 2
    $this->output($movedCount . ' messages moved');
0 ignored issues
show
Documentation introduced by
$movedCount . ' messages moved' is of type string, but the function expects a boolean.

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);
Loading history...
601
602 2
    return true;
603
  }
604
605
  /**
606
   * Function to determine if a particular value is found in a imap_fetchstructure key.
607
   *
608
   * @param array  $currParameters imap_fetstructure parameters
609
   * @param string $varKey         imap_fetstructure key
610
   * @param string $varValue       value to check for
611
   *
612
   * @return boolean
613
   */
614 2
  public function isParameter($currParameters, $varKey, $varValue)
615
  {
616 2
    foreach ($currParameters as $object) {
617
      if (
618 2
          strtolower($object->attribute) == strtolower($varKey)
619 2
          &&
620 2
          strtolower($object->value) == strtolower($varValue)
621 2
      ) {
622 2
        return true;
623
      }
624
    }
625
626
    return false;
627
  }
628
629
  /**
630
   * Function to process each individual message.
631
   *
632
   * @param int    $pos          message number
633
   * @param string $type         DNS or BODY type
634
   * @param string $totalFetched total number of messages in mailbox
635
   *
636
   * @return boolean
637
   */
638 2
  public function processBounce($pos, $type, $totalFetched)
639
  {
640 2
    $header = imap_header($this->mailboxLink, $pos);
641 2
    $subject = isset($header->subject) ? strip_tags($header->subject) : '[NO SUBJECT]';
642 2
    $body = '';
643 2
    $headerFull = imap_fetchheader($this->mailboxLink, $pos);
644 2
    $bodyFull = imap_body($this->mailboxLink, $pos);
645
646 2
    if ($type == 'DSN') {
647
      // first part of DSN (Delivery Status Notification), human-readable explanation
648 2
      $dsnMsg = imap_fetchbody($this->mailboxLink, $pos, '1');
649 2
      $dsnMsgStructure = imap_bodystruct($this->mailboxLink, $pos, '1');
650
651 2
      if ($dsnMsgStructure->encoding == 4) {
652 1
        $dsnMsg = quoted_printable_decode($dsnMsg);
653 2
      } elseif ($dsnMsgStructure->encoding == 3) {
654
        $dsnMsg = base64_decode($dsnMsg);
655
      }
656
657
      // second part of DSN (Delivery Status Notification), delivery-status
658 2
      $dsnReport = imap_fetchbody($this->mailboxLink, $pos, '2');
659
660
      // process bounces by rules
661 2
      $result = bmhDSNRules($dsnMsg, $dsnReport, $this->debugDsnRule);
662 2
    } elseif ($type == 'BODY') {
663 2
      $structure = imap_fetchstructure($this->mailboxLink, $pos);
664
665 2
      switch ($structure->type) {
666 2
        case 0: // Content-type = text
667 2
          $body = imap_fetchbody($this->mailboxLink, $pos, '1');
668 2
          $result = bmhBodyRules($body, $structure, $this->debugBodyRule);
0 ignored issues
show
Documentation introduced by
$structure is of type object, but the function expects a string.

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);
Loading history...
669 2
          break;
670
671
        case 1: // Content-type = multipart
672
          $body = imap_fetchbody($this->mailboxLink, $pos, '1');
673
674
          // Detect encoding and decode - only base64
675
          if ($structure->parts[0]->encoding == 4) {
676
            $body = quoted_printable_decode($body);
677
          } elseif ($structure->parts[0]->encoding == 3) {
678
            $body = base64_decode($body);
679
          }
680
681
          $result = bmhBodyRules($body, $structure, $this->debugBodyRule);
0 ignored issues
show
Documentation introduced by
$structure is of type object, but the function expects a string.

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);
Loading history...
682
          break;
683
684
        case 2: // Content-type = message
685
          $body = imap_body($this->mailboxLink, $pos);
686
687
          if ($structure->encoding == 4) {
688
            $body = quoted_printable_decode($body);
689
          } elseif ($structure->encoding == 3) {
690
            $body = base64_decode($body);
691
          }
692
693
          $body = substr($body, 0, 1000);
694
          $result = bmhBodyRules($body, $structure, $this->debugBodyRule);
0 ignored issues
show
Documentation introduced by
$structure is of type object, but the function expects a string.

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);
Loading history...
695
          break;
696
697
        default: // unsupport Content-type
698
          $this->output('Msg #' . $pos . ' is unsupported Content-Type:' . $structure->type, self::VERBOSE_REPORT);
0 ignored issues
show
Documentation introduced by
'Msg #' . $pos . ' is un...pe:' . $structure->type is of type string, but the function expects a boolean.

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);
Loading history...
699
700
          return false;
701 2
      }
702 2
    } else {
703
      // internal error
704
      $this->errorMessage = 'Internal Error: unknown type';
705
706
      return false;
707
    }
708
709 2
    $email = $result['email'];
710 2
    $bounceType = $result['bounce_type'];
711
712 2
    if ($this->moveHard && $result['remove'] == 1) {
713
      $remove = 'moved (hard)';
714 2
    } elseif ($this->moveSoft && $result['remove'] == 1) {
715
      $remove = 'moved (soft)';
716 2
    } elseif ($this->disableDelete) {
717
      $remove = 0;
718
    } else {
719 2
      $remove = $result['remove'];
720
    }
721
722 2
    $ruleNumber = $result['rule_no'];
723 2
    $ruleCategory = $result['rule_cat'];
724 2
    $xheader = false;
725
726 2
    if ($ruleNumber === '0000') {
727
      // unrecognized
728
      if (
729 2
          trim($email) == ''
730 2
          &&
731 2
          property_exists($header, 'fromaddress') === true
732 2
      ) {
733 2
        $email = $header->fromaddress;
734 2
      }
735
736 2 View Code Duplication
      if ($this->testMode) {
0 ignored issues
show
Duplication introduced by
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.

Loading history...
737 2
        $this->output('Match: ' . $ruleNumber . ':' . $ruleCategory . '; ' . $bounceType . '; ' . $email);
0 ignored issues
show
Documentation introduced by
'Match: ' . $ruleNumber ...nceType . '; ' . $email is of type string, but the function expects a boolean.

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);
Loading history...
738 2
      } else {
739
        // code below will use the Callback function, but return no value
740
        $params = array(
741
            $pos,
742
            $bounceType,
743
            $email,
744
            $subject,
745
            $header,
746
            $remove,
747
            $ruleNumber,
748
            $ruleCategory,
749
            $totalFetched,
750
            $body,
751
            $headerFull,
752
            $bodyFull,
753
        );
754
        call_user_func_array($this->actionFunction, $params);
755
      }
756 2 View Code Duplication
    } else {
0 ignored issues
show
Duplication introduced by
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.

Loading history...
757
      // match rule, do bounce action
758 2
      if ($this->testMode) {
759 2
        $this->output('Match: ' . $ruleNumber . ':' . $ruleCategory . '; ' . $bounceType . '; ' . $email);
0 ignored issues
show
Documentation introduced by
'Match: ' . $ruleNumber ...nceType . '; ' . $email is of type string, but the function expects a boolean.

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);
Loading history...
760
761 2
        return true;
762
      } else {
763
        $params = array(
764
            $pos,
765
            $bounceType,
766
            $email,
767
            $subject,
768
            $xheader,
769
            $remove,
770
            $ruleNumber,
771
            $ruleCategory,
772
            $totalFetched,
773
            $body,
774
            $headerFull,
775
            $bodyFull,
776
        );
777
778
        return call_user_func_array($this->actionFunction, $params);
779
      }
780
    }
781
782 2
    return false;
783
  }
784
785
  /**
786
   * Function to check if a mailbox exists - if not found, it will create it.
787
   *
788
   * @param string  $mailbox the mailbox name, must be in 'INBOX.checkmailbox' format
789
   * @param boolean $create  whether or not to create the checkmailbox if not found, defaults to true
790
   *
791
   * @return boolean
792
   */
793
  public function mailboxExist($mailbox, $create = true)
794
  {
795
    if (trim($mailbox) == '' || strpos($mailbox, 'INBOX.') === false) {
796
      // this is a critical error with either the mailbox name blank or an invalid mailbox name
797
      // need to stop processing and exit at this point
798
      echo "Invalid mailbox name for move operation. Cannot continue.<br />\n";
799
      echo "TIP: the mailbox you want to move the message to must include 'INBOX.' at the start.<br />\n";
800
      exit();
0 ignored issues
show
Coding Style Compatibility introduced by
The method mailboxExist() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
801
    }
802
803
    $port = $this->port . '/' . $this->service . '/' . $this->serviceOption;
804
    $mbox = imap_open('{' . $this->mailhost . ':' . $port . '}', $this->mailboxUserName, $this->mailboxPassword, OP_HALFOPEN);
805
806
    if ($mbox === false) {
807
      return false;
808
    }
809
810
    $list = imap_getmailboxes($mbox, '{' . $this->mailhost . ':' . $port . '}', '*');
811
    $mailboxFound = false;
812
813
    if (is_array($list)) {
814
      foreach ($list as $key => $val) {
815
        // get the mailbox name only
816
        $nameArr = explode('}', imap_utf7_decode($val->name));
817
        $nameRaw = $nameArr[count($nameArr) - 1];
818
        if ($mailbox == $nameRaw) {
819
          $mailboxFound = true;
820
        }
821
      }
822
823
      if (($mailboxFound === false) && $create) {
824
        /** @noinspection PhpUsageOfSilenceOperatorInspection */
825
        @imap_createmailbox($mbox, imap_utf7_encode('{' . $this->mailhost . ':' . $port . '}' . $mailbox));
0 ignored issues
show
Security Best Practice introduced by
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.');
}
Loading history...
826
        imap_close($mbox);
827
828
        return true;
829
      } else {
830
        imap_close($mbox);
831
832
        return false;
833
      }
834
    } else {
835
      imap_close($mbox);
836
837
      return false;
838
    }
839
  }
840
}
841