Completed
Push — master ( 6d1a51...be646c )
by Lars
02:36
created

BounceMailHandler::processBounce()   F

Complexity

Conditions 25
Paths 964

Size

Total Lines 160
Code Lines 112

Duplication

Lines 51
Ratio 31.88 %

Code Coverage

Tests 50
CRAP Score 142.3367

Importance

Changes 11
Bugs 3 Features 5
Metric Value
cc 25
eloc 112
c 11
b 3
f 5
nc 964
nop 3
dl 51
loc 160
rs 2.2307
ccs 50
cts 117
cp 0.4274
crap 142.3367

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
   * Mailbox folder to move unprocessed mails
236
   * @var string
237
   */
238
  public $unprocessedBox = 'INBOX.unprocessed';
239
240
  /**
241
   * deletes messages globally prior to date in variable
242
   *
243
   * NOTE: excludes any message folder that includes 'sent' in mailbox name
244
   * format is same as MySQL: 'yyyy-mm-dd'
245
   * if variable is blank, will not process global delete
246
   *
247
   * @var string
248
   */
249
  public $deleteMsgDate = '';
250
251
  /**
252
   * Holds Bounce Mail Handler version.
253
   *
254
   * @var string
255
   */
256
  private $version = '5.3-dev';
257
258
  /**
259
   * (internal variable)
260
   *
261
   * The resource handler for the opened mailbox (POP3/IMAP/NNTP/etc.)
262
   *
263
   * @var resource
264
   */
265
  private $mailboxLink = false;
266
267
  /**
268
   * get version
269
   *
270
   * @return string
271
   */
272
  public function getVersion()
273
  {
274
    return $this->version;
275
  }
276
277
  /**
278
   * open a mail box
279
   *
280
   * @return boolean
281
   */
282
  public function openMailbox()
283
  {
284
    // before starting the processing, let's check the delete flag and do global deletes if true
285
    if (trim($this->deleteMsgDate) != '') {
286
      echo 'processing global delete based on date of ' . $this->deleteMsgDate . '<br />';
287
      $this->globalDelete();
288
    }
289
290
    // disable move operations if server is Gmail ... Gmail does not support mailbox creation
291
    if (false !== stripos($this->mailhost, 'gmail')) {
292
      $this->moveSoft = false;
293
      $this->moveHard = false;
294
    }
295
296
    $port = $this->port . '/' . $this->service . '/' . $this->serviceOption;
297
298
    set_time_limit(6000);
299
300
    if (!$this->testMode) {
301
      $this->mailboxLink = imap_open('{' . $this->mailhost . ':' . $port . '}' . $this->boxname, $this->mailboxUserName, $this->mailboxPassword, CL_EXPUNGE | ($this->testMode ? OP_READONLY : 0));
302
    } else {
303
      $this->mailboxLink = imap_open('{' . $this->mailhost . ':' . $port . '}' . $this->boxname, $this->mailboxUserName, $this->mailboxPassword, ($this->testMode ? OP_READONLY : 0));
304
    }
305
306
    if (!$this->mailboxLink) {
307
      $this->errorMessage = 'Cannot create ' . $this->service . ' connection to ' . $this->mailhost . $this->bmhNewLine . 'Error MSG: ' . imap_last_error();
308
      $this->output();
309
310
      return false;
311
    } else {
312
      $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...
313
314
      return true;
315
    }
316
  }
317
318
  /**
319
   * Function to delete messages in a mailbox, based on date
320
   *
321
   * NOTE: this is global ... will affect all mailboxes except any that have 'sent' in the mailbox name
322
   */
323
  public function globalDelete()
324
  {
325
    $dateArr = explode('-', $this->deleteMsgDate); // date format is yyyy-mm-dd
326
    $delDate = mktime(0, 0, 0, $dateArr[1], $dateArr[2], $dateArr[0]);
327
328
    $port = $this->port . '/' . $this->service . '/' . $this->serviceOption;
329
    $mboxt = imap_open('{' . $this->mailhost . ':' . $port . '}', $this->mailboxUserName, $this->mailboxPassword, OP_HALFOPEN);
330
331
    if ($mboxt === false) {
332
      return false;
333
    }
334
335
    $list = imap_getmailboxes($mboxt, '{' . $this->mailhost . ':' . $port . '}', '*');
336
337
    if (is_array($list)) {
338
      foreach ($list as $key => $val) {
339
        // get the mailbox name only
340
        $nameArr = explode('}', imap_utf7_decode($val->name));
341
        $nameRaw = $nameArr[count($nameArr) - 1];
342
343
        if (false === stripos($nameRaw, 'sent')) {
344
          $mboxd = imap_open('{' . $this->mailhost . ':' . $port . '}' . $nameRaw, $this->mailboxUserName, $this->mailboxPassword, CL_EXPUNGE);
345
          $messages = imap_sort($mboxd, SORTDATE, 0);
346
          $i = 0;
347
348
          foreach ($messages as $message) {
349
            $header = imap_header($mboxd, $message);
350
351
            // purge if prior to global delete date
352
            if ($header->udate < $delDate) {
353
              imap_delete($mboxd, $message);
354
            }
355
            $i++;
356
          }
357
358
          imap_expunge($mboxd);
359
          imap_close($mboxd);
360
        }
361
      }
362
363
      imap_close($mboxt);
364
365
      return true;
366
367
    } else {
368
      imap_close($mboxt);
369
370
      return false;
371
    }
372
  }
373
374
  /**
375
   * output additional msg for debug
376
   *
377
   * @param bool|false $msg          if not given, output the last error msg
378
   * @param int        $verboseLevel the output level of this message
379
   */
380 2
  public function output($msg = false, $verboseLevel = self::VERBOSE_SIMPLE)
381
  {
382 2
    if ($this->verbose >= $verboseLevel) {
383 2
      if (empty($msg)) {
384
        echo $this->errorMessage . $this->bmhNewLine;
385
      } else {
386 2
        echo $msg . $this->bmhNewLine;
387
      }
388 2
    }
389 2
  }
390
391
  /**
392
   * open a mail box in local file system
393
   *
394
   * @param string $filePath The local mailbox file path
395
   *
396
   * @return boolean
397
   */
398 2
  public function openLocal($filePath)
399
  {
400 2
    set_time_limit(6000);
401
402 2
    if (!$this->testMode) {
403
      $this->mailboxLink = imap_open($filePath, '', '', CL_EXPUNGE | ($this->testMode ? OP_READONLY : 0));
404
    } else {
405 2
      $this->mailboxLink = imap_open($filePath, '', '', ($this->testMode ? OP_READONLY : 0));
406
    }
407
408 2
    if (!$this->mailboxLink) {
409
      $this->errorMessage = 'Cannot open the mailbox file to ' . $filePath . $this->bmhNewLine . 'Error MSG: ' . imap_last_error();
410
      $this->output();
411
412
      return false;
413
    } else {
414 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...
415
416 2
      return true;
417
    }
418
  }
419
420
  /**
421
   * process the messages in a mailbox
422
   *
423
   * @param bool|false $max $max maximum limit messages processed in one batch, if not given uses the property
424
   *                        $maxMessages
425
   *
426
   * @return bool
427
   */
428 2
  public function processMailbox($max = false)
429
  {
430 2
    if (empty($this->actionFunction) || !is_callable($this->actionFunction)) {
431
      $this->errorMessage = 'Action function not found!';
432
      $this->output();
433
434
      return false;
435
    }
436
437 2
    if ($this->moveHard && ($this->disableDelete === false)) {
438
      $this->disableDelete = true;
439
    }
440
441 2
    if (!empty($max)) {
442
      $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...
443
    }
444
445
    // initialize counters
446 2
    $totalCount = imap_num_msg($this->mailboxLink);
447 2
    $fetchedCount = $totalCount;
448 2
    $processedCount = 0;
449 2
    $unprocessedCount = 0;
450 2
    $deletedCount = 0;
451 2
    $movedCount = 0;
452 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...
453
454
    // process maximum number of messages
455 2
    if ($fetchedCount > $this->maxMessages) {
456
      $fetchedCount = $this->maxMessages;
457
      $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...
458
    }
459
460 2
    if ($this->testMode) {
461 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...
462 2
    } else {
463
      if ($this->disableDelete) {
464
        if ($this->moveHard) {
465
          $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...
466
        } else {
467
          $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...
468
        }
469
      } else {
470
        $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...
471
      }
472
    }
473
474 2
    for ($x = 1; $x <= $fetchedCount; $x++) {
475
476
      // fetch the messages one at a time
477 2
      if ($this->useFetchstructure) {
478 2
        $structure = imap_fetchstructure($this->mailboxLink, $x);
479
480
        if (
481 2
            $structure->type == 1
482 2
            &&
483 2
            $structure->ifsubtype
484 2
            &&
485 2
            strtoupper($structure->subtype) == 'REPORT'
486 2
            &&
487 2
            $structure->ifparameters
488 2
            &&
489 2
            $this->isParameter($structure->parameters, 'REPORT-TYPE', 'delivery-status')
490 2
        ) {
491 2
          $processed = $this->processBounce($x, 'DSN', $totalCount);
492 2
        } else {
493
          // not standard DSN msg
494 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...
495
496 2
          if ($this->debugBodyRule) {
497
            if ($structure->ifdescription) {
498
              $this->output("  Content-Type : {$structure->description}", self::VERBOSE_DEBUG);
499
            } else {
500
              $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...
501
            }
502
          }
503
504 2
          $processed = $this->processBounce($x, 'BODY', $totalCount);
505
        }
506 2
      } else {
507
        $header = imap_fetchheader($this->mailboxLink, $x);
508
509
        // Could be multi-line, if the new line begins with SPACE or HTAB
510
        if (preg_match("/Content-Type:((?:[^\n]|\n[\t ])+)(?:\n[^\t ]|$)/i", $header, $match)) {
511
          if (preg_match("/multipart\/report/i", $match[1]) && preg_match("/report-type=[\"']?delivery-status[\"']?/i", $match[1])) {
512
            // standard DSN msg
513
            $processed = $this->processBounce($x, 'DSN', $totalCount);
514
          } else {
515
            // not standard DSN msg
516
            $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...
517
518
            if ($this->debugBodyRule) {
519
              $this->output("  Content-Type : {$match[1]}", self::VERBOSE_DEBUG);
520
            }
521
522
            $processed = $this->processBounce($x, 'BODY', $totalCount);
523
          }
524
        } else {
525
          // didn't get content-type header
526
          $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...
527
528
          if ($this->debugBodyRule) {
529
            $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...
530
          }
531
532
          $processed = $this->processBounce($x, 'BODY', $totalCount);
533
        }
534
      }
535
536 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...
537 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...
538
539 2
      if ($processed) {
540 2
        $processedCount++;
541
542 2
        if (!$this->disableDelete) {
543
          // delete the bounce if not in disableDelete mode
544 2
          if (!$this->testMode) {
545
            /** @noinspection PhpUsageOfSilenceOperatorInspection */
546
            @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...
547
          }
548
549 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...
550 2
          $deletedCount++;
551 2
        } elseif ($this->moveHard) {
552
          // check if the move directory exists, if not create it
553
          if (!$this->testMode) {
554
            $this->mailboxExist($this->hardMailbox);
555
          }
556
557
          // move the message
558
          if (!$this->testMode) {
559
            /** @noinspection PhpUsageOfSilenceOperatorInspection */
560
            @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...
561
          }
562
563
          $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...
564
          $movedCount++;
565
        } elseif ($this->moveSoft) {
566
          // check if the move directory exists, if not create it
567
          if (!$this->testMode) {
568
            $this->mailboxExist($this->softMailbox);
569
          }
570
571
          // move the message
572
          if (!$this->testMode) {
573
            /** @noinspection PhpUsageOfSilenceOperatorInspection */
574
            @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...
575
          }
576
577
          $moveFlag[$x] = true;
578
          $movedCount++;
579
        }
580 2
      } else {
581
        // not processed
582 2
        $unprocessedCount++;
583 2
        if (!$this->disableDelete && $this->purgeUnprocessed) {
584
          // delete this bounce if not in disableDelete mode, and the flag BOUNCE_PURGE_UNPROCESSED is set
585
          if (!$this->testMode) {
586
            /** @noinspection PhpUsageOfSilenceOperatorInspection */
587
            @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...
588
          }
589
590
          $deleteFlag[$x] = true;
591
          $deletedCount++;
592
        }
593
594
        // check if the move directory exists, if not create it
595 2
        $this->mailboxExist($this->unprocessedBox);
596
        // move the message
597
        @imap_mail_move($this->mailboxLink, $x, $this->unprocessedBox);
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...
598
        $moveFlag[$x] = true;
599
      }
600
601 2
      flush();
602 2
    }
603
604 1
    $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...
605
606 1
    imap_expunge($this->mailboxLink);
607 1
    imap_close($this->mailboxLink);
608
609 1
    $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...
610 1
    $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...
611 1
    $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...
612 1
    $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...
613 1
    $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...
614
615 1
    return true;
616
  }
617
618
  /**
619
   * Function to determine if a particular value is found in a imap_fetchstructure key.
620
   *
621
   * @param array  $currParameters imap_fetstructure parameters
622
   * @param string $varKey         imap_fetstructure key
623
   * @param string $varValue       value to check for
624
   *
625
   * @return boolean
626
   */
627 2
  public function isParameter($currParameters, $varKey, $varValue)
628
  {
629 2
    foreach ($currParameters as $object) {
630
      if (
631 2
          strtolower($object->attribute) == strtolower($varKey)
632 2
          &&
633 2
          strtolower($object->value) == strtolower($varValue)
634 2
      ) {
635 2
        return true;
636
      }
637
    }
638
639
    return false;
640
  }
641
642
  /**
643
   * Function to process each individual message.
644
   *
645
   * @param int    $pos          message number
646
   * @param string $type         DNS or BODY type
647
   * @param string $totalFetched total number of messages in mailbox
648
   *
649
   * @return boolean
650
   */
651 2
  public function processBounce($pos, $type, $totalFetched)
652
  {
653 2
    $header = imap_header($this->mailboxLink, $pos);
654 2
    $subject = isset($header->subject) ? strip_tags($header->subject) : '[NO SUBJECT]';
655 2
    $body = '';
656 2
    $headerFull = imap_fetchheader($this->mailboxLink, $pos);
657 2
    $bodyFull = imap_body($this->mailboxLink, $pos);
658
659 2
    if ($type == 'DSN') {
660
      // first part of DSN (Delivery Status Notification), human-readable explanation
661 2
      $dsnMsg = imap_fetchbody($this->mailboxLink, $pos, '1');
662 2
      $dsnMsgStructure = imap_bodystruct($this->mailboxLink, $pos, '1');
663
664 2
      if ($dsnMsgStructure->encoding == 4) {
665
        $dsnMsg = quoted_printable_decode($dsnMsg);
666 2
      } elseif ($dsnMsgStructure->encoding == 3) {
667
        $dsnMsg = base64_decode($dsnMsg);
668
      }
669
670
      // second part of DSN (Delivery Status Notification), delivery-status
671 2
      $dsnReport = imap_fetchbody($this->mailboxLink, $pos, '2');
672
673
      // process bounces by rules
674 2
      $result = bmhDSNRules($dsnMsg, $dsnReport, $this->debugDsnRule);
675 2
    } elseif ($type == 'BODY') {
676 2
      $structure = imap_fetchstructure($this->mailboxLink, $pos);
677
678 2
      switch ($structure->type) {
679 2
        case 0: // Content-type = text
680 2
          $body = imap_fetchbody($this->mailboxLink, $pos, '1');
681 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...
682 2
          break;
683
684
        case 1: // Content-type = multipart
685
          $body = imap_fetchbody($this->mailboxLink, $pos, '1');
686
687
          // Detect encoding and decode - only base64
688
          if ($structure->parts[0]->encoding == 4) {
689
            $body = quoted_printable_decode($body);
690
          } elseif ($structure->parts[0]->encoding == 3) {
691
            $body = base64_decode($body);
692
          }
693
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
        case 2: // Content-type = message
698
          $body = imap_body($this->mailboxLink, $pos);
699
700
          if ($structure->encoding == 4) {
701
            $body = quoted_printable_decode($body);
702
          } elseif ($structure->encoding == 3) {
703
            $body = base64_decode($body);
704
          }
705
706
          $body = substr($body, 0, 1000);
707
          $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...
708
          break;
709
710
        default: // unsupport Content-type
711
          $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...
712
713
          return false;
714 2
      }
715 2
    } else {
716
      // internal error
717
      $this->errorMessage = 'Internal Error: unknown type';
718
719
      return false;
720
    }
721
722 2
    $email = $result['email'];
723 2
    $bounceType = $result['bounce_type'];
724
725
    // workaround: I think there is a error in one of the reg-ex in "phpmailer-bmh_rules.php".
726 2
    if ($email && strpos($email, 'TO:<')) {
727
      $email = str_replace('TO:<', '', $email);
728
    }
729
730 2
    if ($this->moveHard && $result['remove'] == 1) {
731
      $remove = 'moved (hard)';
732 2
    } elseif ($this->moveSoft && $result['remove'] == 1) {
733
      $remove = 'moved (soft)';
734 2
    } elseif ($this->disableDelete) {
735
      $remove = 0;
736
    } else {
737 2
      $remove = $result['remove'];
738
    }
739
740 2
    $ruleNumber = $result['rule_no'];
741 2
    $ruleCategory = $result['rule_cat'];
742 2
    $status_code = $result['status_code'];
743 2
    $action = $result['action'];
744 2
    $diagnostic_code = $result['diagnostic_code'];
745 2
    $xheader = false;
746
747 2
    if ($ruleNumber === '0000') {
748
      // unrecognized
749
      if (
750 2
          trim($email) == ''
751 2
          &&
752 2
          property_exists($header, 'fromaddress') === true
753 2
      ) {
754 2
        $email = $header->fromaddress;
755 2
      }
756
757 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...
758 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...
759 2
      } else {
760
        // code below will use the Callback function, but return no value
761
        $params = array(
762
            $pos,
763
            $bounceType,
764
            $email,
765
            $subject,
766
            $header,
767
            $remove,
768
            $ruleNumber,
769
            $ruleCategory,
770
            $totalFetched,
771
            $body,
772
            $headerFull,
773
            $bodyFull,
774
            $status_code,
775
            $action,
776
            $diagnostic_code,
777
        );
778
        call_user_func_array($this->actionFunction, $params);
779
      }
780 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...
781
      // match rule, do bounce action
782 2
      if ($this->testMode) {
783 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...
784
785 2
        return true;
786
      } else {
787
        $params = array(
788
            $pos,
789
            $bounceType,
790
            $email,
791
            $subject,
792
            $xheader,
793
            $remove,
794
            $ruleNumber,
795
            $ruleCategory,
796
            $totalFetched,
797
            $body,
798
            $headerFull,
799
            $bodyFull,
800
            $status_code,
801
            $action,
802
            $diagnostic_code,
803
        );
804
805
        return call_user_func_array($this->actionFunction, $params);
806
      }
807
    }
808
809 2
    return false;
810
  }
811
812
  /**
813
   * Function to check if a mailbox exists - if not found, it will create it.
814
   *
815
   * @param string  $mailbox the mailbox name, must be in 'INBOX.checkmailbox' format
816
   * @param boolean $create  whether or not to create the checkmailbox if not found, defaults to true
817
   *
818
   * @return boolean
819
   */
820 2
  public function mailboxExist($mailbox, $create = true)
821
  {
822 2
    if (trim($mailbox) == '') {
823
      // this is a critical error with either the mailbox name blank or an invalid mailbox name
824
      // need to stop processing and exit at this point
825
      echo "Invalid mailbox name for move operation. Cannot continue.<br />\n";
826
      echo "TIP: the mailbox you want to move the message to must include 'INBOX.' at the start.<br />\n";
827
      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...
828
    }
829
830 2
    $port = $this->port . '/' . $this->service . '/' . $this->serviceOption;
831 2
    $mbox = imap_open('{' . $this->mailhost . ':' . $port . '}', $this->mailboxUserName, $this->mailboxPassword, OP_HALFOPEN);
832
833
    if ($mbox === false) {
834
      return false;
835
    }
836
837
    $list = imap_getmailboxes($mbox, '{' . $this->mailhost . ':' . $port . '}', '*');
838
    $mailboxFound = false;
839
840
    if (is_array($list)) {
841
      foreach ($list as $key => $val) {
842
        // get the mailbox name only
843
        $nameArr = explode('}', imap_utf7_decode($val->name));
844
        $nameRaw = $nameArr[count($nameArr) - 1];
845
        if ($mailbox == $nameRaw) {
846
          $mailboxFound = true;
847
        }
848
      }
849
850
      if (($mailboxFound === false) && $create) {
851
        /** @noinspection PhpUsageOfSilenceOperatorInspection */
852
        @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...
853
        imap_close($mbox);
854
855
        return true;
856
      } else {
857
        imap_close($mbox);
858
859
        return false;
860
      }
861
    } else {
862
      imap_close($mbox);
863
864
      return false;
865
    }
866
  }
867
}
868