Completed
Pull Request — master (#133)
by Goffy
16:45
created

PHPMailer::createHeader()   F

Complexity

Conditions 22
Paths 18432

Size

Total Lines 90
Code Lines 51

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 22
eloc 51
nc 18432
nop 0
dl 0
loc 90
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
2
/**
3
 * PHPMailer - PHP email creation and transport class.
4
 * PHP Version 5
5
 * @package PHPMailer
6
 * @link https://github.com/PHPMailer/PHPMailer/ The PHPMailer GitHub project
7
 * @author Marcus Bointon (Synchro/coolbru) <[email protected]>
8
 * @author Jim Jagielski (jimjag) <[email protected]>
9
 * @author Andy Prevost (codeworxtech) <[email protected]>
10
 * @author Brent R. Matzelle (original founder)
11
 * @copyright 2012 - 2014 Marcus Bointon
12
 * @copyright 2010 - 2012 Jim Jagielski
13
 * @copyright 2004 - 2009 Andy Prevost
14
 * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
15
 * @note This program is distributed in the hope that it will be useful - WITHOUT
16
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17
 * FITNESS FOR A PARTICULAR PURPOSE.
18
 */
19
20
/**
21
 * PHPMailer - PHP email creation and transport class.
22
 * @package PHPMailer
23
 * @author Marcus Bointon (Synchro/coolbru) <[email protected]>
24
 * @author Jim Jagielski (jimjag) <[email protected]>
25
 * @author Andy Prevost (codeworxtech) <[email protected]>
26
 * @author Brent R. Matzelle (original founder)
27
 */
28
class PHPMailer
29
{
30
    /**
31
     * The PHPMailer Version number.
32
     * @var string
33
     */
34
    public $Version = '5.2.14';
35
36
    /**
37
     * Email priority.
38
     * Options: null (default), 1 = High, 3 = Normal, 5 = low.
39
     * When null, the header is not set at all.
40
     * @var integer
41
     */
42
    public $Priority = null;
43
44
    /**
45
     * The character set of the message.
46
     * @var string
47
     */
48
    public $CharSet = 'iso-8859-1';
49
50
    /**
51
     * The MIME Content-type of the message.
52
     * @var string
53
     */
54
    public $ContentType = 'text/plain';
55
56
    /**
57
     * The message encoding.
58
     * Options: "8bit", "7bit", "binary", "base64", and "quoted-printable".
59
     * @var string
60
     */
61
    public $Encoding = '8bit';
62
63
    /**
64
     * Holds the most recent mailer error message.
65
     * @var string
66
     */
67
    public $ErrorInfo = '';
68
69
    /**
70
     * The From email address for the message.
71
     * @var string
72
     */
73
    public $From = 'root@localhost';
74
75
    /**
76
     * The From name of the message.
77
     * @var string
78
     */
79
    public $FromName = 'Root User';
80
81
    /**
82
     * The Sender email (Return-Path) of the message.
83
     * If not empty, will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode.
84
     * @var string
85
     */
86
    public $Sender = '';
87
88
    /**
89
     * The Return-Path of the message.
90
     * If empty, it will be set to either From or Sender.
91
     * @var string
92
     * @deprecated Email senders should never set a return-path header;
93
     * it's the receiver's job (RFC5321 section 4.4), so this no longer does anything.
94
     * @link https://tools.ietf.org/html/rfc5321#section-4.4 RFC5321 reference
95
     */
96
    public $ReturnPath = '';
97
98
    /**
99
     * The Subject of the message.
100
     * @var string
101
     */
102
    public $Subject = '';
103
104
    /**
105
     * An HTML or plain text message body.
106
     * If HTML then call isHTML(true).
107
     * @var string
108
     */
109
    public $Body = '';
110
111
    /**
112
     * The plain-text message body.
113
     * This body can be read by mail clients that do not have HTML email
114
     * capability such as mutt & Eudora.
115
     * Clients that can read HTML will view the normal Body.
116
     * @var string
117
     */
118
    public $AltBody = '';
119
120
    /**
121
     * An iCal message part body.
122
     * Only supported in simple alt or alt_inline message types
123
     * To generate iCal events, use the bundled extras/EasyPeasyICS.php class or iCalcreator
124
     * @link http://sprain.ch/blog/downloads/php-class-easypeasyics-create-ical-files-with-php/
125
     * @link http://kigkonsult.se/iCalcreator/
126
     * @var string
127
     */
128
    public $Ical = '';
129
130
    /**
131
     * The complete compiled MIME message body.
132
     * @access protected
133
     * @var string
134
     */
135
    protected $MIMEBody = '';
136
137
    /**
138
     * The complete compiled MIME message headers.
139
     * @var string
140
     * @access protected
141
     */
142
    protected $MIMEHeader = '';
143
144
    /**
145
     * Extra headers that createHeader() doesn't fold in.
146
     * @var string
147
     * @access protected
148
     */
149
    protected $mailHeader = '';
150
151
    /**
152
     * Word-wrap the message body to this number of chars.
153
     * Set to 0 to not wrap. A useful value here is 78, for RFC2822 section 2.1.1 compliance.
154
     * @var integer
155
     */
156
    public $WordWrap = 0;
157
158
    /**
159
     * Which method to use to send mail.
160
     * Options: "mail", "sendmail", or "smtp".
161
     * @var string
162
     */
163
    public $Mailer = 'mail';
164
165
    /**
166
     * The path to the sendmail program.
167
     * @var string
168
     */
169
    public $Sendmail = '/usr/sbin/sendmail';
170
171
    /**
172
     * Whether mail() uses a fully sendmail-compatible MTA.
173
     * One which supports sendmail's "-oi -f" options.
174
     * @var boolean
175
     */
176
    public $UseSendmailOptions = true;
177
178
    /**
179
     * Path to PHPMailer plugins.
180
     * Useful if the SMTP class is not in the PHP include path.
181
     * @var string
182
     * @deprecated Should not be needed now there is an autoloader.
183
     */
184
    public $PluginDir = '';
185
186
    /**
187
     * The email address that a reading confirmation should be sent to, also known as read receipt.
188
     * @var string
189
     */
190
    public $ConfirmReadingTo = '';
191
192
    /**
193
     * The hostname to use in the Message-ID header and as default HELO string.
194
     * If empty, PHPMailer attempts to find one with, in order,
195
     * $_SERVER['SERVER_NAME'], gethostname(), php_uname('n'), or the value
196
     * 'localhost.localdomain'.
197
     * @var string
198
     */
199
    public $Hostname = '';
200
201
    /**
202
     * An ID to be used in the Message-ID header.
203
     * If empty, a unique id will be generated.
204
     * @var string
205
     */
206
    public $MessageID = '';
207
208
    /**
209
     * The message Date to be used in the Date header.
210
     * If empty, the current date will be added.
211
     * @var string
212
     */
213
    public $MessageDate = '';
214
215
    /**
216
     * SMTP hosts.
217
     * Either a single hostname or multiple semicolon-delimited hostnames.
218
     * You can also specify a different port
219
     * for each host by using this format: [hostname:port]
220
     * (e.g. "smtp1.example.com:25;smtp2.example.com").
221
     * You can also specify encryption type, for example:
222
     * (e.g. "tls://smtp1.example.com:587;ssl://smtp2.example.com:465").
223
     * Hosts will be tried in order.
224
     * @var string
225
     */
226
    public $Host = 'localhost';
227
228
    /**
229
     * The default SMTP server port.
230
     * @var integer
231
     * @TODO Why is this needed when the SMTP class takes care of it?
232
     */
233
    public $Port = 25;
234
235
    /**
236
     * The SMTP HELO of the message.
237
     * Default is $Hostname. If $Hostname is empty, PHPMailer attempts to find
238
     * one with the same method described above for $Hostname.
239
     * @var string
240
     * @see PHPMailer::$Hostname
241
     */
242
    public $Helo = '';
243
244
    /**
245
     * What kind of encryption to use on the SMTP connection.
246
     * Options: '', 'ssl' or 'tls'
247
     * @var string
248
     */
249
    public $SMTPSecure = '';
250
251
    /**
252
     * Whether to enable TLS encryption automatically if a server supports it,
253
     * even if `SMTPSecure` is not set to 'tls'.
254
     * Be aware that in PHP >= 5.6 this requires that the server's certificates are valid.
255
     * @var boolean
256
     */
257
    public $SMTPAutoTLS = true;
258
259
    /**
260
     * Whether to use SMTP authentication.
261
     * Uses the Username and Password properties.
262
     * @var boolean
263
     * @see PHPMailer::$Username
264
     * @see PHPMailer::$Password
265
     */
266
    public $SMTPAuth = false;
267
268
    /**
269
     * Options array passed to stream_context_create when connecting via SMTP.
270
     * @var array
271
     */
272
    public $SMTPOptions = array();
273
274
    /**
275
     * SMTP username.
276
     * @var string
277
     */
278
    public $Username = '';
279
280
    /**
281
     * SMTP password.
282
     * @var string
283
     */
284
    public $Password = '';
285
286
    /**
287
     * SMTP auth type.
288
     * Options are LOGIN (default), PLAIN, NTLM, CRAM-MD5
289
     * @var string
290
     */
291
    public $AuthType = '';
292
293
    /**
294
     * SMTP realm.
295
     * Used for NTLM auth
296
     * @var string
297
     */
298
    public $Realm = '';
299
300
    /**
301
     * SMTP workstation.
302
     * Used for NTLM auth
303
     * @var string
304
     */
305
    public $Workstation = '';
306
307
    /**
308
     * The SMTP server timeout in seconds.
309
     * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2
310
     * @var integer
311
     */
312
    public $Timeout = 300;
313
314
    /**
315
     * SMTP class debug output mode.
316
     * Debug output level.
317
     * Options:
318
     * * `0` No output
319
     * * `1` Commands
320
     * * `2` Data and commands
321
     * * `3` As 2 plus connection status
322
     * * `4` Low-level data output
323
     * @var integer
324
     * @see SMTP::$do_debug
325
     */
326
    public $SMTPDebug = 0;
327
328
    /**
329
     * How to handle debug output.
330
     * Options:
331
     * * `echo` Output plain-text as-is, appropriate for CLI
332
     * * `html` Output escaped, line breaks converted to `<br>`, appropriate for browser output
333
     * * `error_log` Output to error log as configured in php.ini
334
     *
335
     * Alternatively, you can provide a callable expecting two params: a message string and the debug level:
336
     * <code>
337
     * $mail->Debugoutput = function($str, $level) {echo "debug level $level; message: $str";};
338
     * </code>
339
     * @var string|callable
340
     * @see SMTP::$Debugoutput
341
     */
342
    public $Debugoutput = 'echo';
343
344
    /**
345
     * Whether to keep SMTP connection open after each message.
346
     * If this is set to true then to close the connection
347
     * requires an explicit call to smtpClose().
348
     * @var boolean
349
     */
350
    public $SMTPKeepAlive = false;
351
352
    /**
353
     * Whether to split multiple to addresses into multiple messages
354
     * or send them all in one message.
355
     * @var boolean
356
     */
357
    public $SingleTo = false;
358
359
    /**
360
     * Storage for addresses when SingleTo is enabled.
361
     * @var array
362
     * @TODO This should really not be public
363
     */
364
    public $SingleToArray = array();
365
366
    /**
367
     * Whether to generate VERP addresses on send.
368
     * Only applicable when sending via SMTP.
369
     * @link https://en.wikipedia.org/wiki/Variable_envelope_return_path
370
     * @link http://www.postfix.org/VERP_README.html Postfix VERP info
371
     * @var boolean
372
     */
373
    public $do_verp = false;
374
375
    /**
376
     * Whether to allow sending messages with an empty body.
377
     * @var boolean
378
     */
379
    public $AllowEmpty = false;
380
381
    /**
382
     * The default line ending.
383
     * @note The default remains "\n". We force CRLF where we know
384
     *        it must be used via self::CRLF.
385
     * @var string
386
     */
387
    public $LE = "\n";
388
389
    /**
390
     * DKIM selector.
391
     * @var string
392
     */
393
    public $DKIM_selector = '';
394
395
    /**
396
     * DKIM Identity.
397
     * Usually the email address used as the source of the email
398
     * @var string
399
     */
400
    public $DKIM_identity = '';
401
402
    /**
403
     * DKIM passphrase.
404
     * Used if your key is encrypted.
405
     * @var string
406
     */
407
    public $DKIM_passphrase = '';
408
409
    /**
410
     * DKIM signing domain name.
411
     * @example 'example.com'
412
     * @var string
413
     */
414
    public $DKIM_domain = '';
415
416
    /**
417
     * DKIM private key file path.
418
     * @var string
419
     */
420
    public $DKIM_private = '';
421
422
    /**
423
     * Callback Action function name.
424
     *
425
     * The function that handles the result of the send email action.
426
     * It is called out by send() for each email sent.
427
     *
428
     * Value can be any php callable: http://www.php.net/is_callable
429
     *
430
     * Parameters:
431
     *   boolean $result        result of the send action
432
     *   string  $to            email address of the recipient
433
     *   string  $cc            cc email addresses
434
     *   string  $bcc           bcc email addresses
435
     *   string  $subject       the subject
436
     *   string  $body          the email body
437
     *   string  $from          email address of sender
438
     * @var string
439
     */
440
    public $action_function = '';
441
442
    /**
443
     * What to put in the X-Mailer header.
444
     * Options: An empty string for PHPMailer default, whitespace for none, or a string to use
445
     * @var string
446
     */
447
    public $XMailer = '';
448
449
    /**
450
     * An instance of the SMTP sender class.
451
     * @var SMTP
452
     * @access protected
453
     */
454
    protected $smtp = null;
455
456
    /**
457
     * The array of 'to' names and addresses.
458
     * @var array
459
     * @access protected
460
     */
461
    protected $to = array();
462
463
    /**
464
     * The array of 'cc' names and addresses.
465
     * @var array
466
     * @access protected
467
     */
468
    protected $cc = array();
469
470
    /**
471
     * The array of 'bcc' names and addresses.
472
     * @var array
473
     * @access protected
474
     */
475
    protected $bcc = array();
476
477
    /**
478
     * The array of reply-to names and addresses.
479
     * @var array
480
     * @access protected
481
     */
482
    protected $ReplyTo = array();
483
484
    /**
485
     * An array of all kinds of addresses.
486
     * Includes all of $to, $cc, $bcc
487
     * @var array
488
     * @access protected
489
     * @see PHPMailer::$to @see PHPMailer::$cc @see PHPMailer::$bcc
490
     */
491
    protected $all_recipients = array();
492
493
    /**
494
     * An array of names and addresses queued for validation.
495
     * In send(), valid and non duplicate entries are moved to $all_recipients
496
     * and one of $to, $cc, or $bcc.
497
     * This array is used only for addresses with IDN.
498
     * @var array
499
     * @access protected
500
     * @see PHPMailer::$to @see PHPMailer::$cc @see PHPMailer::$bcc
501
     * @see PHPMailer::$all_recipients
502
     */
503
    protected $RecipientsQueue = array();
504
505
    /**
506
     * An array of reply-to names and addresses queued for validation.
507
     * In send(), valid and non duplicate entries are moved to $ReplyTo.
508
     * This array is used only for addresses with IDN.
509
     * @var array
510
     * @access protected
511
     * @see PHPMailer::$ReplyTo
512
     */
513
    protected $ReplyToQueue = array();
514
515
    /**
516
     * The array of attachments.
517
     * @var array
518
     * @access protected
519
     */
520
    protected $attachment = array();
521
522
    /**
523
     * The array of custom headers.
524
     * @var array
525
     * @access protected
526
     */
527
    protected $CustomHeader = array();
528
529
    /**
530
     * The most recent Message-ID (including angular brackets).
531
     * @var string
532
     * @access protected
533
     */
534
    protected $lastMessageID = '';
535
536
    /**
537
     * The message's MIME type.
538
     * @var string
539
     * @access protected
540
     */
541
    protected $message_type = '';
542
543
    /**
544
     * The array of MIME boundary strings.
545
     * @var array
546
     * @access protected
547
     */
548
    protected $boundary = array();
549
550
    /**
551
     * The array of available languages.
552
     * @var array
553
     * @access protected
554
     */
555
    protected $language = array();
556
557
    /**
558
     * The number of errors encountered.
559
     * @var integer
560
     * @access protected
561
     */
562
    protected $error_count = 0;
563
564
    /**
565
     * The S/MIME certificate file path.
566
     * @var string
567
     * @access protected
568
     */
569
    protected $sign_cert_file = '';
570
571
    /**
572
     * The S/MIME key file path.
573
     * @var string
574
     * @access protected
575
     */
576
    protected $sign_key_file = '';
577
578
    /**
579
     * The optional S/MIME extra certificates ("CA Chain") file path.
580
     * @var string
581
     * @access protected
582
     */
583
    protected $sign_extracerts_file = '';
584
585
    /**
586
     * The S/MIME password for the key.
587
     * Used only if the key is encrypted.
588
     * @var string
589
     * @access protected
590
     */
591
    protected $sign_key_pass = '';
592
593
    /**
594
     * Whether to throw exceptions for errors.
595
     * @var boolean
596
     * @access protected
597
     */
598
    protected $exceptions = false;
599
600
    /**
601
     * Unique ID used for message ID and boundaries.
602
     * @var string
603
     * @access protected
604
     */
605
    protected $uniqueid = '';
606
607
    /**
608
     * Error severity: message only, continue processing.
609
     */
610
    const STOP_MESSAGE = 0;
611
612
    /**
613
     * Error severity: message, likely ok to continue processing.
614
     */
615
    const STOP_CONTINUE = 1;
616
617
    /**
618
     * Error severity: message, plus full stop, critical error reached.
619
     */
620
    const STOP_CRITICAL = 2;
621
622
    /**
623
     * SMTP RFC standard line ending.
624
     */
625
    const CRLF = "\r\n";
626
627
    /**
628
     * The maximum line length allowed by RFC 2822 section 2.1.1
629
     * @var integer
630
     */
631
    const MAX_LINE_LENGTH = 998;
632
633
    /**
634
     * Constructor.
635
     * @param boolean $exceptions Should we throw external exceptions?
636
     */
637
    public function __construct($exceptions = false)
638
    {
639
        $this->exceptions = (boolean)$exceptions;
640
    }
641
642
    /**
643
     * Destructor.
644
     */
645
    public function __destruct()
646
    {
647
        //Close any open SMTP connection nicely
648
        if ($this->Mailer == 'smtp') {
649
            $this->smtpClose();
650
        }
651
    }
652
653
    /**
654
     * Call mail() in a safe_mode-aware fashion.
655
     * Also, unless sendmail_path points to sendmail (or something that
656
     * claims to be sendmail), don't pass params (not a perfect fix,
657
     * but it will do)
658
     * @param string $to To
659
     * @param string $subject Subject
660
     * @param string $body Message Body
661
     * @param string $header Additional Header(s)
662
     * @param string $params Params
663
     * @access private
664
     * @return boolean
665
     */
666
    private function mailPassthru($to, $subject, $body, $header, $params)
667
    {
668
        //Check overloading of mail function to avoid double-encoding
669
        if (ini_get('mbstring.func_overload') & 1) {
670
            $subject = $this->secureHeader($subject);
671
        } else {
672
            $subject = $this->encodeHeader($this->secureHeader($subject));
673
        }
674
        if (ini_get('safe_mode') || !($this->UseSendmailOptions)) {
675
            $result = @mail($to, $subject, $body, $header);
676
        } else {
677
            $result = @mail($to, $subject, $body, $header, $params);
678
        }
679
        return $result;
680
    }
681
682
    /**
683
     * Output debugging info via user-defined method.
684
     * Only generates output if SMTP debug output is enabled (@see SMTP::$do_debug).
685
     * @see PHPMailer::$Debugoutput
686
     * @see PHPMailer::$SMTPDebug
687
     * @param string $str
688
     */
689 View Code Duplication
    protected function edebug($str)
690
    {
691
        if ($this->SMTPDebug <= 0) {
692
            return;
693
        }
694
        //Avoid clash with built-in function names
695
        if (!in_array($this->Debugoutput, array('error_log', 'html', 'echo')) and is_callable($this->Debugoutput)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
696
            call_user_func($this->Debugoutput, $str, $this->SMTPDebug);
697
            return;
698
        }
699
        switch ($this->Debugoutput) {
700
            case 'error_log':
701
                //Don't output, just log
702
                error_log($str);
703
                break;
704
            case 'html':
705
                //Cleans up output a bit for a better looking, HTML-safe output
706
                echo htmlentities(
707
                    preg_replace('/[\r\n]+/', '', $str),
708
                    ENT_QUOTES,
709
                    'UTF-8'
710
                )
711
                . "<br>\n";
712
                break;
713
            case 'echo':
714
            default:
715
                //Normalize line breaks
716
                $str = preg_replace('/(\r\n|\r|\n)/ms', "\n", $str);
717
                echo gmdate('Y-m-d H:i:s') . "\t" . str_replace(
718
                    "\n",
719
                    "\n                   \t                  ",
720
                    trim($str)
721
                ) . "\n";
722
        }
723
    }
724
725
    /**
726
     * Sets message type to HTML or plain.
727
     * @param boolean $isHtml True for HTML mode.
728
     * @return void
729
     */
730
    public function isHTML($isHtml = true)
731
    {
732
        if ($isHtml) {
733
            $this->ContentType = 'text/html';
734
        } else {
735
            $this->ContentType = 'text/plain';
736
        }
737
    }
738
739
    /**
740
     * Send messages using SMTP.
741
     * @return void
742
     */
743
    public function isSMTP()
744
    {
745
        $this->Mailer = 'smtp';
746
    }
747
748
    /**
749
     * Send messages using PHP's mail() function.
750
     * @return void
751
     */
752
    public function isMail()
753
    {
754
        $this->Mailer = 'mail';
755
    }
756
757
    /**
758
     * Send messages using $Sendmail.
759
     * @return void
760
     */
761 View Code Duplication
    public function isSendmail()
762
    {
763
        $ini_sendmail_path = ini_get('sendmail_path');
764
765
        if (!stristr($ini_sendmail_path, 'sendmail')) {
766
            $this->Sendmail = '/usr/sbin/sendmail';
767
        } else {
768
            $this->Sendmail = $ini_sendmail_path;
769
        }
770
        $this->Mailer = 'sendmail';
771
    }
772
773
    /**
774
     * Send messages using qmail.
775
     * @return void
776
     */
777 View Code Duplication
    public function isQmail()
778
    {
779
        $ini_sendmail_path = ini_get('sendmail_path');
780
781
        if (!stristr($ini_sendmail_path, 'qmail')) {
782
            $this->Sendmail = '/var/qmail/bin/qmail-inject';
783
        } else {
784
            $this->Sendmail = $ini_sendmail_path;
785
        }
786
        $this->Mailer = 'qmail';
787
    }
788
789
    /**
790
     * Add a "To" address.
791
     * @param string $address The email address to send to
792
     * @param string $name
793
     * @return boolean true on success, false if address already used or invalid in some way
794
     */
795
    public function addAddress($address, $name = '')
796
    {
797
        return $this->addOrEnqueueAnAddress('to', $address, $name);
798
    }
799
800
    /**
801
     * Add a "CC" address.
802
     * @note: This function works with the SMTP mailer on win32, not with the "mail" mailer.
803
     * @param string $address The email address to send to
804
     * @param string $name
805
     * @return boolean true on success, false if address already used or invalid in some way
806
     */
807
    public function addCC($address, $name = '')
808
    {
809
        return $this->addOrEnqueueAnAddress('cc', $address, $name);
810
    }
811
812
    /**
813
     * Add a "BCC" address.
814
     * @note: This function works with the SMTP mailer on win32, not with the "mail" mailer.
815
     * @param string $address The email address to send to
816
     * @param string $name
817
     * @return boolean true on success, false if address already used or invalid in some way
818
     */
819
    public function addBCC($address, $name = '')
820
    {
821
        return $this->addOrEnqueueAnAddress('bcc', $address, $name);
822
    }
823
824
    /**
825
     * Add a "Reply-To" address.
826
     * @param string $address The email address to reply to
827
     * @param string $name
828
     * @return boolean true on success, false if address already used or invalid in some way
829
     */
830
    public function addReplyTo($address, $name = '')
831
    {
832
        return $this->addOrEnqueueAnAddress('Reply-To', $address, $name);
833
    }
834
835
    /**
836
     * Add an address to one of the recipient arrays or to the ReplyTo array. Because PHPMailer
837
     * can't validate addresses with an IDN without knowing the PHPMailer::$CharSet (that can still
838
     * be modified after calling this function), addition of such addresses is delayed until send().
839
     * Addresses that have been added already return false, but do not throw exceptions.
840
     * @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo'
841
     * @param string $address The email address to send, resp. to reply to
842
     * @param string $name
843
     * @throws phpmailerException
844
     * @return boolean true on success, false if address already used or invalid in some way
845
     * @access protected
846
     */
847
    protected function addOrEnqueueAnAddress($kind, $address, $name)
848
    {
849
        $address = trim($address);
850
        $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
851
        if (($pos = strrpos($address, '@')) === false) {
852
            // At-sign is misssing.
853
            $error_message = $this->lang('invalid_address') . $address;
854
            $this->setError($error_message);
855
            $this->edebug($error_message);
856
            if ($this->exceptions) {
857
                throw new phpmailerException($error_message);
858
            }
859
            return false;
860
        }
861
        $params = array($kind, $address, $name);
862
        // Enqueue addresses with IDN until we know the PHPMailer::$CharSet.
863
        if ($this->has8bitChars(substr($address, ++$pos)) and $this->idnSupported()) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
864
            if ($kind != 'Reply-To') {
865
                if (!array_key_exists($address, $this->RecipientsQueue)) {
866
                    $this->RecipientsQueue[$address] = $params;
867
                    return true;
868
                }
869
            } else {
870
                if (!array_key_exists($address, $this->ReplyToQueue)) {
871
                    $this->ReplyToQueue[$address] = $params;
872
                    return true;
873
                }
874
            }
875
            return false;
876
        }
877
        // Immediately add standard addresses without IDN.
878
        return call_user_func_array(array($this, 'addAnAddress'), $params);
879
    }
880
881
    /**
882
     * Add an address to one of the recipient arrays or to the ReplyTo array.
883
     * Addresses that have been added already return false, but do not throw exceptions.
884
     * @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo'
885
     * @param string $address The email address to send, resp. to reply to
886
     * @param string $name
887
     * @throws phpmailerException
888
     * @return boolean true on success, false if address already used or invalid in some way
889
     * @access protected
890
     */
891
    protected function addAnAddress($kind, $address, $name = '')
892
    {
893
        if (!in_array($kind, array('to', 'cc', 'bcc', 'Reply-To'))) {
894
            $error_message = $this->lang('Invalid recipient kind: ') . $kind;
895
            $this->setError($error_message);
896
            $this->edebug($error_message);
897
            if ($this->exceptions) {
898
                throw new phpmailerException($error_message);
899
            }
900
            return false;
901
        }
902 View Code Duplication
        if (!$this->validateAddress($address)) {
903
            $error_message = $this->lang('invalid_address') . $address;
904
            $this->setError($error_message);
905
            $this->edebug($error_message);
906
            if ($this->exceptions) {
907
                throw new phpmailerException($error_message);
908
            }
909
            return false;
910
        }
911
        if ($kind != 'Reply-To') {
912 View Code Duplication
            if (!array_key_exists(strtolower($address), $this->all_recipients)) {
913
                array_push($this->$kind, array($address, $name));
914
                $this->all_recipients[strtolower($address)] = true;
915
                return true;
916
            }
917
        } else {
918 View Code Duplication
            if (!array_key_exists(strtolower($address), $this->ReplyTo)) {
919
                $this->ReplyTo[strtolower($address)] = array($address, $name);
920
                return true;
921
            }
922
        }
923
        return false;
924
    }
925
926
    /**
927
     * Parse and validate a string containing one or more RFC822-style comma-separated email addresses
928
     * of the form "display name <address>" into an array of name/address pairs.
929
     * Uses the imap_rfc822_parse_adrlist function if the IMAP extension is available.
930
     * Note that quotes in the name part are removed.
931
     * @param string $addrstr The address list string
932
     * @param bool $useimap Whether to use the IMAP extension to parse the list
933
     * @return array
934
     * @link http://www.andrew.cmu.edu/user/agreen1/testing/mrbs/web/Mail/RFC822.php A more careful implementation
935
     */
936
    public function parseAddresses($addrstr, $useimap = true)
937
    {
938
        $addresses = array();
939
        if ($useimap and function_exists('imap_rfc822_parse_adrlist')) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
940
            //Use this built-in parser if it's available
941
            $list = imap_rfc822_parse_adrlist($addrstr, '');
942
            foreach ($list as $address) {
943
                if ($address->host != '.SYNTAX-ERROR.') {
944
                    if ($this->validateAddress($address->mailbox . '@' . $address->host)) {
945
                        $addresses[] = array(
946
                            'name' => (property_exists($address, 'personal') ? $address->personal : ''),
947
                            'address' => $address->mailbox . '@' . $address->host
948
                        );
949
                    }
950
                }
951
            }
952
        } else {
953
            //Use this simpler parser
954
            $list = explode(',', $addrstr);
955
            foreach ($list as $address) {
956
                $address = trim($address);
957
                //Is there a separate name part?
958
                if (strpos($address, '<') === false) {
959
                    //No separate name, just use the whole thing
960
                    if ($this->validateAddress($address)) {
961
                        $addresses[] = array(
962
                            'name' => '',
963
                            'address' => $address
964
                        );
965
                    }
966
                } else {
967
                    list($name, $email) = explode('<', $address);
968
                    $email = trim(str_replace('>', '', $email));
969
                    if ($this->validateAddress($email)) {
970
                        $addresses[] = array(
971
                            'name' => trim(str_replace(array('"', "'"), '', $name)),
972
                            'address' => $email
973
                        );
974
                    }
975
                }
976
            }
977
        }
978
        return $addresses;
979
    }
980
981
    /**
982
     * Set the From and FromName properties.
983
     * @param string $address
984
     * @param string $name
985
     * @param boolean $auto Whether to also set the Sender address, defaults to true
986
     * @throws phpmailerException
987
     * @return boolean
988
     */
989
    public function setFrom($address, $name = '', $auto = true)
990
    {
991
        $address = trim($address);
992
        $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
993
        // Don't validate now addresses with IDN. Will be done in send().
994
        if (($pos = strrpos($address, '@')) === false or
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
995
            (!$this->has8bitChars(substr($address, ++$pos)) or !$this->idnSupported()) and
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
996
            !$this->validateAddress($address)) {
997
            $error_message = $this->lang('invalid_address') . $address;
998
            $this->setError($error_message);
999
            $this->edebug($error_message);
1000
            if ($this->exceptions) {
1001
                throw new phpmailerException($error_message);
1002
            }
1003
            return false;
1004
        }
1005
        $this->From = $address;
1006
        $this->FromName = $name;
1007
        if ($auto) {
1008
            if (empty($this->Sender)) {
1009
                $this->Sender = $address;
1010
            }
1011
        }
1012
        return true;
1013
    }
1014
1015
    /**
1016
     * Return the Message-ID header of the last email.
1017
     * Technically this is the value from the last time the headers were created,
1018
     * but it's also the message ID of the last sent message except in
1019
     * pathological cases.
1020
     * @return string
1021
     */
1022
    public function getLastMessageID()
1023
    {
1024
        return $this->lastMessageID;
1025
    }
1026
1027
    /**
1028
     * Check that a string looks like an email address.
1029
     * @param string $address The email address to check
1030
     * @param string $patternselect A selector for the validation pattern to use :
1031
     * * `auto` Pick best pattern automatically;
1032
     * * `pcre8` Use the squiloople.com pattern, requires PCRE > 8.0, PHP >= 5.3.2, 5.2.14;
1033
     * * `pcre` Use old PCRE implementation;
1034
     * * `php` Use PHP built-in FILTER_VALIDATE_EMAIL;
1035
     * * `html5` Use the pattern given by the HTML5 spec for 'email' type form input elements.
1036
     * * `noregex` Don't use a regex: super fast, really dumb.
1037
     * @return boolean
1038
     * @static
1039
     * @access public
1040
     */
1041
    public static function validateAddress($address, $patternselect = 'auto')
1042
    {
1043
        //Reject line breaks in addresses; it's valid RFC5322, but not RFC5321
1044
        if (strpos($address, "\n") !== false or strpos($address, "\r") !== false) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1045
            return false;
1046
        }
1047
        if (!$patternselect or $patternselect == 'auto') {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1048
            //Check this constant first so it works when extension_loaded() is disabled by safe mode
1049
            //Constant was added in PHP 5.2.4
1050
            if (defined('PCRE_VERSION')) {
1051
                //This pattern can get stuck in a recursive loop in PCRE <= 8.0.2
1052
                if (version_compare(PCRE_VERSION, '8.0.3') >= 0) {
1053
                    $patternselect = 'pcre8';
1054
                } else {
1055
                    $patternselect = 'pcre';
1056
                }
1057
            } elseif (function_exists('extension_loaded') and extension_loaded('pcre')) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1058
                //Fall back to older PCRE
1059
                $patternselect = 'pcre';
1060
            } else {
1061
                //Filter_var appeared in PHP 5.2.0 and does not require the PCRE extension
1062
                if (version_compare(PHP_VERSION, '5.2.0') >= 0) {
1063
                    $patternselect = 'php';
1064
                } else {
1065
                    $patternselect = 'noregex';
1066
                }
1067
            }
1068
        }
1069
        switch ($patternselect) {
1070 View Code Duplication
            case 'pcre8':
1071
                /**
1072
                 * Uses the same RFC5322 regex on which FILTER_VALIDATE_EMAIL is based, but allows dotless domains.
1073
                 * @link http://squiloople.com/2009/12/20/email-address-validation/
1074
                 * @copyright 2009-2010 Michael Rushton
1075
                 * Feel free to use and redistribute this code. But please keep this copyright notice.
1076
                 */
1077
                return (boolean)preg_match(
1078
                    '/^(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){255,})(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){65,}@)' .
1079
                    '((?>(?>(?>((?>(?>(?>\x0D\x0A)?[\t ])+|(?>[\t ]*\x0D\x0A)?[\t ]+)?)(\((?>(?2)' .
1080
                    '(?>[\x01-\x08\x0B\x0C\x0E-\'*-\[\]-\x7F]|\\\[\x00-\x7F]|(?3)))*(?2)\)))+(?2))|(?2))?)' .
1081
                    '([!#-\'*+\/-9=?^-~-]+|"(?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\x7F]))*' .
1082
                    '(?2)")(?>(?1)\.(?1)(?4))*(?1)@(?!(?1)[a-z0-9-]{64,})(?1)(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)' .
1083
                    '(?>(?1)\.(?!(?1)[a-z0-9-]{64,})(?1)(?5)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?6)){7}' .
1084
                    '|(?!(?:.*[a-f0-9][:\]]){8,})((?6)(?>:(?6)){0,6})?::(?7)?))|(?>(?>IPv6:(?>(?6)(?>:(?6)){5}:' .
1085
                    '|(?!(?:.*[a-f0-9]:){6,})(?8)?::(?>((?6)(?>:(?6)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}' .
1086
                    '|[1-9]?[0-9])(?>\.(?9)){3}))\])(?1)$/isD',
1087
                    $address
1088
                );
1089 View Code Duplication
            case 'pcre':
1090
                //An older regex that doesn't need a recent PCRE
1091
                return (boolean)preg_match(
1092
                    '/^(?!(?>"?(?>\\\[ -~]|[^"])"?){255,})(?!(?>"?(?>\\\[ -~]|[^"])"?){65,}@)(?>' .
1093
                    '[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*")' .
1094
                    '(?>\.(?>[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*"))*' .
1095
                    '@(?>(?![a-z0-9-]{64,})(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>\.(?![a-z0-9-]{64,})' .
1096
                    '(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)){0,126}|\[(?:(?>IPv6:(?>(?>[a-f0-9]{1,4})(?>:' .
1097
                    '[a-f0-9]{1,4}){7}|(?!(?:.*[a-f0-9][:\]]){8,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?' .
1098
                    '::(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?))|(?>(?>IPv6:(?>[a-f0-9]{1,4}(?>:' .
1099
                    '[a-f0-9]{1,4}){5}:|(?!(?:.*[a-f0-9]:){6,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4})?' .
1100
                    '::(?>(?:[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4}):)?))?(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}' .
1101
                    '|[1-9]?[0-9])(?>\.(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}))\])$/isD',
1102
                    $address
1103
                );
1104
            case 'html5':
1105
                /**
1106
                 * This is the pattern used in the HTML5 spec for validation of 'email' type form input elements.
1107
                 * @link http://www.whatwg.org/specs/web-apps/current-work/#e-mail-state-(type=email)
1108
                 */
1109
                return (boolean)preg_match(
1110
                    '/^[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}' .
1111
                    '[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/sD',
1112
                    $address
1113
                );
1114
            case 'noregex':
1115
                //No PCRE! Do something _very_ approximate!
1116
                //Check the address is 3 chars or longer and contains an @ that's not the first or last char
1117
                return (strlen($address) >= 3
1118
                    and strpos($address, '@') >= 1
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1119
                    and strpos($address, '@') != strlen($address) - 1);
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1120
            case 'php':
1121
            default:
1122
                return (boolean)filter_var($address, FILTER_VALIDATE_EMAIL);
1123
        }
1124
    }
1125
1126
    /**
1127
     * Tells whether IDNs (Internationalized Domain Names) are supported or not. This requires the
1128
     * "intl" and "mbstring" PHP extensions.
1129
     * @return bool "true" if required functions for IDN support are present
1130
     */
1131
    public function idnSupported()
1132
    {
1133
        // @TODO: Write our own "idn_to_ascii" function for PHP <= 5.2.
1134
        return function_exists('idn_to_ascii') and function_exists('mb_convert_encoding');
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1135
    }
1136
1137
    /**
1138
     * Converts IDN in given email address to its ASCII form, also known as punycode, if possible.
1139
     * Important: Address must be passed in same encoding as currently set in PHPMailer::$CharSet.
1140
     * This function silently returns unmodified address if:
1141
     * - No conversion is necessary (i.e. domain name is not an IDN, or is already in ASCII form)
1142
     * - Conversion to punycode is impossible (e.g. required PHP functions are not available)
1143
     *   or fails for any reason (e.g. domain has characters not allowed in an IDN)
1144
     * @see PHPMailer::$CharSet
1145
     * @param string $address The email address to convert
1146
     * @return string The encoded address in ASCII form
1147
     */
1148
    public function punyencodeAddress($address)
1149
    {
1150
        // Verify we have required functions, CharSet, and at-sign.
1151
        if ($this->idnSupported() and
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1152
            !empty($this->CharSet) and
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1153
            ($pos = strrpos($address, '@')) !== false) {
1154
            $domain = substr($address, ++$pos);
1155
            // Verify CharSet string is a valid one, and domain properly encoded in this CharSet.
1156
            if ($this->has8bitChars($domain) and @mb_check_encoding($domain, $this->CharSet)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1157
                $domain = mb_convert_encoding($domain, 'UTF-8', $this->CharSet);
1158
                if (($punycode = defined('INTL_IDNA_VARIANT_UTS46') ?
1159
                    idn_to_ascii($domain, 0, INTL_IDNA_VARIANT_UTS46) :
1160
                    idn_to_ascii($domain)) !== false) {
1161
                    return substr($address, 0, $pos) . $punycode;
1162
                }
1163
            }
1164
        }
1165
        return $address;
1166
    }
1167
1168
    /**
1169
     * Create a message and send it.
1170
     * Uses the sending method specified by $Mailer.
1171
     * @throws phpmailerException
1172
     * @return boolean false on error - See the ErrorInfo property for details of the error.
1173
     */
1174
    public function send()
1175
    {
1176
        try {
1177
            if (!$this->preSend()) {
1178
                return false;
1179
            }
1180
            return $this->postSend();
1181
        } catch (phpmailerException $exc) {
1182
            $this->mailHeader = '';
1183
            $this->setError($exc->getMessage());
1184
            if ($this->exceptions) {
1185
                throw $exc;
1186
            }
1187
            return false;
1188
        }
1189
    }
1190
1191
    /**
1192
     * Prepare a message for sending.
1193
     * @throws phpmailerException
1194
     * @return boolean
1195
     */
1196
    public function preSend()
1197
    {
1198
        try {
1199
            $this->error_count = 0; // Reset errors
1200
            $this->mailHeader = '';
1201
1202
            // Dequeue recipient and Reply-To addresses with IDN
1203
            foreach (array_merge($this->RecipientsQueue, $this->ReplyToQueue) as $params) {
1204
                $params[1] = $this->punyencodeAddress($params[1]);
1205
                call_user_func_array(array($this, 'addAnAddress'), $params);
1206
            }
1207
            if ((count($this->to) + count($this->cc) + count($this->bcc)) < 1) {
1208
                throw new phpmailerException($this->lang('provide_address'), self::STOP_CRITICAL);
1209
            }
1210
1211
            // Validate From, Sender, and ConfirmReadingTo addresses
1212
            foreach (array('From', 'Sender', 'ConfirmReadingTo') as $address_kind) {
1213
                $this->$address_kind = trim($this->$address_kind);
1214
                if (empty($this->$address_kind)) {
1215
                    continue;
1216
                }
1217
                $this->$address_kind = $this->punyencodeAddress($this->$address_kind);
1218 View Code Duplication
                if (!$this->validateAddress($this->$address_kind)) {
1219
                    $error_message = $this->lang('invalid_address') . $this->$address_kind;
1220
                    $this->setError($error_message);
1221
                    $this->edebug($error_message);
1222
                    if ($this->exceptions) {
1223
                        throw new phpmailerException($error_message);
1224
                    }
1225
                    return false;
1226
                }
1227
            }
1228
1229
            // Set whether the message is multipart/alternative
1230
            if (!empty($this->AltBody)) {
1231
                $this->ContentType = 'multipart/alternative';
1232
            }
1233
1234
            $this->setMessageType();
1235
            // Refuse to send an empty message unless we are specifically allowing it
1236
            if (!$this->AllowEmpty and empty($this->Body)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1237
                throw new phpmailerException($this->lang('empty_message'), self::STOP_CRITICAL);
1238
            }
1239
1240
            // Create body before headers in case body makes changes to headers (e.g. altering transfer encoding)
1241
            $this->MIMEHeader = '';
1242
            $this->MIMEBody = $this->createBody();
1243
            // createBody may have added some headers, so retain them
1244
            $tempheaders = $this->MIMEHeader;
1245
            $this->MIMEHeader = $this->createHeader();
1246
            $this->MIMEHeader .= $tempheaders;
1247
1248
            // To capture the complete message when using mail(), create
1249
            // an extra header list which createHeader() doesn't fold in
1250
            if ($this->Mailer == 'mail') {
1251
                if (count($this->to) > 0) {
1252
                    $this->mailHeader .= $this->addrAppend('To', $this->to);
1253
                } else {
1254
                    $this->mailHeader .= $this->headerLine('To', 'undisclosed-recipients:;');
1255
                }
1256
                $this->mailHeader .= $this->headerLine(
1257
                    'Subject',
1258
                    $this->encodeHeader($this->secureHeader(trim($this->Subject)))
1259
                );
1260
            }
1261
1262
            // Sign with DKIM if enabled
1263
            if (!empty($this->DKIM_domain)
1264
                && !empty($this->DKIM_private)
1265
                && !empty($this->DKIM_selector)
1266
                && file_exists($this->DKIM_private)) {
1267
                $header_dkim = $this->DKIM_Add(
1268
                    $this->MIMEHeader . $this->mailHeader,
1269
                    $this->encodeHeader($this->secureHeader($this->Subject)),
1270
                    $this->MIMEBody
1271
                );
1272
                $this->MIMEHeader = rtrim($this->MIMEHeader, "\r\n ") . self::CRLF .
1273
                    str_replace("\r\n", "\n", $header_dkim) . self::CRLF;
1274
            }
1275
            return true;
1276
        } catch (phpmailerException $exc) {
1277
            $this->setError($exc->getMessage());
1278
            if ($this->exceptions) {
1279
                throw $exc;
1280
            }
1281
            return false;
1282
        }
1283
    }
1284
1285
    /**
1286
     * Actually send a message.
1287
     * Send the email via the selected mechanism
1288
     * @throws phpmailerException
1289
     * @return boolean
1290
     */
1291
    public function postSend()
1292
    {
1293
        try {
1294
            // Choose the mailer and send through it
1295
            switch ($this->Mailer) {
1296
                case 'sendmail':
1297
                case 'qmail':
1298
                    return $this->sendmailSend($this->MIMEHeader, $this->MIMEBody);
1299
                case 'smtp':
1300
                    return $this->smtpSend($this->MIMEHeader, $this->MIMEBody);
1301
                case 'mail':
1302
                    return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
1303
                default:
1304
                    $sendMethod = $this->Mailer.'Send';
1305
                    if (method_exists($this, $sendMethod)) {
1306
                        return $this->$sendMethod($this->MIMEHeader, $this->MIMEBody);
1307
                    }
1308
1309
                    return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
1310
            }
1311
        } catch (phpmailerException $exc) {
1312
            $this->setError($exc->getMessage());
1313
            $this->edebug($exc->getMessage());
1314
            if ($this->exceptions) {
1315
                throw $exc;
1316
            }
1317
        }
1318
        return false;
1319
    }
1320
1321
    /**
1322
     * Send mail using the $Sendmail program.
1323
     * @param string $header The message headers
1324
     * @param string $body The message body
1325
     * @see PHPMailer::$Sendmail
1326
     * @throws phpmailerException
1327
     * @access protected
1328
     * @return boolean
1329
     */
1330
    protected function sendmailSend($header, $body)
1331
    {
1332
        if ($this->Sender != '') {
1333
            if ($this->Mailer == 'qmail') {
1334
                $sendmail = sprintf('%s -f%s', escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
1335
            } else {
1336
                $sendmail = sprintf('%s -oi -f%s -t', escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
1337
            }
1338
        } else {
1339
            if ($this->Mailer == 'qmail') {
1340
                $sendmail = sprintf('%s', escapeshellcmd($this->Sendmail));
1341
            } else {
1342
                $sendmail = sprintf('%s -oi -t', escapeshellcmd($this->Sendmail));
1343
            }
1344
        }
1345
        if ($this->SingleTo) {
1346
            foreach ($this->SingleToArray as $toAddr) {
1347 View Code Duplication
                if (!@$mail = popen($sendmail, 'w')) {
1348
                    throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
1349
                }
1350
                fputs($mail, 'To: ' . $toAddr . "\n");
1351
                fputs($mail, $header);
1352
                fputs($mail, $body);
1353
                $result = pclose($mail);
1354
                $this->doCallback(
1355
                    ($result == 0),
1356
                    array($toAddr),
1357
                    $this->cc,
1358
                    $this->bcc,
1359
                    $this->Subject,
1360
                    $body,
1361
                    $this->From
1362
                );
1363
                if ($result != 0) {
1364
                    throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
1365
                }
1366
            }
1367
        } else {
1368 View Code Duplication
            if (!@$mail = popen($sendmail, 'w')) {
1369
                throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
1370
            }
1371
            fputs($mail, $header);
1372
            fputs($mail, $body);
1373
            $result = pclose($mail);
1374
            $this->doCallback(
1375
                ($result == 0),
1376
                $this->to,
1377
                $this->cc,
1378
                $this->bcc,
1379
                $this->Subject,
1380
                $body,
1381
                $this->From
1382
            );
1383
            if ($result != 0) {
1384
                throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
1385
            }
1386
        }
1387
        return true;
1388
    }
1389
1390
    /**
1391
     * Send mail using the PHP mail() function.
1392
     * @param string $header The message headers
1393
     * @param string $body The message body
1394
     * @link http://www.php.net/manual/en/book.mail.php
1395
     * @throws phpmailerException
1396
     * @access protected
1397
     * @return boolean
1398
     */
1399
    protected function mailSend($header, $body)
1400
    {
1401
        $toArr = array();
1402
        foreach ($this->to as $toaddr) {
1403
            $toArr[] = $this->addrFormat($toaddr);
1404
        }
1405
        $to = implode(', ', $toArr);
1406
1407
        if (empty($this->Sender)) {
1408
            $params = ' ';
1409
        } else {
1410
            $params = sprintf('-f%s', $this->Sender);
1411
        }
1412
        if ($this->Sender != '' and !ini_get('safe_mode')) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1413
            $old_from = ini_get('sendmail_from');
1414
            ini_set('sendmail_from', $this->Sender);
1415
        }
1416
        $result = false;
1417
        if ($this->SingleTo && count($toArr) > 1) {
1418
            foreach ($toArr as $toAddr) {
1419
                $result = $this->mailPassthru($toAddr, $this->Subject, $body, $header, $params);
1420
                $this->doCallback($result, array($toAddr), $this->cc, $this->bcc, $this->Subject, $body, $this->From);
1421
            }
1422
        } else {
1423
            $result = $this->mailPassthru($to, $this->Subject, $body, $header, $params);
1424
            $this->doCallback($result, $this->to, $this->cc, $this->bcc, $this->Subject, $body, $this->From);
1425
        }
1426
        if (isset($old_from)) {
1427
            ini_set('sendmail_from', $old_from);
1428
        }
1429
        if (!$result) {
1430
            throw new phpmailerException($this->lang('instantiate'), self::STOP_CRITICAL);
1431
        }
1432
        return true;
1433
    }
1434
1435
    /**
1436
     * Get an instance to use for SMTP operations.
1437
     * Override this function to load your own SMTP implementation
1438
     * @return SMTP
1439
     */
1440
    public function getSMTPInstance()
1441
    {
1442
        if (!is_object($this->smtp)) {
1443
            $this->smtp = new SMTP;
1444
        }
1445
        return $this->smtp;
1446
    }
1447
1448
    /**
1449
     * Send mail via SMTP.
1450
     * Returns false if there is a bad MAIL FROM, RCPT, or DATA input.
1451
     * Uses the PHPMailerSMTP class by default.
1452
     * @see PHPMailer::getSMTPInstance() to use a different class.
1453
     * @param string $header The message headers
1454
     * @param string $body The message body
1455
     * @throws phpmailerException
1456
     * @uses SMTP
1457
     * @access protected
1458
     * @return boolean
1459
     */
1460
    protected function smtpSend($header, $body)
1461
    {
1462
        $bad_rcpt = array();
1463
        if (!$this->smtpConnect($this->SMTPOptions)) {
1464
            throw new phpmailerException($this->lang('smtp_connect_failed'), self::STOP_CRITICAL);
1465
        }
1466
        if ('' == $this->Sender) {
1467
            $smtp_from = $this->From;
1468
        } else {
1469
            $smtp_from = $this->Sender;
1470
        }
1471
        if (!$this->smtp->mail($smtp_from)) {
1472
            $this->setError($this->lang('from_failed') . $smtp_from . ' : ' . implode(',', $this->smtp->getError()));
1473
            throw new phpmailerException($this->ErrorInfo, self::STOP_CRITICAL);
1474
        }
1475
1476
        // Attempt to send to all recipients
1477
        foreach (array($this->to, $this->cc, $this->bcc) as $togroup) {
1478
            foreach ($togroup as $to) {
1479
                if (!$this->smtp->recipient($to[0])) {
1480
                    $error = $this->smtp->getError();
1481
                    $bad_rcpt[] = array('to' => $to[0], 'error' => $error['detail']);
1482
                    $isSent = false;
1483
                } else {
1484
                    $isSent = true;
1485
                }
1486
                $this->doCallback($isSent, array($to[0]), array(), array(), $this->Subject, $body, $this->From);
1487
            }
1488
        }
1489
1490
        // Only send the DATA command if we have viable recipients
1491
        if ((count($this->all_recipients) > count($bad_rcpt)) and !$this->smtp->data($header . $body)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1492
            throw new phpmailerException($this->lang('data_not_accepted'), self::STOP_CRITICAL);
1493
        }
1494
        if ($this->SMTPKeepAlive) {
1495
            $this->smtp->reset();
1496
        } else {
1497
            $this->smtp->quit();
1498
            $this->smtp->close();
1499
        }
1500
        //Create error message for any bad addresses
1501
        if (count($bad_rcpt) > 0) {
1502
            $errstr = '';
1503
            foreach ($bad_rcpt as $bad) {
1504
                $errstr .= $bad['to'] . ': ' . $bad['error'];
1505
            }
1506
            throw new phpmailerException(
1507
                $this->lang('recipients_failed') . $errstr,
1508
                self::STOP_CONTINUE
1509
            );
1510
        }
1511
        return true;
1512
    }
1513
1514
    /**
1515
     * Initiate a connection to an SMTP server.
1516
     * Returns false if the operation failed.
1517
     * @param array $options An array of options compatible with stream_context_create()
1518
     * @uses SMTP
1519
     * @access public
1520
     * @throws phpmailerException
1521
     * @return boolean
1522
     */
1523
    public function smtpConnect($options = array())
1524
    {
1525
        if (is_null($this->smtp)) {
1526
            $this->smtp = $this->getSMTPInstance();
1527
        }
1528
1529
        // Already connected?
1530
        if ($this->smtp->connected()) {
1531
            return true;
1532
        }
1533
1534
        $this->smtp->setTimeout($this->Timeout);
1535
        $this->smtp->setDebugLevel($this->SMTPDebug);
1536
        $this->smtp->setDebugOutput($this->Debugoutput);
1537
        $this->smtp->setVerp($this->do_verp);
1538
        $hosts = explode(';', $this->Host);
1539
        $lastexception = null;
1540
1541 View Code Duplication
        foreach ($hosts as $hostentry) {
1542
            $hostinfo = array();
1543
            if (!preg_match('/^((ssl|tls):\/\/)*([a-zA-Z0-9\.-]*):?([0-9]*)$/', trim($hostentry), $hostinfo)) {
1544
                // Not a valid host entry
1545
                continue;
1546
            }
1547
            // $hostinfo[2]: optional ssl or tls prefix
1548
            // $hostinfo[3]: the hostname
1549
            // $hostinfo[4]: optional port number
1550
            // The host string prefix can temporarily override the current setting for SMTPSecure
1551
            // If it's not specified, the default value is used
1552
            $prefix = '';
1553
            $secure = $this->SMTPSecure;
1554
            $tls = ($this->SMTPSecure == 'tls');
1555
            if ('ssl' == $hostinfo[2] or ('' == $hostinfo[2] and 'ssl' == $this->SMTPSecure)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1556
                $prefix = 'ssl://';
1557
                $tls = false; // Can't have SSL and TLS at the same time
1558
                $secure = 'ssl';
1559
            } elseif ($hostinfo[2] == 'tls') {
1560
                $tls = true;
1561
                // tls doesn't use a prefix
1562
                $secure = 'tls';
1563
            }
1564
            //Do we need the OpenSSL extension?
1565
            $sslext = defined('OPENSSL_ALGO_SHA1');
1566
            if ('tls' === $secure or 'ssl' === $secure) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1567
                //Check for an OpenSSL constant rather than using extension_loaded, which is sometimes disabled
1568
                if (!$sslext) {
1569
                    throw new phpmailerException($this->lang('extension_missing').'openssl', self::STOP_CRITICAL);
1570
                }
1571
            }
1572
            $host = $hostinfo[3];
1573
            $port = $this->Port;
1574
            $tport = (integer)$hostinfo[4];
1575
            if ($tport > 0 and $tport < 65536) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1576
                $port = $tport;
1577
            }
1578
            if ($this->smtp->connect($prefix . $host, $port, $this->Timeout, $options)) {
1579
                try {
1580
                    if ($this->Helo) {
1581
                        $hello = $this->Helo;
1582
                    } else {
1583
                        $hello = $this->serverHostname();
1584
                    }
1585
                    $this->smtp->hello($hello);
1586
                    //Automatically enable TLS encryption if:
1587
                    // * it's not disabled
1588
                    // * we have openssl extension
1589
                    // * we are not already using SSL
1590
                    // * the server offers STARTTLS
1591
                    if ($this->SMTPAutoTLS and $sslext and $secure != 'ssl' and $this->smtp->getServerExt('STARTTLS')) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1592
                        $tls = true;
1593
                    }
1594
                    if ($tls) {
1595
                        if (!$this->smtp->startTLS()) {
1596
                            throw new phpmailerException($this->lang('connect_host'));
1597
                        }
1598
                        // We must resend HELO after tls negotiation
1599
                        $this->smtp->hello($hello);
1600
                    }
1601
                    if ($this->SMTPAuth) {
1602
                        if (!$this->smtp->authenticate(
1603
                            $this->Username,
1604
                            $this->Password,
1605
                            $this->AuthType,
1606
                            $this->Realm,
1607
                            $this->Workstation
1608
                        )
1609
                        ) {
1610
                            throw new phpmailerException($this->lang('authenticate'));
1611
                        }
1612
                    }
1613
                    return true;
1614
                } catch (phpmailerException $exc) {
1615
                    $lastexception = $exc;
1616
                    $this->edebug($exc->getMessage());
1617
                    // We must have connected, but then failed TLS or Auth, so close connection nicely
1618
                    $this->smtp->quit();
1619
                }
1620
            }
1621
        }
1622
        // If we get here, all connection attempts have failed, so close connection hard
1623
        $this->smtp->close();
1624
        // As we've caught all exceptions, just report whatever the last one was
1625
        if ($this->exceptions and !is_null($lastexception)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1626
            throw $lastexception;
1627
        }
1628
        return false;
1629
    }
1630
1631
    /**
1632
     * Close the active SMTP session if one exists.
1633
     * @return void
1634
     */
1635
    public function smtpClose()
1636
    {
1637
        if ($this->smtp !== null) {
1638
            if ($this->smtp->connected()) {
1639
                $this->smtp->quit();
1640
                $this->smtp->close();
1641
            }
1642
        }
1643
    }
1644
1645
    /**
1646
     * Set the language for error messages.
1647
     * Returns false if it cannot load the language file.
1648
     * The default language is English.
1649
     * @param string $langcode ISO 639-1 2-character language code (e.g. French is "fr")
1650
     * @param string $lang_path Path to the language file directory, with trailing separator (slash)
1651
     * @return boolean
1652
     * @access public
1653
     */
1654
    public function setLanguage($langcode = 'en', $lang_path = '')
1655
    {
1656
        // Define full set of translatable strings in English
1657
        $PHPMAILER_LANG = array(
1658
            'authenticate' => 'SMTP Error: Could not authenticate.',
1659
            'connect_host' => 'SMTP Error: Could not connect to SMTP host.',
1660
            'data_not_accepted' => 'SMTP Error: data not accepted.',
1661
            'empty_message' => 'Message body empty',
1662
            'encoding' => 'Unknown encoding: ',
1663
            'execute' => 'Could not execute: ',
1664
            'file_access' => 'Could not access file: ',
1665
            'file_open' => 'File Error: Could not open file: ',
1666
            'from_failed' => 'The following From address failed: ',
1667
            'instantiate' => 'Could not instantiate mail function.',
1668
            'invalid_address' => 'Invalid address: ',
1669
            'mailer_not_supported' => ' mailer is not supported.',
1670
            'provide_address' => 'You must provide at least one recipient email address.',
1671
            'recipients_failed' => 'SMTP Error: The following recipients failed: ',
1672
            'signing' => 'Signing Error: ',
1673
            'smtp_connect_failed' => 'SMTP connect() failed.',
1674
            'smtp_error' => 'SMTP server error: ',
1675
            'variable_set' => 'Cannot set or reset variable: ',
1676
            'extension_missing' => 'Extension missing: '
1677
        );
1678
        if (empty($lang_path)) {
1679
            // Calculate an absolute path so it can work if CWD is not here
1680
            $lang_path = dirname(__FILE__). DIRECTORY_SEPARATOR . 'language'. DIRECTORY_SEPARATOR;
1681
        }
1682
        $foundlang = true;
1683
        $lang_file = $lang_path . 'phpmailer.lang-' . $langcode . '.php';
1684
        // There is no English translation file
1685
        if ($langcode != 'en') {
1686
            // Make sure language file path is readable
1687
            if (!is_readable($lang_file)) {
1688
                $foundlang = false;
1689
            } else {
1690
                // Overwrite language-specific strings.
1691
                // This way we'll never have missing translation keys.
1692
                $foundlang = include $lang_file;
1693
            }
1694
        }
1695
        $this->language = $PHPMAILER_LANG;
1696
        return (boolean)$foundlang; // Returns false if language not found
1697
    }
1698
1699
    /**
1700
     * Get the array of strings for the current language.
1701
     * @return array
1702
     */
1703
    public function getTranslations()
1704
    {
1705
        return $this->language;
1706
    }
1707
1708
    /**
1709
     * Create recipient headers.
1710
     * @access public
1711
     * @param string $type
1712
     * @param array $addr An array of recipient,
1713
     * where each recipient is a 2-element indexed array with element 0 containing an address
1714
     * and element 1 containing a name, like:
1715
     * array(array('[email protected]', 'Joe User'), array('[email protected]', 'Zoe User'))
1716
     * @return string
1717
     */
1718
    public function addrAppend($type, $addr)
1719
    {
1720
        $addresses = array();
1721
        foreach ($addr as $address) {
1722
            $addresses[] = $this->addrFormat($address);
1723
        }
1724
        return $type . ': ' . implode(', ', $addresses) . $this->LE;
1725
    }
1726
1727
    /**
1728
     * Format an address for use in a message header.
1729
     * @access public
1730
     * @param array $addr A 2-element indexed array, element 0 containing an address, element 1 containing a name
1731
     *      like array('[email protected]', 'Joe User')
1732
     * @return string
1733
     */
1734
    public function addrFormat($addr)
1735
    {
1736
        if (empty($addr[1])) { // No name provided
1737
            return $this->secureHeader($addr[0]);
1738
        } else {
1739
            return $this->encodeHeader($this->secureHeader($addr[1]), 'phrase') . ' <' . $this->secureHeader(
1740
                $addr[0]
1741
            ) . '>';
1742
        }
1743
    }
1744
1745
    /**
1746
     * Word-wrap message.
1747
     * For use with mailers that do not automatically perform wrapping
1748
     * and for quoted-printable encoded messages.
1749
     * Original written by philippe.
1750
     * @param string $message The message to wrap
1751
     * @param integer $length The line length to wrap to
1752
     * @param boolean $qp_mode Whether to run in Quoted-Printable mode
1753
     * @access public
1754
     * @return string
1755
     */
1756
    public function wrapText($message, $length, $qp_mode = false)
1757
    {
1758
        if ($qp_mode) {
1759
            $soft_break = sprintf(' =%s', $this->LE);
1760
        } else {
1761
            $soft_break = $this->LE;
1762
        }
1763
        // If utf-8 encoding is used, we will need to make sure we don't
1764
        // split multibyte characters when we wrap
1765
        $is_utf8 = (strtolower($this->CharSet) == 'utf-8');
1766
        $lelen = strlen($this->LE);
1767
        $crlflen = strlen(self::CRLF);
1768
1769
        $message = $this->fixEOL($message);
1770
        //Remove a trailing line break
1771
        if (substr($message, -$lelen) == $this->LE) {
1772
            $message = substr($message, 0, -$lelen);
1773
        }
1774
1775
        //Split message into lines
1776
        $lines = explode($this->LE, $message);
1777
        //Message will be rebuilt in here
1778
        $message = '';
1779
        foreach ($lines as $line) {
1780
            $words = explode(' ', $line);
1781
            $buf = '';
1782
            $firstword = true;
1783
            foreach ($words as $word) {
1784
                if ($qp_mode and (strlen($word) > $length)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1785
                    $space_left = $length - strlen($buf) - $crlflen;
1786
                    if (!$firstword) {
1787
                        if ($space_left > 20) {
1788
                            $len = $space_left;
1789 View Code Duplication
                            if ($is_utf8) {
1790
                                $len = $this->utf8CharBoundary($word, $len);
1791
                            } elseif (substr($word, $len - 1, 1) == '=') {
1792
                                $len--;
1793
                            } elseif (substr($word, $len - 2, 1) == '=') {
1794
                                $len -= 2;
1795
                            }
1796
                            $part = substr($word, 0, $len);
1797
                            $word = substr($word, $len);
1798
                            $buf .= ' ' . $part;
1799
                            $message .= $buf . sprintf('=%s', self::CRLF);
1800
                        } else {
1801
                            $message .= $buf . $soft_break;
1802
                        }
1803
                        $buf = '';
1804
                    }
1805
                    while (strlen($word) > 0) {
1806
                        if ($length <= 0) {
1807
                            break;
1808
                        }
1809
                        $len = $length;
1810 View Code Duplication
                        if ($is_utf8) {
1811
                            $len = $this->utf8CharBoundary($word, $len);
1812
                        } elseif (substr($word, $len - 1, 1) == '=') {
1813
                            $len--;
1814
                        } elseif (substr($word, $len - 2, 1) == '=') {
1815
                            $len -= 2;
1816
                        }
1817
                        $part = substr($word, 0, $len);
1818
                        $word = substr($word, $len);
1819
1820
                        if (strlen($word) > 0) {
1821
                            $message .= $part . sprintf('=%s', self::CRLF);
1822
                        } else {
1823
                            $buf = $part;
1824
                        }
1825
                    }
1826
                } else {
1827
                    $buf_o = $buf;
1828
                    if (!$firstword) {
1829
                        $buf .= ' ';
1830
                    }
1831
                    $buf .= $word;
1832
1833
                    if (strlen($buf) > $length and $buf_o != '') {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1834
                        $message .= $buf_o . $soft_break;
1835
                        $buf = $word;
1836
                    }
1837
                }
1838
                $firstword = false;
1839
            }
1840
            $message .= $buf . self::CRLF;
1841
        }
1842
1843
        return $message;
1844
    }
1845
1846
    /**
1847
     * Find the last character boundary prior to $maxLength in a utf-8
1848
     * quoted-printable encoded string.
1849
     * Original written by Colin Brown.
1850
     * @access public
1851
     * @param string $encodedText utf-8 QP text
1852
     * @param integer $maxLength Find the last character boundary prior to this length
1853
     * @return integer
1854
     */
1855
    public function utf8CharBoundary($encodedText, $maxLength)
1856
    {
1857
        $foundSplitPos = false;
1858
        $lookBack = 3;
1859
        while (!$foundSplitPos) {
1860
            $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack);
1861
            $encodedCharPos = strpos($lastChunk, '=');
1862
            if (false !== $encodedCharPos) {
1863
                // Found start of encoded character byte within $lookBack block.
1864
                // Check the encoded byte value (the 2 chars after the '=')
1865
                $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2);
1866
                $dec = hexdec($hex);
1867
                if ($dec < 128) {
1868
                    // Single byte character.
1869
                    // If the encoded char was found at pos 0, it will fit
1870
                    // otherwise reduce maxLength to start of the encoded char
1871
                    if ($encodedCharPos > 0) {
1872
                        $maxLength = $maxLength - ($lookBack - $encodedCharPos);
1873
                    }
1874
                    $foundSplitPos = true;
1875
                } elseif ($dec >= 192) {
1876
                    // First byte of a multi byte character
1877
                    // Reduce maxLength to split at start of character
1878
                    $maxLength = $maxLength - ($lookBack - $encodedCharPos);
1879
                    $foundSplitPos = true;
1880
                } elseif ($dec < 192) {
1881
                    // Middle byte of a multi byte character, look further back
1882
                    $lookBack += 3;
1883
                }
1884
            } else {
1885
                // No encoded character found
1886
                $foundSplitPos = true;
1887
            }
1888
        }
1889
        return $maxLength;
1890
    }
1891
1892
    /**
1893
     * Apply word wrapping to the message body.
1894
     * Wraps the message body to the number of chars set in the WordWrap property.
1895
     * You should only do this to plain-text bodies as wrapping HTML tags may break them.
1896
     * This is called automatically by createBody(), so you don't need to call it yourself.
1897
     * @access public
1898
     * @return void
1899
     */
1900
    public function setWordWrap()
1901
    {
1902
        if ($this->WordWrap < 1) {
1903
            return;
1904
        }
1905
1906
        switch ($this->message_type) {
1907
            case 'alt':
1908
            case 'alt_inline':
1909
            case 'alt_attach':
1910
            case 'alt_inline_attach':
1911
                $this->AltBody = $this->wrapText($this->AltBody, $this->WordWrap);
1912
                break;
1913
            default:
1914
                $this->Body = $this->wrapText($this->Body, $this->WordWrap);
1915
                break;
1916
        }
1917
    }
1918
1919
    /**
1920
     * Assemble message headers.
1921
     * @access public
1922
     * @return string The assembled headers
1923
     */
1924
    public function createHeader()
1925
    {
1926
        $result = '';
1927
1928
        if ($this->MessageDate == '') {
1929
            $this->MessageDate = self::rfcDate();
1930
        }
1931
        $result .= $this->headerLine('Date', $this->MessageDate);
1932
1933
        // To be created automatically by mail()
1934
        if ($this->SingleTo) {
1935
            if ($this->Mailer != 'mail') {
1936
                foreach ($this->to as $toaddr) {
1937
                    $this->SingleToArray[] = $this->addrFormat($toaddr);
1938
                }
1939
            }
1940
        } else {
1941
            if (count($this->to) > 0) {
1942
                if ($this->Mailer != 'mail') {
1943
                    $result .= $this->addrAppend('To', $this->to);
1944
                }
1945
            } elseif (count($this->cc) == 0) {
1946
                $result .= $this->headerLine('To', 'undisclosed-recipients:;');
1947
            }
1948
        }
1949
1950
        $result .= $this->addrAppend('From', array(array(trim($this->From), $this->FromName)));
1951
1952
        // sendmail and mail() extract Cc from the header before sending
1953
        if (count($this->cc) > 0) {
1954
            $result .= $this->addrAppend('Cc', $this->cc);
1955
        }
1956
1957
        // sendmail and mail() extract Bcc from the header before sending
1958
        if ((
1959
                $this->Mailer == 'sendmail' or $this->Mailer == 'qmail' or $this->Mailer == 'mail'
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1960
            )
1961
            and count($this->bcc) > 0
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1962
        ) {
1963
            $result .= $this->addrAppend('Bcc', $this->bcc);
1964
        }
1965
1966
        if (count($this->ReplyTo) > 0) {
1967
            $result .= $this->addrAppend('Reply-To', $this->ReplyTo);
1968
        }
1969
1970
        // mail() sets the subject itself
1971
        if ($this->Mailer != 'mail') {
1972
            $result .= $this->headerLine('Subject', $this->encodeHeader($this->secureHeader($this->Subject)));
1973
        }
1974
1975
        if ($this->MessageID != '') {
1976
            $this->lastMessageID = $this->MessageID;
1977
        } else {
1978
            $this->lastMessageID = sprintf('<%s@%s>', $this->uniqueid, $this->serverHostname());
1979
        }
1980
        $result .= $this->headerLine('Message-ID', $this->lastMessageID);
1981
        if (!is_null($this->Priority)) {
1982
            $result .= $this->headerLine('X-Priority', $this->Priority);
1983
        }
1984
        if ($this->XMailer == '') {
1985
            $result .= $this->headerLine(
1986
                'X-Mailer',
1987
                'PHPMailer ' . $this->Version . ' (https://github.com/PHPMailer/PHPMailer)'
1988
            );
1989
        } else {
1990
            $myXmailer = trim($this->XMailer);
1991
            if ($myXmailer) {
1992
                $result .= $this->headerLine('X-Mailer', $myXmailer);
1993
            }
1994
        }
1995
1996
        if ($this->ConfirmReadingTo != '') {
1997
            $result .= $this->headerLine('Disposition-Notification-To', '<' . $this->ConfirmReadingTo . '>');
1998
        }
1999
2000
        // Add custom headers
2001
        foreach ($this->CustomHeader as $header) {
2002
            $result .= $this->headerLine(
2003
                trim($header[0]),
2004
                $this->encodeHeader(trim($header[1]))
2005
            );
2006
        }
2007
        if (!$this->sign_key_file) {
2008
            $result .= $this->headerLine('MIME-Version', '1.0');
2009
            $result .= $this->getMailMIME();
2010
        }
2011
2012
        return $result;
2013
    }
2014
2015
    /**
2016
     * Get the message MIME type headers.
2017
     * @access public
2018
     * @return string
2019
     */
2020
    public function getMailMIME()
2021
    {
2022
        $result = '';
2023
        $ismultipart = true;
2024
        switch ($this->message_type) {
2025 View Code Duplication
            case 'inline':
2026
                $result .= $this->headerLine('Content-Type', 'multipart/related;');
2027
                $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
2028
                break;
2029
            case 'attach':
2030
            case 'inline_attach':
2031
            case 'alt_attach':
2032 View Code Duplication
            case 'alt_inline_attach':
2033
                $result .= $this->headerLine('Content-Type', 'multipart/mixed;');
2034
                $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
2035
                break;
2036
            case 'alt':
2037 View Code Duplication
            case 'alt_inline':
2038
                $result .= $this->headerLine('Content-Type', 'multipart/alternative;');
2039
                $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
2040
                break;
2041
            default:
2042
                // Catches case 'plain': and case '':
2043
                $result .= $this->textLine('Content-Type: ' . $this->ContentType . '; charset=' . $this->CharSet);
2044
                $ismultipart = false;
2045
                break;
2046
        }
2047
        // RFC1341 part 5 says 7bit is assumed if not specified
2048
        if ($this->Encoding != '7bit') {
2049
            // RFC 2045 section 6.4 says multipart MIME parts may only use 7bit, 8bit or binary CTE
2050
            if ($ismultipart) {
2051
                if ($this->Encoding == '8bit') {
2052
                    $result .= $this->headerLine('Content-Transfer-Encoding', '8bit');
2053
                }
2054
                // The only remaining alternatives are quoted-printable and base64, which are both 7bit compatible
2055
            } else {
2056
                $result .= $this->headerLine('Content-Transfer-Encoding', $this->Encoding);
2057
            }
2058
        }
2059
2060
        if ($this->Mailer != 'mail') {
2061
            $result .= $this->LE;
2062
        }
2063
2064
        return $result;
2065
    }
2066
2067
    /**
2068
     * Returns the whole MIME message.
2069
     * Includes complete headers and body.
2070
     * Only valid post preSend().
2071
     * @see PHPMailer::preSend()
2072
     * @access public
2073
     * @return string
2074
     */
2075
    public function getSentMIMEMessage()
2076
    {
2077
        return $this->MIMEHeader . $this->mailHeader . self::CRLF . $this->MIMEBody;
2078
    }
2079
2080
    /**
2081
     * Assemble the message body.
2082
     * Returns an empty string on failure.
2083
     * @access public
2084
     * @throws phpmailerException
2085
     * @return string The assembled message body
2086
     */
2087
    public function createBody()
2088
    {
2089
        $body = '';
2090
        //Create unique IDs and preset boundaries
2091
        $this->uniqueid = md5(uniqid(time()));
2092
        $this->boundary[1] = 'b1_' . $this->uniqueid;
2093
        $this->boundary[2] = 'b2_' . $this->uniqueid;
2094
        $this->boundary[3] = 'b3_' . $this->uniqueid;
2095
2096
        if ($this->sign_key_file) {
2097
            $body .= $this->getMailMIME() . $this->LE;
2098
        }
2099
2100
        $this->setWordWrap();
2101
2102
        $bodyEncoding = $this->Encoding;
2103
        $bodyCharSet = $this->CharSet;
2104
        //Can we do a 7-bit downgrade?
2105
        if ($bodyEncoding == '8bit' and !$this->has8bitChars($this->Body)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
2106
            $bodyEncoding = '7bit';
2107
            $bodyCharSet = 'us-ascii';
2108
        }
2109
        //If lines are too long, and we're not already using an encoding that will shorten them,
2110
        //change to quoted-printable transfer encoding
2111
        if ('base64' != $this->Encoding and self::hasLineLongerThanMax($this->Body)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
2112
            $this->Encoding = 'quoted-printable';
2113
            $bodyEncoding = 'quoted-printable';
2114
        }
2115
2116
        $altBodyEncoding = $this->Encoding;
2117
        $altBodyCharSet = $this->CharSet;
2118
        //Can we do a 7-bit downgrade?
2119
        if ($altBodyEncoding == '8bit' and !$this->has8bitChars($this->AltBody)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
2120
            $altBodyEncoding = '7bit';
2121
            $altBodyCharSet = 'us-ascii';
2122
        }
2123
        //If lines are too long, change to quoted-printable transfer encoding
2124
        if (self::hasLineLongerThanMax($this->AltBody)) {
2125
            $altBodyEncoding = 'quoted-printable';
2126
        }
2127
        //Use this as a preamble in all multipart message types
2128
        $mimepre = "This is a multi-part message in MIME format." . $this->LE . $this->LE;
2129
        switch ($this->message_type) {
2130 View Code Duplication
            case 'inline':
2131
                $body .= $mimepre;
2132
                $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding);
2133
                $body .= $this->encodeString($this->Body, $bodyEncoding);
2134
                $body .= $this->LE . $this->LE;
2135
                $body .= $this->attachAll('inline', $this->boundary[1]);
2136
                break;
2137 View Code Duplication
            case 'attach':
2138
                $body .= $mimepre;
2139
                $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding);
2140
                $body .= $this->encodeString($this->Body, $bodyEncoding);
2141
                $body .= $this->LE . $this->LE;
2142
                $body .= $this->attachAll('attachment', $this->boundary[1]);
2143
                break;
2144
            case 'inline_attach':
2145
                $body .= $mimepre;
2146
                $body .= $this->textLine('--' . $this->boundary[1]);
2147
                $body .= $this->headerLine('Content-Type', 'multipart/related;');
2148
                $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
2149
                $body .= $this->LE;
2150
                $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, '', $bodyEncoding);
2151
                $body .= $this->encodeString($this->Body, $bodyEncoding);
2152
                $body .= $this->LE . $this->LE;
2153
                $body .= $this->attachAll('inline', $this->boundary[2]);
2154
                $body .= $this->LE;
2155
                $body .= $this->attachAll('attachment', $this->boundary[1]);
2156
                break;
2157
            case 'alt':
2158
                $body .= $mimepre;
2159
                $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding);
2160
                $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
2161
                $body .= $this->LE . $this->LE;
2162
                $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, 'text/html', $bodyEncoding);
2163
                $body .= $this->encodeString($this->Body, $bodyEncoding);
2164
                $body .= $this->LE . $this->LE;
2165
                if (!empty($this->Ical)) {
2166
                    $body .= $this->getBoundary($this->boundary[1], '', 'text/calendar; method=REQUEST', '');
2167
                    $body .= $this->encodeString($this->Ical, $this->Encoding);
2168
                    $body .= $this->LE . $this->LE;
2169
                }
2170
                $body .= $this->endBoundary($this->boundary[1]);
2171
                break;
2172 View Code Duplication
            case 'alt_inline':
2173
                $body .= $mimepre;
2174
                $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding);
2175
                $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
2176
                $body .= $this->LE . $this->LE;
2177
                $body .= $this->textLine('--' . $this->boundary[1]);
2178
                $body .= $this->headerLine('Content-Type', 'multipart/related;');
2179
                $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
2180
                $body .= $this->LE;
2181
                $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding);
2182
                $body .= $this->encodeString($this->Body, $bodyEncoding);
2183
                $body .= $this->LE . $this->LE;
2184
                $body .= $this->attachAll('inline', $this->boundary[2]);
2185
                $body .= $this->LE;
2186
                $body .= $this->endBoundary($this->boundary[1]);
2187
                break;
2188 View Code Duplication
            case 'alt_attach':
2189
                $body .= $mimepre;
2190
                $body .= $this->textLine('--' . $this->boundary[1]);
2191
                $body .= $this->headerLine('Content-Type', 'multipart/alternative;');
2192
                $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
2193
                $body .= $this->LE;
2194
                $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding);
2195
                $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
2196
                $body .= $this->LE . $this->LE;
2197
                $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding);
2198
                $body .= $this->encodeString($this->Body, $bodyEncoding);
2199
                $body .= $this->LE . $this->LE;
2200
                $body .= $this->endBoundary($this->boundary[2]);
2201
                $body .= $this->LE;
2202
                $body .= $this->attachAll('attachment', $this->boundary[1]);
2203
                break;
2204
            case 'alt_inline_attach':
2205
                $body .= $mimepre;
2206
                $body .= $this->textLine('--' . $this->boundary[1]);
2207
                $body .= $this->headerLine('Content-Type', 'multipart/alternative;');
2208
                $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
2209
                $body .= $this->LE;
2210
                $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding);
2211
                $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
2212
                $body .= $this->LE . $this->LE;
2213
                $body .= $this->textLine('--' . $this->boundary[2]);
2214
                $body .= $this->headerLine('Content-Type', 'multipart/related;');
2215
                $body .= $this->textLine("\tboundary=\"" . $this->boundary[3] . '"');
2216
                $body .= $this->LE;
2217
                $body .= $this->getBoundary($this->boundary[3], $bodyCharSet, 'text/html', $bodyEncoding);
2218
                $body .= $this->encodeString($this->Body, $bodyEncoding);
2219
                $body .= $this->LE . $this->LE;
2220
                $body .= $this->attachAll('inline', $this->boundary[3]);
2221
                $body .= $this->LE;
2222
                $body .= $this->endBoundary($this->boundary[2]);
2223
                $body .= $this->LE;
2224
                $body .= $this->attachAll('attachment', $this->boundary[1]);
2225
                break;
2226
            default:
2227
                // catch case 'plain' and case ''
2228
                $body .= $this->encodeString($this->Body, $bodyEncoding);
2229
                break;
2230
        }
2231
2232
        if ($this->isError()) {
2233
            $body = '';
2234
        } elseif ($this->sign_key_file) {
2235
            try {
2236
                if (!defined('PKCS7_TEXT')) {
2237
                    throw new phpmailerException($this->lang('extension_missing') . 'openssl');
2238
                }
2239
                // @TODO would be nice to use php://temp streams here, but need to wrap for PHP < 5.1
2240
                $file = tempnam(sys_get_temp_dir(), 'mail');
2241
                if (false === file_put_contents($file, $body)) {
2242
                    throw new phpmailerException($this->lang('signing') . ' Could not write temp file');
2243
                }
2244
                $signed = tempnam(sys_get_temp_dir(), 'signed');
2245
                //Workaround for PHP bug https://bugs.php.net/bug.php?id=69197
2246
                if (empty($this->sign_extracerts_file)) {
2247
                    $sign = @openssl_pkcs7_sign(
2248
                        $file,
2249
                        $signed,
2250
                        'file://' . realpath($this->sign_cert_file),
2251
                        array('file://' . realpath($this->sign_key_file), $this->sign_key_pass),
2252
                        null
2253
                    );
2254
                } else {
2255
                    $sign = @openssl_pkcs7_sign(
2256
                        $file,
2257
                        $signed,
2258
                        'file://' . realpath($this->sign_cert_file),
2259
                        array('file://' . realpath($this->sign_key_file), $this->sign_key_pass),
2260
                        null,
2261
                        PKCS7_DETACHED,
2262
                        $this->sign_extracerts_file
2263
                    );
2264
                }
2265
                if ($sign) {
2266
                    @unlink($file);
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...
2267
                    $body = file_get_contents($signed);
2268
                    @unlink($signed);
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...
2269
                    //The message returned by openssl contains both headers and body, so need to split them up
2270
                    $parts = explode("\n\n", $body, 2);
2271
                    $this->MIMEHeader .= $parts[0] . $this->LE . $this->LE;
2272
                    $body = $parts[1];
2273
                } else {
2274
                    @unlink($file);
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...
2275
                    @unlink($signed);
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...
2276
                    throw new phpmailerException($this->lang('signing') . openssl_error_string());
2277
                }
2278
            } catch (phpmailerException $exc) {
2279
                $body = '';
2280
                if ($this->exceptions) {
2281
                    throw $exc;
2282
                }
2283
            }
2284
        }
2285
        return $body;
2286
    }
2287
2288
    /**
2289
     * Return the start of a message boundary.
2290
     * @access protected
2291
     * @param string $boundary
2292
     * @param string $charSet
2293
     * @param string $contentType
2294
     * @param string $encoding
2295
     * @return string
2296
     */
2297
    protected function getBoundary($boundary, $charSet, $contentType, $encoding)
2298
    {
2299
        $result = '';
2300
        if ($charSet == '') {
2301
            $charSet = $this->CharSet;
2302
        }
2303
        if ($contentType == '') {
2304
            $contentType = $this->ContentType;
2305
        }
2306
        if ($encoding == '') {
2307
            $encoding = $this->Encoding;
2308
        }
2309
        $result .= $this->textLine('--' . $boundary);
2310
        $result .= sprintf('Content-Type: %s; charset=%s', $contentType, $charSet);
2311
        $result .= $this->LE;
2312
        // RFC1341 part 5 says 7bit is assumed if not specified
2313
        if ($encoding != '7bit') {
2314
            $result .= $this->headerLine('Content-Transfer-Encoding', $encoding);
2315
        }
2316
        $result .= $this->LE;
2317
2318
        return $result;
2319
    }
2320
2321
    /**
2322
     * Return the end of a message boundary.
2323
     * @access protected
2324
     * @param string $boundary
2325
     * @return string
2326
     */
2327
    protected function endBoundary($boundary)
2328
    {
2329
        return $this->LE . '--' . $boundary . '--' . $this->LE;
2330
    }
2331
2332
    /**
2333
     * Set the message type.
2334
     * PHPMailer only supports some preset message types,
2335
     * not arbitrary MIME structures.
2336
     * @access protected
2337
     * @return void
2338
     */
2339
    protected function setMessageType()
2340
    {
2341
        $type = array();
2342
        if ($this->alternativeExists()) {
2343
            $type[] = 'alt';
2344
        }
2345
        if ($this->inlineImageExists()) {
2346
            $type[] = 'inline';
2347
        }
2348
        if ($this->attachmentExists()) {
2349
            $type[] = 'attach';
2350
        }
2351
        $this->message_type = implode('_', $type);
2352
        if ($this->message_type == '') {
2353
            $this->message_type = 'plain';
2354
        }
2355
    }
2356
2357
    /**
2358
     * Format a header line.
2359
     * @access public
2360
     * @param string $name
2361
     * @param string $value
2362
     * @return string
2363
     */
2364
    public function headerLine($name, $value)
2365
    {
2366
        return $name . ': ' . $value . $this->LE;
2367
    }
2368
2369
    /**
2370
     * Return a formatted mail line.
2371
     * @access public
2372
     * @param string $value
2373
     * @return string
2374
     */
2375
    public function textLine($value)
2376
    {
2377
        return $value . $this->LE;
2378
    }
2379
2380
    /**
2381
     * Add an attachment from a path on the filesystem.
2382
     * Returns false if the file could not be found or read.
2383
     * @param string $path Path to the attachment.
2384
     * @param string $name Overrides the attachment name.
2385
     * @param string $encoding File encoding (see $Encoding).
2386
     * @param string $type File extension (MIME) type.
2387
     * @param string $disposition Disposition to use
2388
     * @throws phpmailerException
2389
     * @return boolean
2390
     */
2391
    public function addAttachment($path, $name = '', $encoding = 'base64', $type = '', $disposition = 'attachment')
2392
    {
2393
        try {
2394
            if (!@is_file($path)) {
2395
                throw new phpmailerException($this->lang('file_access') . $path, self::STOP_CONTINUE);
2396
            }
2397
2398
            // If a MIME type is not specified, try to work it out from the file name
2399
            if ($type == '') {
2400
                $type = self::filenameToType($path);
2401
            }
2402
2403
            $filename = basename($path);
2404
            if ($name == '') {
2405
                $name = $filename;
2406
            }
2407
2408
            $this->attachment[] = array(
2409
                0 => $path,
2410
                1 => $filename,
2411
                2 => $name,
2412
                3 => $encoding,
2413
                4 => $type,
2414
                5 => false, // isStringAttachment
2415
                6 => $disposition,
2416
                7 => 0
2417
            );
2418
2419
        } catch (phpmailerException $exc) {
2420
            $this->setError($exc->getMessage());
2421
            $this->edebug($exc->getMessage());
2422
            if ($this->exceptions) {
2423
                throw $exc;
2424
            }
2425
            return false;
2426
        }
2427
        return true;
2428
    }
2429
2430
    /**
2431
     * Return the array of attachments.
2432
     * @return array
2433
     */
2434
    public function getAttachments()
2435
    {
2436
        return $this->attachment;
2437
    }
2438
2439
    /**
2440
     * Attach all file, string, and binary attachments to the message.
2441
     * Returns an empty string on failure.
2442
     * @access protected
2443
     * @param string $disposition_type
2444
     * @param string $boundary
2445
     * @return string
2446
     */
2447
    protected function attachAll($disposition_type, $boundary)
2448
    {
2449
        // Return text of body
2450
        $mime = array();
2451
        $cidUniq = array();
2452
        $incl = array();
2453
2454
        // Add all attachments
2455
        foreach ($this->attachment as $attachment) {
2456
            // Check if it is a valid disposition_filter
2457
            if ($attachment[6] == $disposition_type) {
2458
                // Check for string attachment
2459
                $string = '';
2460
                $path = '';
2461
                $bString = $attachment[5];
2462
                if ($bString) {
2463
                    $string = $attachment[0];
2464
                } else {
2465
                    $path = $attachment[0];
2466
                }
2467
2468
                $inclhash = md5(serialize($attachment));
2469
                if (in_array($inclhash, $incl)) {
2470
                    continue;
2471
                }
2472
                $incl[] = $inclhash;
2473
                $name = $attachment[2];
2474
                $encoding = $attachment[3];
2475
                $type = $attachment[4];
2476
                $disposition = $attachment[6];
2477
                $cid = $attachment[7];
2478
                if ($disposition == 'inline' && array_key_exists($cid, $cidUniq)) {
2479
                    continue;
2480
                }
2481
                $cidUniq[$cid] = true;
2482
2483
                $mime[] = sprintf('--%s%s', $boundary, $this->LE);
2484
                //Only include a filename property if we have one
2485
                if (!empty($name)) {
2486
                    $mime[] = sprintf(
2487
                        'Content-Type: %s; name="%s"%s',
2488
                        $type,
2489
                        $this->encodeHeader($this->secureHeader($name)),
2490
                        $this->LE
2491
                    );
2492
                } else {
2493
                    $mime[] = sprintf(
2494
                        'Content-Type: %s%s',
2495
                        $type,
2496
                        $this->LE
2497
                    );
2498
                }
2499
                // RFC1341 part 5 says 7bit is assumed if not specified
2500
                if ($encoding != '7bit') {
2501
                    $mime[] = sprintf('Content-Transfer-Encoding: %s%s', $encoding, $this->LE);
2502
                }
2503
2504
                if ($disposition == 'inline') {
2505
                    $mime[] = sprintf('Content-ID: <%s>%s', $cid, $this->LE);
2506
                }
2507
2508
                // If a filename contains any of these chars, it should be quoted,
2509
                // but not otherwise: RFC2183 & RFC2045 5.1
2510
                // Fixes a warning in IETF's msglint MIME checker
2511
                // Allow for bypassing the Content-Disposition header totally
2512
                if (!(empty($disposition))) {
2513
                    $encoded_name = $this->encodeHeader($this->secureHeader($name));
2514
                    if (preg_match('/[ \(\)<>@,;:\\"\/\[\]\?=]/', $encoded_name)) {
2515
                        $mime[] = sprintf(
2516
                            'Content-Disposition: %s; filename="%s"%s',
2517
                            $disposition,
2518
                            $encoded_name,
2519
                            $this->LE . $this->LE
2520
                        );
2521
                    } else {
2522
                        if (!empty($encoded_name)) {
2523
                            $mime[] = sprintf(
2524
                                'Content-Disposition: %s; filename=%s%s',
2525
                                $disposition,
2526
                                $encoded_name,
2527
                                $this->LE . $this->LE
2528
                            );
2529
                        } else {
2530
                            $mime[] = sprintf(
2531
                                'Content-Disposition: %s%s',
2532
                                $disposition,
2533
                                $this->LE . $this->LE
2534
                            );
2535
                        }
2536
                    }
2537
                } else {
2538
                    $mime[] = $this->LE;
2539
                }
2540
2541
                // Encode as string attachment
2542
                if ($bString) {
2543
                    $mime[] = $this->encodeString($string, $encoding);
2544
                    if ($this->isError()) {
2545
                        return '';
2546
                    }
2547
                    $mime[] = $this->LE . $this->LE;
2548
                } else {
2549
                    $mime[] = $this->encodeFile($path, $encoding);
2550
                    if ($this->isError()) {
2551
                        return '';
2552
                    }
2553
                    $mime[] = $this->LE . $this->LE;
2554
                }
2555
            }
2556
        }
2557
2558
        $mime[] = sprintf('--%s--%s', $boundary, $this->LE);
2559
2560
        return implode('', $mime);
2561
    }
2562
2563
    /**
2564
     * Encode a file attachment in requested format.
2565
     * Returns an empty string on failure.
2566
     * @param string $path The full path to the file
2567
     * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
2568
     * @throws phpmailerException
2569
     * @access protected
2570
     * @return string
2571
     */
2572
    protected function encodeFile($path, $encoding = 'base64')
2573
    {
2574
        try {
2575
            if (!is_readable($path)) {
2576
                throw new phpmailerException($this->lang('file_open') . $path, self::STOP_CONTINUE);
2577
            }
2578
            $magic_quotes = get_magic_quotes_runtime();
2579
            if ($magic_quotes) {
2580
                if (version_compare(PHP_VERSION, '5.3.0', '<')) {
2581
                    set_magic_quotes_runtime(false);
0 ignored issues
show
Deprecated Code introduced by
The function set_magic_quotes_runtime() has been deprecated with message: Deprecated as of PHP 5.3.0. Relying on this feature is highly discouraged.

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
2582
                } else {
2583
                    //Doesn't exist in PHP 5.4, but we don't need to check because
2584
                    //get_magic_quotes_runtime always returns false in 5.4+
2585
                    //so it will never get here
2586
                    ini_set('magic_quotes_runtime', false);
2587
                }
2588
            }
2589
            $file_buffer = file_get_contents($path);
2590
            $file_buffer = $this->encodeString($file_buffer, $encoding);
2591
            if ($magic_quotes) {
2592
                if (version_compare(PHP_VERSION, '5.3.0', '<')) {
2593
                    set_magic_quotes_runtime($magic_quotes);
0 ignored issues
show
Deprecated Code introduced by
The function set_magic_quotes_runtime() has been deprecated with message: Deprecated as of PHP 5.3.0. Relying on this feature is highly discouraged.

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
2594
                } else {
2595
                    ini_set('magic_quotes_runtime', $magic_quotes);
2596
                }
2597
            }
2598
            return $file_buffer;
2599
        } catch (Exception $exc) {
2600
            $this->setError($exc->getMessage());
2601
            return '';
2602
        }
2603
    }
2604
2605
    /**
2606
     * Encode a string in requested format.
2607
     * Returns an empty string on failure.
2608
     * @param string $str The text to encode
2609
     * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
2610
     * @access public
2611
     * @return string
2612
     */
2613
    public function encodeString($str, $encoding = 'base64')
2614
    {
2615
        $encoded = '';
2616
        switch (strtolower($encoding)) {
2617
            case 'base64':
2618
                $encoded = chunk_split(base64_encode($str), 76, $this->LE);
2619
                break;
2620
            case '7bit':
2621
            case '8bit':
2622
                $encoded = $this->fixEOL($str);
2623
                // Make sure it ends with a line break
2624
                if (substr($encoded, -(strlen($this->LE))) != $this->LE) {
2625
                    $encoded .= $this->LE;
2626
                }
2627
                break;
2628
            case 'binary':
2629
                $encoded = $str;
2630
                break;
2631
            case 'quoted-printable':
2632
                $encoded = $this->encodeQP($str);
2633
                break;
2634
            default:
2635
                $this->setError($this->lang('encoding') . $encoding);
2636
                break;
2637
        }
2638
        return $encoded;
2639
    }
2640
2641
    /**
2642
     * Encode a header string optimally.
2643
     * Picks shortest of Q, B, quoted-printable or none.
2644
     * @access public
2645
     * @param string $str
2646
     * @param string $position
2647
     * @return string
2648
     */
2649
    public function encodeHeader($str, $position = 'text')
2650
    {
2651
        $matchcount = 0;
2652
        switch (strtolower($position)) {
2653
            case 'phrase':
2654
                if (!preg_match('/[\200-\377]/', $str)) {
2655
                    // Can't use addslashes as we don't know the value of magic_quotes_sybase
2656
                    $encoded = addcslashes($str, "\0..\37\177\\\"");
2657
                    if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) {
2658
                        return ($encoded);
2659
                    } else {
2660
                        return ("\"$encoded\"");
2661
                    }
2662
                }
2663
                $matchcount = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches);
2664
                break;
2665
            /** @noinspection PhpMissingBreakStatementInspection */
2666
            case 'comment':
2667
                $matchcount = preg_match_all('/[()"]/', $str, $matches);
2668
                // Intentional fall-through
2669
            case 'text':
2670
            default:
2671
                $matchcount += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches);
2672
                break;
2673
        }
2674
2675
        //There are no chars that need encoding
2676
        if ($matchcount == 0) {
2677
            return ($str);
2678
        }
2679
2680
        $maxlen = 75 - 7 - strlen($this->CharSet);
2681
        // Try to select the encoding which should produce the shortest output
2682
        if ($matchcount > strlen($str) / 3) {
2683
            // More than a third of the content will need encoding, so B encoding will be most efficient
2684
            $encoding = 'B';
2685
            if (function_exists('mb_strlen') && $this->hasMultiBytes($str)) {
2686
                // Use a custom function which correctly encodes and wraps long
2687
                // multibyte strings without breaking lines within a character
2688
                $encoded = $this->base64EncodeWrapMB($str, "\n");
2689
            } else {
2690
                $encoded = base64_encode($str);
2691
                $maxlen -= $maxlen % 4;
2692
                $encoded = trim(chunk_split($encoded, $maxlen, "\n"));
2693
            }
2694
        } else {
2695
            $encoding = 'Q';
2696
            $encoded = $this->encodeQ($str, $position);
2697
            $encoded = $this->wrapText($encoded, $maxlen, true);
2698
            $encoded = str_replace('=' . self::CRLF, "\n", trim($encoded));
2699
        }
2700
2701
        $encoded = preg_replace('/^(.*)$/m', ' =?' . $this->CharSet . "?$encoding?\\1?=", $encoded);
2702
        $encoded = trim(str_replace("\n", $this->LE, $encoded));
2703
2704
        return $encoded;
2705
    }
2706
2707
    /**
2708
     * Check if a string contains multi-byte characters.
2709
     * @access public
2710
     * @param string $str multi-byte text to wrap encode
2711
     * @return boolean
2712
     */
2713
    public function hasMultiBytes($str)
2714
    {
2715
        if (function_exists('mb_strlen')) {
2716
            return (strlen($str) > mb_strlen($str, $this->CharSet));
2717
        } else { // Assume no multibytes (we can't handle without mbstring functions anyway)
2718
            return false;
2719
        }
2720
    }
2721
2722
    /**
2723
     * Does a string contain any 8-bit chars (in any charset)?
2724
     * @param string $text
2725
     * @return boolean
2726
     */
2727
    public function has8bitChars($text)
2728
    {
2729
        return (boolean)preg_match('/[\x80-\xFF]/', $text);
2730
    }
2731
2732
    /**
2733
     * Encode and wrap long multibyte strings for mail headers
2734
     * without breaking lines within a character.
2735
     * Adapted from a function by paravoid
2736
     * @link http://www.php.net/manual/en/function.mb-encode-mimeheader.php#60283
2737
     * @access public
2738
     * @param string $str multi-byte text to wrap encode
2739
     * @param string $linebreak string to use as linefeed/end-of-line
2740
     * @return string
2741
     */
2742
    public function base64EncodeWrapMB($str, $linebreak = null)
2743
    {
2744
        $start = '=?' . $this->CharSet . '?B?';
2745
        $end = '?=';
2746
        $encoded = '';
2747
        if ($linebreak === null) {
2748
            $linebreak = $this->LE;
2749
        }
2750
2751
        $mb_length = mb_strlen($str, $this->CharSet);
2752
        // Each line must have length <= 75, including $start and $end
2753
        $length = 75 - strlen($start) - strlen($end);
2754
        // Average multi-byte ratio
2755
        $ratio = $mb_length / strlen($str);
2756
        // Base64 has a 4:3 ratio
2757
        $avgLength = floor($length * $ratio * .75);
2758
2759
        for ($i = 0; $i < $mb_length; $i += $offset) {
2760
            $lookBack = 0;
2761
            do {
2762
                $offset = $avgLength - $lookBack;
2763
                $chunk = mb_substr($str, $i, $offset, $this->CharSet);
2764
                $chunk = base64_encode($chunk);
2765
                $lookBack++;
2766
            } while (strlen($chunk) > $length);
2767
            $encoded .= $chunk . $linebreak;
2768
        }
2769
2770
        // Chomp the last linefeed
2771
        $encoded = substr($encoded, 0, -strlen($linebreak));
2772
        return $encoded;
2773
    }
2774
2775
    /**
2776
     * Encode a string in quoted-printable format.
2777
     * According to RFC2045 section 6.7.
2778
     * @access public
2779
     * @param string $string The text to encode
2780
     * @param integer $line_max Number of chars allowed on a line before wrapping
2781
     * @return string
2782
     * @link http://www.php.net/manual/en/function.quoted-printable-decode.php#89417 Adapted from this comment
2783
     */
2784
    public function encodeQP($string, $line_max = 76)
2785
    {
2786
        // Use native function if it's available (>= PHP5.3)
2787
        if (function_exists('quoted_printable_encode')) {
2788
            return quoted_printable_encode($string);
2789
        }
2790
        // Fall back to a pure PHP implementation
2791
        $string = str_replace(
2792
            array('%20', '%0D%0A.', '%0D%0A', '%'),
2793
            array(' ', "\r\n=2E", "\r\n", '='),
2794
            rawurlencode($string)
2795
        );
2796
        return preg_replace('/[^\r\n]{' . ($line_max - 3) . '}[^=\r\n]{2}/', "$0=\r\n", $string);
2797
    }
2798
2799
    /**
2800
     * Backward compatibility wrapper for an old QP encoding function that was removed.
2801
     * @see PHPMailer::encodeQP()
2802
     * @access public
2803
     * @param string $string
2804
     * @param integer $line_max
2805
     * @param boolean $space_conv
2806
     * @return string
2807
     * @deprecated Use encodeQP instead.
2808
     */
2809
    public function encodeQPphp(
2810
        $string,
2811
        $line_max = 76,
2812
        /** @noinspection PhpUnusedParameterInspection */ $space_conv = false
0 ignored issues
show
Unused Code introduced by
The parameter $space_conv is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
2813
    ) {
2814
        return $this->encodeQP($string, $line_max);
2815
    }
2816
2817
    /**
2818
     * Encode a string using Q encoding.
2819
     * @link http://tools.ietf.org/html/rfc2047
2820
     * @param string $str the text to encode
2821
     * @param string $position Where the text is going to be used, see the RFC for what that means
2822
     * @access public
2823
     * @return string
2824
     */
2825
    public function encodeQ($str, $position = 'text')
2826
    {
2827
        // There should not be any EOL in the string
2828
        $pattern = '';
2829
        $encoded = str_replace(array("\r", "\n"), '', $str);
2830
        switch (strtolower($position)) {
2831
            case 'phrase':
2832
                // RFC 2047 section 5.3
2833
                $pattern = '^A-Za-z0-9!*+\/ -';
2834
                break;
2835
            /** @noinspection PhpMissingBreakStatementInspection */
2836
            case 'comment':
2837
                // RFC 2047 section 5.2
2838
                $pattern = '\(\)"';
2839
                // intentional fall-through
2840
                // for this reason we build the $pattern without including delimiters and []
2841
            case 'text':
2842
            default:
2843
                // RFC 2047 section 5.1
2844
                // Replace every high ascii, control, =, ? and _ characters
2845
                $pattern = '\000-\011\013\014\016-\037\075\077\137\177-\377' . $pattern;
2846
                break;
2847
        }
2848
        $matches = array();
2849
        if (preg_match_all("/[{$pattern}]/", $encoded, $matches)) {
2850
            // If the string contains an '=', make sure it's the first thing we replace
2851
            // so as to avoid double-encoding
2852
            $eqkey = array_search('=', $matches[0]);
2853
            if (false !== $eqkey) {
2854
                unset($matches[0][$eqkey]);
2855
                array_unshift($matches[0], '=');
2856
            }
2857
            foreach (array_unique($matches[0]) as $char) {
2858
                $encoded = str_replace($char, '=' . sprintf('%02X', ord($char)), $encoded);
2859
            }
2860
        }
2861
        // Replace every spaces to _ (more readable than =20)
2862
        return str_replace(' ', '_', $encoded);
2863
    }
2864
2865
    /**
2866
     * Add a string or binary attachment (non-filesystem).
2867
     * This method can be used to attach ascii or binary data,
2868
     * such as a BLOB record from a database.
2869
     * @param string $string String attachment data.
2870
     * @param string $filename Name of the attachment.
2871
     * @param string $encoding File encoding (see $Encoding).
2872
     * @param string $type File extension (MIME) type.
2873
     * @param string $disposition Disposition to use
2874
     * @return void
2875
     */
2876
    public function addStringAttachment(
2877
        $string,
2878
        $filename,
2879
        $encoding = 'base64',
2880
        $type = '',
2881
        $disposition = 'attachment'
2882
    ) {
2883
        // If a MIME type is not specified, try to work it out from the file name
2884
        if ($type == '') {
2885
            $type = self::filenameToType($filename);
2886
        }
2887
        // Append to $attachment array
2888
        $this->attachment[] = array(
2889
            0 => $string,
2890
            1 => $filename,
2891
            2 => basename($filename),
2892
            3 => $encoding,
2893
            4 => $type,
2894
            5 => true, // isStringAttachment
2895
            6 => $disposition,
2896
            7 => 0
2897
        );
2898
    }
2899
2900
    /**
2901
     * Add an embedded (inline) attachment from a file.
2902
     * This can include images, sounds, and just about any other document type.
2903
     * These differ from 'regular' attachments in that they are intended to be
2904
     * displayed inline with the message, not just attached for download.
2905
     * This is used in HTML messages that embed the images
2906
     * the HTML refers to using the $cid value.
2907
     * @param string $path Path to the attachment.
2908
     * @param string $cid Content ID of the attachment; Use this to reference
2909
     *        the content when using an embedded image in HTML.
2910
     * @param string $name Overrides the attachment name.
2911
     * @param string $encoding File encoding (see $Encoding).
2912
     * @param string $type File MIME type.
2913
     * @param string $disposition Disposition to use
2914
     * @return boolean True on successfully adding an attachment
2915
     */
2916
    public function addEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = '', $disposition = 'inline')
2917
    {
2918
        if (!@is_file($path)) {
2919
            $this->setError($this->lang('file_access') . $path);
2920
            return false;
2921
        }
2922
2923
        // If a MIME type is not specified, try to work it out from the file name
2924
        if ($type == '') {
2925
            $type = self::filenameToType($path);
2926
        }
2927
2928
        $filename = basename($path);
2929
        if ($name == '') {
2930
            $name = $filename;
2931
        }
2932
2933
        // Append to $attachment array
2934
        $this->attachment[] = array(
2935
            0 => $path,
2936
            1 => $filename,
2937
            2 => $name,
2938
            3 => $encoding,
2939
            4 => $type,
2940
            5 => false, // isStringAttachment
2941
            6 => $disposition,
2942
            7 => $cid
2943
        );
2944
        return true;
2945
    }
2946
2947
    /**
2948
     * Add an embedded stringified attachment.
2949
     * This can include images, sounds, and just about any other document type.
2950
     * Be sure to set the $type to an image type for images:
2951
     * JPEG images use 'image/jpeg', GIF uses 'image/gif', PNG uses 'image/png'.
2952
     * @param string $string The attachment binary data.
2953
     * @param string $cid Content ID of the attachment; Use this to reference
2954
     *        the content when using an embedded image in HTML.
2955
     * @param string $name
2956
     * @param string $encoding File encoding (see $Encoding).
2957
     * @param string $type MIME type.
2958
     * @param string $disposition Disposition to use
2959
     * @return boolean True on successfully adding an attachment
2960
     */
2961
    public function addStringEmbeddedImage(
2962
        $string,
2963
        $cid,
2964
        $name = '',
2965
        $encoding = 'base64',
2966
        $type = '',
2967
        $disposition = 'inline'
2968
    ) {
2969
        // If a MIME type is not specified, try to work it out from the name
2970
        if ($type == '' and !empty($name)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
2971
            $type = self::filenameToType($name);
2972
        }
2973
2974
        // Append to $attachment array
2975
        $this->attachment[] = array(
2976
            0 => $string,
2977
            1 => $name,
2978
            2 => $name,
2979
            3 => $encoding,
2980
            4 => $type,
2981
            5 => true, // isStringAttachment
2982
            6 => $disposition,
2983
            7 => $cid
2984
        );
2985
        return true;
2986
    }
2987
2988
    /**
2989
     * Check if an inline attachment is present.
2990
     * @access public
2991
     * @return boolean
2992
     */
2993
    public function inlineImageExists()
2994
    {
2995
        foreach ($this->attachment as $attachment) {
2996
            if ($attachment[6] == 'inline') {
2997
                return true;
2998
            }
2999
        }
3000
        return false;
3001
    }
3002
3003
    /**
3004
     * Check if an attachment (non-inline) is present.
3005
     * @return boolean
3006
     */
3007
    public function attachmentExists()
3008
    {
3009
        foreach ($this->attachment as $attachment) {
3010
            if ($attachment[6] == 'attachment') {
3011
                return true;
3012
            }
3013
        }
3014
        return false;
3015
    }
3016
3017
    /**
3018
     * Check if this message has an alternative body set.
3019
     * @return boolean
3020
     */
3021
    public function alternativeExists()
3022
    {
3023
        return !empty($this->AltBody);
3024
    }
3025
3026
    /**
3027
     * Clear queued addresses of given kind.
3028
     * @access protected
3029
     * @param string $kind 'to', 'cc', or 'bcc'
3030
     * @return void
3031
     */
3032
    public function clearQueuedAddresses($kind)
3033
    {
3034
        $RecipientsQueue = $this->RecipientsQueue;
3035
        foreach ($RecipientsQueue as $address => $params) {
3036
            if ($params[0] == $kind) {
3037
                unset($this->RecipientsQueue[$address]);
3038
            }
3039
        }
3040
    }
3041
3042
    /**
3043
     * Clear all To recipients.
3044
     * @return void
3045
     */
3046
    public function clearAddresses()
3047
    {
3048
        foreach ($this->to as $to) {
3049
            unset($this->all_recipients[strtolower($to[0])]);
3050
        }
3051
        $this->to = array();
3052
        $this->clearQueuedAddresses('to');
3053
    }
3054
3055
    /**
3056
     * Clear all CC recipients.
3057
     * @return void
3058
     */
3059 View Code Duplication
    public function clearCCs()
3060
    {
3061
        foreach ($this->cc as $cc) {
3062
            unset($this->all_recipients[strtolower($cc[0])]);
3063
        }
3064
        $this->cc = array();
3065
        $this->clearQueuedAddresses('cc');
3066
    }
3067
3068
    /**
3069
     * Clear all BCC recipients.
3070
     * @return void
3071
     */
3072 View Code Duplication
    public function clearBCCs()
3073
    {
3074
        foreach ($this->bcc as $bcc) {
3075
            unset($this->all_recipients[strtolower($bcc[0])]);
3076
        }
3077
        $this->bcc = array();
3078
        $this->clearQueuedAddresses('bcc');
3079
    }
3080
3081
    /**
3082
     * Clear all ReplyTo recipients.
3083
     * @return void
3084
     */
3085
    public function clearReplyTos()
3086
    {
3087
        $this->ReplyTo = array();
3088
        $this->ReplyToQueue = array();
3089
    }
3090
3091
    /**
3092
     * Clear all recipient types.
3093
     * @return void
3094
     */
3095
    public function clearAllRecipients()
3096
    {
3097
        $this->to = array();
3098
        $this->cc = array();
3099
        $this->bcc = array();
3100
        $this->all_recipients = array();
3101
        $this->RecipientsQueue = array();
3102
    }
3103
3104
    /**
3105
     * Clear all filesystem, string, and binary attachments.
3106
     * @return void
3107
     */
3108
    public function clearAttachments()
3109
    {
3110
        $this->attachment = array();
3111
    }
3112
3113
    /**
3114
     * Clear all custom headers.
3115
     * @return void
3116
     */
3117
    public function clearCustomHeaders()
3118
    {
3119
        $this->CustomHeader = array();
3120
    }
3121
3122
    /**
3123
     * Add an error message to the error container.
3124
     * @access protected
3125
     * @param string $msg
3126
     * @return void
3127
     */
3128
    protected function setError($msg)
3129
    {
3130
        $this->error_count++;
3131
        if ($this->Mailer == 'smtp' and !is_null($this->smtp)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
3132
            $lasterror = $this->smtp->getError();
3133
            if (!empty($lasterror['error'])) {
3134
                $msg .= $this->lang('smtp_error') . $lasterror['error'];
3135
                if (!empty($lasterror['detail'])) {
3136
                    $msg .= ' Detail: '. $lasterror['detail'];
3137
                }
3138
                if (!empty($lasterror['smtp_code'])) {
3139
                    $msg .= ' SMTP code: ' . $lasterror['smtp_code'];
3140
                }
3141
                if (!empty($lasterror['smtp_code_ex'])) {
3142
                    $msg .= ' Additional SMTP info: ' . $lasterror['smtp_code_ex'];
3143
                }
3144
            }
3145
        }
3146
        $this->ErrorInfo = $msg;
3147
    }
3148
3149
    /**
3150
     * Return an RFC 822 formatted date.
3151
     * @access public
3152
     * @return string
3153
     * @static
3154
     */
3155
    public static function rfcDate()
3156
    {
3157
        // Set the time zone to whatever the default is to avoid 500 errors
3158
        // Will default to UTC if it's not set properly in php.ini
3159
        date_default_timezone_set(@date_default_timezone_get());
3160
        return date('D, j M Y H:i:s O');
3161
    }
3162
3163
    /**
3164
     * Get the server hostname.
3165
     * Returns 'localhost.localdomain' if unknown.
3166
     * @access protected
3167
     * @return string
3168
     */
3169
    protected function serverHostname()
3170
    {
3171
        $result = 'localhost.localdomain';
3172
        if (!empty($this->Hostname)) {
3173
            $result = $this->Hostname;
3174
        } elseif (isset($_SERVER) and array_key_exists('SERVER_NAME', $_SERVER) and !empty($_SERVER['SERVER_NAME'])) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
3175
            $result = $_SERVER['SERVER_NAME'];
3176
        } elseif (function_exists('gethostname') && gethostname() !== false) {
3177
            $result = gethostname();
3178
        } elseif (php_uname('n') !== false) {
3179
            $result = php_uname('n');
3180
        }
3181
        return $result;
3182
    }
3183
3184
    /**
3185
     * Get an error message in the current language.
3186
     * @access protected
3187
     * @param string $key
3188
     * @return string
3189
     */
3190
    protected function lang($key)
3191
    {
3192
        if (count($this->language) < 1) {
3193
            $this->setLanguage('en'); // set the default language
3194
        }
3195
3196
        if (array_key_exists($key, $this->language)) {
3197
            if ($key == 'smtp_connect_failed') {
3198
                //Include a link to troubleshooting docs on SMTP connection failure
3199
                //this is by far the biggest cause of support questions
3200
                //but it's usually not PHPMailer's fault.
3201
                return $this->language[$key] . ' https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting';
3202
            }
3203
            return $this->language[$key];
3204
        } else {
3205
            //Return the key as a fallback
3206
            return $key;
3207
        }
3208
    }
3209
3210
    /**
3211
     * Check if an error occurred.
3212
     * @access public
3213
     * @return boolean True if an error did occur.
3214
     */
3215
    public function isError()
3216
    {
3217
        return ($this->error_count > 0);
3218
    }
3219
3220
    /**
3221
     * Ensure consistent line endings in a string.
3222
     * Changes every end of line from CRLF, CR or LF to $this->LE.
3223
     * @access public
3224
     * @param string $str String to fixEOL
3225
     * @return string
3226
     */
3227
    public function fixEOL($str)
3228
    {
3229
        // Normalise to \n
3230
        $nstr = str_replace(array("\r\n", "\r"), "\n", $str);
3231
        // Now convert LE as needed
3232
        if ($this->LE !== "\n") {
3233
            $nstr = str_replace("\n", $this->LE, $nstr);
3234
        }
3235
        return $nstr;
3236
    }
3237
3238
    /**
3239
     * Add a custom header.
3240
     * $name value can be overloaded to contain
3241
     * both header name and value (name:value)
3242
     * @access public
3243
     * @param string $name Custom header name
3244
     * @param string $value Header value
3245
     * @return void
3246
     */
3247
    public function addCustomHeader($name, $value = null)
3248
    {
3249
        if ($value === null) {
3250
            // Value passed in as name:value
3251
            $this->CustomHeader[] = explode(':', $name, 2);
3252
        } else {
3253
            $this->CustomHeader[] = array($name, $value);
3254
        }
3255
    }
3256
3257
    /**
3258
     * Returns all custom headers.
3259
     * @return array
3260
     */
3261
    public function getCustomHeaders()
3262
    {
3263
        return $this->CustomHeader;
3264
    }
3265
3266
    /**
3267
     * Create a message from an HTML string.
3268
     * Automatically makes modifications for inline images and backgrounds
3269
     * and creates a plain-text version by converting the HTML.
3270
     * Overwrites any existing values in $this->Body and $this->AltBody
3271
     * @access public
3272
     * @param string $message HTML message string
3273
     * @param string $basedir baseline directory for path
3274
     * @param boolean|callable $advanced Whether to use the internal HTML to text converter
3275
     *    or your own custom converter @see PHPMailer::html2text()
3276
     * @return string $message
3277
     */
3278
    public function msgHTML($message, $basedir = '', $advanced = false)
3279
    {
3280
        preg_match_all('/(src|background)=["\'](.*)["\']/Ui', $message, $images);
3281
        if (array_key_exists(2, $images)) {
3282
            foreach ($images[2] as $imgindex => $url) {
3283
                // Convert data URIs into embedded images
3284
                if (preg_match('#^data:(image[^;,]*)(;base64)?,#', $url, $match)) {
3285
                    $data = substr($url, strpos($url, ','));
3286
                    if ($match[2]) {
3287
                        $data = base64_decode($data);
3288
                    } else {
3289
                        $data = rawurldecode($data);
3290
                    }
3291
                    $cid = md5($url) . '@phpmailer.0'; // RFC2392 S 2
3292
                    if ($this->addStringEmbeddedImage($data, $cid, 'embed' . $imgindex, 'base64', $match[1])) {
3293
                        $message = str_replace(
3294
                            $images[0][$imgindex],
3295
                            $images[1][$imgindex] . '="cid:' . $cid . '"',
3296
                            $message
3297
                        );
3298
                    }
3299
                } elseif (substr($url, 0, 4) !== 'cid:' && !preg_match('#^[A-z]+://#', $url)) {
3300
                    // Do not change urls for absolute images (thanks to corvuscorax)
3301
                    // Do not change urls that are already inline images
3302
                    $filename = basename($url);
3303
                    $directory = dirname($url);
3304
                    if ($directory == '.') {
3305
                        $directory = '';
3306
                    }
3307
                    $cid = md5($url) . '@phpmailer.0'; // RFC2392 S 2
3308
                    if (strlen($basedir) > 1 && substr($basedir, -1) != '/') {
3309
                        $basedir .= '/';
3310
                    }
3311
                    if (strlen($directory) > 1 && substr($directory, -1) != '/') {
3312
                        $directory .= '/';
3313
                    }
3314
                    if ($this->addEmbeddedImage(
3315
                        $basedir . $directory . $filename,
3316
                        $cid,
3317
                        $filename,
3318
                        'base64',
3319
                        self::_mime_types((string)self::mb_pathinfo($filename, PATHINFO_EXTENSION))
3320
                    )
3321
                    ) {
3322
                        $message = preg_replace(
3323
                            '/' . $images[1][$imgindex] . '=["\']' . preg_quote($url, '/') . '["\']/Ui',
3324
                            $images[1][$imgindex] . '="cid:' . $cid . '"',
3325
                            $message
3326
                        );
3327
                    }
3328
                }
3329
            }
3330
        }
3331
        $this->isHTML(true);
3332
        // Convert all message body line breaks to CRLF, makes quoted-printable encoding work much better
3333
        $this->Body = $this->normalizeBreaks($message);
3334
        $this->AltBody = $this->normalizeBreaks($this->html2text($message, $advanced));
3335
        if (empty($this->AltBody)) {
3336
            $this->AltBody = 'To view this email message, open it in a program that understands HTML!' .
3337
                self::CRLF . self::CRLF;
3338
        }
3339
        return $this->Body;
3340
    }
3341
3342
    /**
3343
     * Convert an HTML string into plain text.
3344
     * This is used by msgHTML().
3345
     * Note - older versions of this function used a bundled advanced converter
3346
     * which was been removed for license reasons in #232
3347
     * Example usage:
3348
     * <code>
3349
     * // Use default conversion
3350
     * $plain = $mail->html2text($html);
3351
     * // Use your own custom converter
3352
     * $plain = $mail->html2text($html, function($html) {
3353
     *     $converter = new MyHtml2text($html);
3354
     *     return $converter->get_text();
3355
     * });
3356
     * </code>
3357
     * @param string $html The HTML text to convert
3358
     * @param boolean|callable $advanced Any boolean value to use the internal converter,
3359
     *   or provide your own callable for custom conversion.
3360
     * @return string
3361
     */
3362
    public function html2text($html, $advanced = false)
3363
    {
3364
        if (is_callable($advanced)) {
3365
            return call_user_func($advanced, $html);
3366
        }
3367
        return html_entity_decode(
3368
            trim(strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/\\1>/si', '', $html))),
3369
            ENT_QUOTES,
3370
            $this->CharSet
3371
        );
3372
    }
3373
3374
    /**
3375
     * Get the MIME type for a file extension.
3376
     * @param string $ext File extension
3377
     * @access public
3378
     * @return string MIME type of file.
3379
     * @static
3380
     */
3381
    public static function _mime_types($ext = '')
3382
    {
3383
        $mimes = array(
3384
            'xl'    => 'application/excel',
3385
            'js'    => 'application/javascript',
3386
            'hqx'   => 'application/mac-binhex40',
3387
            'cpt'   => 'application/mac-compactpro',
3388
            'bin'   => 'application/macbinary',
3389
            'doc'   => 'application/msword',
3390
            'word'  => 'application/msword',
3391
            'xlsx'  => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
3392
            'xltx'  => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
3393
            'potx'  => 'application/vnd.openxmlformats-officedocument.presentationml.template',
3394
            'ppsx'  => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
3395
            'pptx'  => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
3396
            'sldx'  => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
3397
            'docx'  => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
3398
            'dotx'  => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
3399
            'xlam'  => 'application/vnd.ms-excel.addin.macroEnabled.12',
3400
            'xlsb'  => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
3401
            'class' => 'application/octet-stream',
3402
            'dll'   => 'application/octet-stream',
3403
            'dms'   => 'application/octet-stream',
3404
            'exe'   => 'application/octet-stream',
3405
            'lha'   => 'application/octet-stream',
3406
            'lzh'   => 'application/octet-stream',
3407
            'psd'   => 'application/octet-stream',
3408
            'sea'   => 'application/octet-stream',
3409
            'so'    => 'application/octet-stream',
3410
            'oda'   => 'application/oda',
3411
            'pdf'   => 'application/pdf',
3412
            'ai'    => 'application/postscript',
3413
            'eps'   => 'application/postscript',
3414
            'ps'    => 'application/postscript',
3415
            'smi'   => 'application/smil',
3416
            'smil'  => 'application/smil',
3417
            'mif'   => 'application/vnd.mif',
3418
            'xls'   => 'application/vnd.ms-excel',
3419
            'ppt'   => 'application/vnd.ms-powerpoint',
3420
            'wbxml' => 'application/vnd.wap.wbxml',
3421
            'wmlc'  => 'application/vnd.wap.wmlc',
3422
            'dcr'   => 'application/x-director',
3423
            'dir'   => 'application/x-director',
3424
            'dxr'   => 'application/x-director',
3425
            'dvi'   => 'application/x-dvi',
3426
            'gtar'  => 'application/x-gtar',
3427
            'php3'  => 'application/x-httpd-php',
3428
            'php4'  => 'application/x-httpd-php',
3429
            'php'   => 'application/x-httpd-php',
3430
            'phtml' => 'application/x-httpd-php',
3431
            'phps'  => 'application/x-httpd-php-source',
3432
            'swf'   => 'application/x-shockwave-flash',
3433
            'sit'   => 'application/x-stuffit',
3434
            'tar'   => 'application/x-tar',
3435
            'tgz'   => 'application/x-tar',
3436
            'xht'   => 'application/xhtml+xml',
3437
            'xhtml' => 'application/xhtml+xml',
3438
            'zip'   => 'application/zip',
3439
            'mid'   => 'audio/midi',
3440
            'midi'  => 'audio/midi',
3441
            'mp2'   => 'audio/mpeg',
3442
            'mp3'   => 'audio/mpeg',
3443
            'mpga'  => 'audio/mpeg',
3444
            'aif'   => 'audio/x-aiff',
3445
            'aifc'  => 'audio/x-aiff',
3446
            'aiff'  => 'audio/x-aiff',
3447
            'ram'   => 'audio/x-pn-realaudio',
3448
            'rm'    => 'audio/x-pn-realaudio',
3449
            'rpm'   => 'audio/x-pn-realaudio-plugin',
3450
            'ra'    => 'audio/x-realaudio',
3451
            'wav'   => 'audio/x-wav',
3452
            'bmp'   => 'image/bmp',
3453
            'gif'   => 'image/gif',
3454
            'jpeg'  => 'image/jpeg',
3455
            'jpe'   => 'image/jpeg',
3456
            'jpg'   => 'image/jpeg',
3457
            'png'   => 'image/png',
3458
            'tiff'  => 'image/tiff',
3459
            'tif'   => 'image/tiff',
3460
            'eml'   => 'message/rfc822',
3461
            'css'   => 'text/css',
3462
            'html'  => 'text/html',
3463
            'htm'   => 'text/html',
3464
            'shtml' => 'text/html',
3465
            'log'   => 'text/plain',
3466
            'text'  => 'text/plain',
3467
            'txt'   => 'text/plain',
3468
            'rtx'   => 'text/richtext',
3469
            'rtf'   => 'text/rtf',
3470
            'vcf'   => 'text/vcard',
3471
            'vcard' => 'text/vcard',
3472
            'xml'   => 'text/xml',
3473
            'xsl'   => 'text/xml',
3474
            'mpeg'  => 'video/mpeg',
3475
            'mpe'   => 'video/mpeg',
3476
            'mpg'   => 'video/mpeg',
3477
            'mov'   => 'video/quicktime',
3478
            'qt'    => 'video/quicktime',
3479
            'rv'    => 'video/vnd.rn-realvideo',
3480
            'avi'   => 'video/x-msvideo',
3481
            'movie' => 'video/x-sgi-movie'
3482
        );
3483
        if (array_key_exists(strtolower($ext), $mimes)) {
3484
            return $mimes[strtolower($ext)];
3485
        }
3486
        return 'application/octet-stream';
3487
    }
3488
3489
    /**
3490
     * Map a file name to a MIME type.
3491
     * Defaults to 'application/octet-stream', i.e.. arbitrary binary data.
3492
     * @param string $filename A file name or full path, does not need to exist as a file
3493
     * @return string
3494
     * @static
3495
     */
3496
    public static function filenameToType($filename)
3497
    {
3498
        // In case the path is a URL, strip any query string before getting extension
3499
        $qpos = strpos($filename, '?');
3500
        if (false !== $qpos) {
3501
            $filename = substr($filename, 0, $qpos);
3502
        }
3503
        $pathinfo = self::mb_pathinfo($filename);
3504
        return self::_mime_types($pathinfo['extension']);
3505
    }
3506
3507
    /**
3508
     * Multi-byte-safe pathinfo replacement.
3509
     * Drop-in replacement for pathinfo(), but multibyte-safe, cross-platform-safe, old-version-safe.
3510
     * Works similarly to the one in PHP >= 5.2.0
3511
     * @link http://www.php.net/manual/en/function.pathinfo.php#107461
3512
     * @param string $path A filename or path, does not need to exist as a file
3513
     * @param integer|string $options Either a PATHINFO_* constant,
3514
     *      or a string name to return only the specified piece, allows 'filename' to work on PHP < 5.2
3515
     * @return string|array
3516
     * @static
3517
     */
3518
    public static function mb_pathinfo($path, $options = null)
3519
    {
3520
        $ret = array('dirname' => '', 'basename' => '', 'extension' => '', 'filename' => '');
3521
        $pathinfo = array();
3522
        if (preg_match('%^(.*?)[\\\\/]*(([^/\\\\]*?)(\.([^\.\\\\/]+?)|))[\\\\/\.]*$%im', $path, $pathinfo)) {
3523
            if (array_key_exists(1, $pathinfo)) {
3524
                $ret['dirname'] = $pathinfo[1];
3525
            }
3526
            if (array_key_exists(2, $pathinfo)) {
3527
                $ret['basename'] = $pathinfo[2];
3528
            }
3529
            if (array_key_exists(5, $pathinfo)) {
3530
                $ret['extension'] = $pathinfo[5];
3531
            }
3532
            if (array_key_exists(3, $pathinfo)) {
3533
                $ret['filename'] = $pathinfo[3];
3534
            }
3535
        }
3536
        switch ($options) {
3537
            case PATHINFO_DIRNAME:
3538
            case 'dirname':
3539
                return $ret['dirname'];
3540
            case PATHINFO_BASENAME:
3541
            case 'basename':
3542
                return $ret['basename'];
3543
            case PATHINFO_EXTENSION:
3544
            case 'extension':
3545
                return $ret['extension'];
3546
            case PATHINFO_FILENAME:
3547
            case 'filename':
3548
                return $ret['filename'];
3549
            default:
3550
                return $ret;
3551
        }
3552
    }
3553
3554
    /**
3555
     * Set or reset instance properties.
3556
     * You should avoid this function - it's more verbose, less efficient, more error-prone and
3557
     * harder to debug than setting properties directly.
3558
     * Usage Example:
3559
     * `$mail->set('SMTPSecure', 'tls');`
3560
     *   is the same as:
3561
     * `$mail->SMTPSecure = 'tls';`
3562
     * @access public
3563
     * @param string $name The property name to set
3564
     * @param mixed $value The value to set the property to
3565
     * @return boolean
3566
     * @TODO Should this not be using the __set() magic function?
3567
     */
3568
    public function set($name, $value = '')
3569
    {
3570
        if (property_exists($this, $name)) {
3571
            $this->$name = $value;
3572
            return true;
3573
        } else {
3574
            $this->setError($this->lang('variable_set') . $name);
3575
            return false;
3576
        }
3577
    }
3578
3579
    /**
3580
     * Strip newlines to prevent header injection.
3581
     * @access public
3582
     * @param string $str
3583
     * @return string
3584
     */
3585
    public function secureHeader($str)
3586
    {
3587
        return trim(str_replace(array("\r", "\n"), '', $str));
3588
    }
3589
3590
    /**
3591
     * Normalize line breaks in a string.
3592
     * Converts UNIX LF, Mac CR and Windows CRLF line breaks into a single line break format.
3593
     * Defaults to CRLF (for message bodies) and preserves consecutive breaks.
3594
     * @param string $text
3595
     * @param string $breaktype What kind of line break to use, defaults to CRLF
3596
     * @return string
3597
     * @access public
3598
     * @static
3599
     */
3600
    public static function normalizeBreaks($text, $breaktype = "\r\n")
3601
    {
3602
        return preg_replace('/(\r\n|\r|\n)/ms', $breaktype, $text);
3603
    }
3604
3605
    /**
3606
     * Set the public and private key files and password for S/MIME signing.
3607
     * @access public
3608
     * @param string $cert_filename
3609
     * @param string $key_filename
3610
     * @param string $key_pass Password for private key
3611
     * @param string $extracerts_filename Optional path to chain certificate
3612
     */
3613
    public function sign($cert_filename, $key_filename, $key_pass, $extracerts_filename = '')
3614
    {
3615
        $this->sign_cert_file = $cert_filename;
3616
        $this->sign_key_file = $key_filename;
3617
        $this->sign_key_pass = $key_pass;
3618
        $this->sign_extracerts_file = $extracerts_filename;
3619
    }
3620
3621
    /**
3622
     * Quoted-Printable-encode a DKIM header.
3623
     * @access public
3624
     * @param string $txt
3625
     * @return string
3626
     */
3627
    public function DKIM_QP($txt)
3628
    {
3629
        $line = '';
3630
        for ($i = 0; $i < strlen($txt); $i++) {
3631
            $ord = ord($txt[$i]);
3632
            if (((0x21 <= $ord) && ($ord <= 0x3A)) || $ord == 0x3C || ((0x3E <= $ord) && ($ord <= 0x7E))) {
3633
                $line .= $txt[$i];
3634
            } else {
3635
                $line .= '=' . sprintf('%02X', $ord);
3636
            }
3637
        }
3638
        return $line;
3639
    }
3640
3641
    /**
3642
     * Generate a DKIM signature.
3643
     * @access public
3644
     * @param string $signHeader
3645
     * @throws phpmailerException
3646
     * @return string
3647
     */
3648
    public function DKIM_Sign($signHeader)
3649
    {
3650
        if (!defined('PKCS7_TEXT')) {
3651
            if ($this->exceptions) {
3652
                throw new phpmailerException($this->lang('extension_missing') . 'openssl');
3653
            }
3654
            return '';
3655
        }
3656
        $privKeyStr = file_get_contents($this->DKIM_private);
3657
        if ($this->DKIM_passphrase != '') {
3658
            $privKey = openssl_pkey_get_private($privKeyStr, $this->DKIM_passphrase);
3659
        } else {
3660
            $privKey = $privKeyStr;
3661
        }
3662
        if (openssl_sign($signHeader, $signature, $privKey)) {
3663
            return base64_encode($signature);
3664
        }
3665
        return '';
3666
    }
3667
3668
    /**
3669
     * Generate a DKIM canonicalization header.
3670
     * @access public
3671
     * @param string $signHeader Header
3672
     * @return string
3673
     */
3674
    public function DKIM_HeaderC($signHeader)
3675
    {
3676
        $signHeader = preg_replace('/\r\n\s+/', ' ', $signHeader);
3677
        $lines = explode("\r\n", $signHeader);
3678
        foreach ($lines as $key => $line) {
3679
            list($heading, $value) = explode(':', $line, 2);
3680
            $heading = strtolower($heading);
3681
            $value = preg_replace('/\s+/', ' ', $value); // Compress useless spaces
3682
            $lines[$key] = $heading . ':' . trim($value); // Don't forget to remove WSP around the value
3683
        }
3684
        $signHeader = implode("\r\n", $lines);
3685
        return $signHeader;
3686
    }
3687
3688
    /**
3689
     * Generate a DKIM canonicalization body.
3690
     * @access public
3691
     * @param string $body Message Body
3692
     * @return string
3693
     */
3694
    public function DKIM_BodyC($body)
3695
    {
3696
        if ($body == '') {
3697
            return "\r\n";
3698
        }
3699
        // stabilize line endings
3700
        $body = str_replace("\r\n", "\n", $body);
3701
        $body = str_replace("\n", "\r\n", $body);
3702
        // END stabilize line endings
3703
        while (substr($body, strlen($body) - 4, 4) == "\r\n\r\n") {
3704
            $body = substr($body, 0, strlen($body) - 2);
3705
        }
3706
        return $body;
3707
    }
3708
3709
    /**
3710
     * Create the DKIM header and body in a new message header.
3711
     * @access public
3712
     * @param string $headers_line Header lines
3713
     * @param string $subject Subject
3714
     * @param string $body Body
3715
     * @return string
3716
     */
3717
    public function DKIM_Add($headers_line, $subject, $body)
3718
    {
3719
        $DKIMsignatureType = 'rsa-sha1'; // Signature & hash algorithms
3720
        $DKIMcanonicalization = 'relaxed/simple'; // Canonicalization of header/body
3721
        $DKIMquery = 'dns/txt'; // Query method
3722
        $DKIMtime = time(); // Signature Timestamp = seconds since 00:00:00 - Jan 1, 1970 (UTC time zone)
3723
        $subject_header = "Subject: $subject";
3724
        $headers = explode($this->LE, $headers_line);
3725
        $from_header = '';
3726
        $to_header = '';
3727
        $current = '';
3728
        foreach ($headers as $header) {
3729
            if (strpos($header, 'From:') === 0) {
3730
                $from_header = $header;
3731
                $current = 'from_header';
3732
            } elseif (strpos($header, 'To:') === 0) {
3733
                $to_header = $header;
3734
                $current = 'to_header';
3735
            } else {
3736
                if (!empty($$current) && strpos($header, ' =?') === 0) {
3737
                    $$current .= $header;
3738
                } else {
3739
                    $current = '';
3740
                }
3741
            }
3742
        }
3743
        $from = str_replace('|', '=7C', $this->DKIM_QP($from_header));
3744
        $to = str_replace('|', '=7C', $this->DKIM_QP($to_header));
3745
        $subject = str_replace(
3746
            '|',
3747
            '=7C',
3748
            $this->DKIM_QP($subject_header)
3749
        ); // Copied header fields (dkim-quoted-printable)
3750
        $body = $this->DKIM_BodyC($body);
3751
        $DKIMlen = strlen($body); // Length of body
3752
        $DKIMb64 = base64_encode(pack('H*', sha1($body))); // Base64 of packed binary SHA-1 hash of body
3753
        if ('' == $this->DKIM_identity) {
3754
            $ident = '';
3755
        } else {
3756
            $ident = ' i=' . $this->DKIM_identity . ';';
3757
        }
3758
        $dkimhdrs = 'DKIM-Signature: v=1; a=' .
3759
            $DKIMsignatureType . '; q=' .
3760
            $DKIMquery . '; l=' .
3761
            $DKIMlen . '; s=' .
3762
            $this->DKIM_selector .
3763
            ";\r\n" .
3764
            "\tt=" . $DKIMtime . '; c=' . $DKIMcanonicalization . ";\r\n" .
3765
            "\th=From:To:Subject;\r\n" .
3766
            "\td=" . $this->DKIM_domain . ';' . $ident . "\r\n" .
3767
            "\tz=$from\r\n" .
3768
            "\t|$to\r\n" .
3769
            "\t|$subject;\r\n" .
3770
            "\tbh=" . $DKIMb64 . ";\r\n" .
3771
            "\tb=";
3772
        $toSign = $this->DKIM_HeaderC(
3773
            $from_header . "\r\n" .
3774
            $to_header . "\r\n" .
3775
            $subject_header . "\r\n" .
3776
            $dkimhdrs
3777
        );
3778
        $signed = $this->DKIM_Sign($toSign);
3779
        return $dkimhdrs . $signed . "\r\n";
3780
    }
3781
3782
    /**
3783
     * Detect if a string contains a line longer than the maximum line length allowed.
3784
     * @param string $str
3785
     * @return boolean
3786
     * @static
3787
     */
3788
    public static function hasLineLongerThanMax($str)
3789
    {
3790
        //+2 to include CRLF line break for a 1000 total
3791
        return (boolean)preg_match('/^(.{'.(self::MAX_LINE_LENGTH + 2).',})/m', $str);
3792
    }
3793
3794
    /**
3795
     * Allows for public read access to 'to' property.
3796
     * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included.
3797
     * @access public
3798
     * @return array
3799
     */
3800
    public function getToAddresses()
3801
    {
3802
        return $this->to;
3803
    }
3804
3805
    /**
3806
     * Allows for public read access to 'cc' property.
3807
     * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included.
3808
     * @access public
3809
     * @return array
3810
     */
3811
    public function getCcAddresses()
3812
    {
3813
        return $this->cc;
3814
    }
3815
3816
    /**
3817
     * Allows for public read access to 'bcc' property.
3818
     * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included.
3819
     * @access public
3820
     * @return array
3821
     */
3822
    public function getBccAddresses()
3823
    {
3824
        return $this->bcc;
3825
    }
3826
3827
    /**
3828
     * Allows for public read access to 'ReplyTo' property.
3829
     * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included.
3830
     * @access public
3831
     * @return array
3832
     */
3833
    public function getReplyToAddresses()
3834
    {
3835
        return $this->ReplyTo;
3836
    }
3837
3838
    /**
3839
     * Allows for public read access to 'all_recipients' property.
3840
     * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included.
3841
     * @access public
3842
     * @return array
3843
     */
3844
    public function getAllRecipientAddresses()
3845
    {
3846
        return $this->all_recipients;
3847
    }
3848
3849
    /**
3850
     * Perform a callback.
3851
     * @param boolean $isSent
3852
     * @param array $to
3853
     * @param array $cc
3854
     * @param array $bcc
3855
     * @param string $subject
3856
     * @param string $body
3857
     * @param string $from
3858
     */
3859
    protected function doCallback($isSent, $to, $cc, $bcc, $subject, $body, $from)
3860
    {
3861
        if (!empty($this->action_function) && is_callable($this->action_function)) {
3862
            $params = array($isSent, $to, $cc, $bcc, $subject, $body, $from);
3863
            call_user_func_array($this->action_function, $params);
3864
        }
3865
    }
3866
}
3867
3868
/**
3869
 * PHPMailer exception handler
3870
 * @package PHPMailer
3871
 */
3872
class phpmailerException extends Exception
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
3873
{
3874
    /**
3875
     * Prettify error message output
3876
     * @return string
3877
     */
3878
    public function errorMessage()
3879
    {
3880
        $errorMsg = '<strong>' . $this->getMessage() . "</strong><br />\n";
3881
        return $errorMsg;
3882
    }
3883
}
3884