Completed
Push — master ( 8b0a5f...3dd768 )
by Lars
03:04
created

BounceMailHandler::processBounce()   F

Complexity

Conditions 29
Paths 1924

Size

Total Lines 165
Code Lines 116

Duplication

Lines 51
Ratio 30.91 %

Code Coverage

Tests 71
CRAP Score 59.278

Importance

Changes 0
Metric Value
cc 29
eloc 116
nc 1924
nop 3
dl 51
loc 165
ccs 71
cts 106
cp 0.6697
crap 59.278
rs 2
c 0
b 0
f 0

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