]> scripts.mit.edu Git - autoinstalls/wordpress.git/blob - wp-includes/class-phpmailer.php
WordPress 4.3.1
[autoinstalls/wordpress.git] / wp-includes / class-phpmailer.php
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) <phpmailer@synchromedia.co.uk>
8  * @author Jim Jagielski (jimjag) <jimjag@gmail.com>
9  * @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
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) <phpmailer@synchromedia.co.uk>
24  * @author Jim Jagielski (jimjag) <jimjag@gmail.com>
25  * @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
26  * @author Brent R. Matzelle (original founder)
27  */
28 class PHPMailer
29 {
30     /**
31      * The PHPMailer Version number.
32      * @type string
33      */
34     public $Version = '5.2.10';
35
36     /**
37      * Email priority.
38      * Options: 1 = High, 3 = Normal, 5 = low.
39      * @type integer
40      */
41     public $Priority = 3;
42
43     /**
44      * The character set of the message.
45      * @type string
46      */
47     public $CharSet = 'iso-8859-1';
48
49     /**
50      * The MIME Content-type of the message.
51      * @type string
52      */
53     public $ContentType = 'text/plain';
54
55     /**
56      * The message encoding.
57      * Options: "8bit", "7bit", "binary", "base64", and "quoted-printable".
58      * @type string
59      */
60     public $Encoding = '8bit';
61
62     /**
63      * Holds the most recent mailer error message.
64      * @type string
65      */
66     public $ErrorInfo = '';
67
68     /**
69      * The From email address for the message.
70      * @type string
71      */
72     public $From = 'root@localhost';
73
74     /**
75      * The From name of the message.
76      * @type string
77      */
78     public $FromName = 'Root User';
79
80     /**
81      * The Sender email (Return-Path) of the message.
82      * If not empty, will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode.
83      * @type string
84      */
85     public $Sender = '';
86
87     /**
88      * The Return-Path of the message.
89      * If empty, it will be set to either From or Sender.
90      * @type string
91      * @deprecated Email senders should never set a return-path header;
92      * it's the receiver's job (RFC5321 section 4.4), so this no longer does anything.
93      * @link https://tools.ietf.org/html/rfc5321#section-4.4 RFC5321 reference
94      */
95     public $ReturnPath = '';
96
97     /**
98      * The Subject of the message.
99      * @type string
100      */
101     public $Subject = '';
102
103     /**
104      * An HTML or plain text message body.
105      * If HTML then call isHTML(true).
106      * @type string
107      */
108     public $Body = '';
109
110     /**
111      * The plain-text message body.
112      * This body can be read by mail clients that do not have HTML email
113      * capability such as mutt & Eudora.
114      * Clients that can read HTML will view the normal Body.
115      * @type string
116      */
117     public $AltBody = '';
118
119     /**
120      * An iCal message part body.
121      * Only supported in simple alt or alt_inline message types
122      * To generate iCal events, use the bundled extras/EasyPeasyICS.php class or iCalcreator
123      * @link http://sprain.ch/blog/downloads/php-class-easypeasyics-create-ical-files-with-php/
124      * @link http://kigkonsult.se/iCalcreator/
125      * @type string
126      */
127     public $Ical = '';
128
129     /**
130      * The complete compiled MIME message body.
131      * @access protected
132      * @type string
133      */
134     protected $MIMEBody = '';
135
136     /**
137      * The complete compiled MIME message headers.
138      * @type string
139      * @access protected
140      */
141     protected $MIMEHeader = '';
142
143     /**
144      * Extra headers that createHeader() doesn't fold in.
145      * @type string
146      * @access protected
147      */
148     protected $mailHeader = '';
149
150     /**
151      * Word-wrap the message body to this number of chars.
152      * Set to 0 to not wrap. A useful value here is 78, for RFC2822 section 2.1.1 compliance.
153      * @type integer
154      */
155     public $WordWrap = 0;
156
157     /**
158      * Which method to use to send mail.
159      * Options: "mail", "sendmail", or "smtp".
160      * @type string
161      */
162     public $Mailer = 'mail';
163
164     /**
165      * The path to the sendmail program.
166      * @type string
167      */
168     public $Sendmail = '/usr/sbin/sendmail';
169
170     /**
171      * Whether mail() uses a fully sendmail-compatible MTA.
172      * One which supports sendmail's "-oi -f" options.
173      * @type boolean
174      */
175     public $UseSendmailOptions = true;
176
177     /**
178      * Path to PHPMailer plugins.
179      * Useful if the SMTP class is not in the PHP include path.
180      * @type string
181      * @deprecated Should not be needed now there is an autoloader.
182      */
183     public $PluginDir = '';
184
185     /**
186      * The email address that a reading confirmation should be sent to.
187      * @type string
188      */
189     public $ConfirmReadingTo = '';
190
191     /**
192      * The hostname to use in Message-Id and Received headers
193      * and as default HELO string.
194      * If empty, the value returned
195      * by SERVER_NAME is used or 'localhost.localdomain'.
196      * @type string
197      */
198     public $Hostname = '';
199
200     /**
201      * An ID to be used in the Message-Id header.
202      * If empty, a unique id will be generated.
203      * @type string
204      */
205     public $MessageID = '';
206
207     /**
208      * The message Date to be used in the Date header.
209      * If empty, the current date will be added.
210      * @type string
211      */
212     public $MessageDate = '';
213
214     /**
215      * SMTP hosts.
216      * Either a single hostname or multiple semicolon-delimited hostnames.
217      * You can also specify a different port
218      * for each host by using this format: [hostname:port]
219      * (e.g. "smtp1.example.com:25;smtp2.example.com").
220      * You can also specify encryption type, for example:
221      * (e.g. "tls://smtp1.example.com:587;ssl://smtp2.example.com:465").
222      * Hosts will be tried in order.
223      * @type string
224      */
225     public $Host = 'localhost';
226
227     /**
228      * The default SMTP server port.
229      * @type integer
230      * @TODO Why is this needed when the SMTP class takes care of it?
231      */
232     public $Port = 25;
233
234     /**
235      * The SMTP HELO of the message.
236      * Default is $Hostname.
237      * @type string
238      * @see PHPMailer::$Hostname
239      */
240     public $Helo = '';
241
242     /**
243      * What kind of encryption to use on the SMTP connection.
244      * Options: '', 'ssl' or 'tls'
245      * @type string
246      */
247     public $SMTPSecure = '';
248
249     /**
250      * Whether to enable TLS encryption automatically if a server supports it,
251      * even if `SMTPSecure` is not set to 'tls'.
252      * Be aware that in PHP >= 5.6 this requires that the server's certificates are valid.
253      * @type boolean
254      */
255     public $SMTPAutoTLS = true;
256
257     /**
258      * Whether to use SMTP authentication.
259      * Uses the Username and Password properties.
260      * @type boolean
261      * @see PHPMailer::$Username
262      * @see PHPMailer::$Password
263      */
264     public $SMTPAuth = false;
265
266     /**
267      * Options array passed to stream_context_create when connecting via SMTP.
268      * @type array
269      */
270     public $SMTPOptions = array();
271
272     /**
273      * SMTP username.
274      * @type string
275      */
276     public $Username = '';
277
278     /**
279      * SMTP password.
280      * @type string
281      */
282     public $Password = '';
283
284     /**
285      * SMTP auth type.
286      * Options are LOGIN (default), PLAIN, NTLM, CRAM-MD5
287      * @type string
288      */
289     public $AuthType = '';
290
291     /**
292      * SMTP realm.
293      * Used for NTLM auth
294      * @type string
295      */
296     public $Realm = '';
297
298     /**
299      * SMTP workstation.
300      * Used for NTLM auth
301      * @type string
302      */
303     public $Workstation = '';
304
305     /**
306      * The SMTP server timeout in seconds.
307      * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2
308      * @type integer
309      */
310     public $Timeout = 300;
311
312     /**
313      * SMTP class debug output mode.
314      * Debug output level.
315      * Options:
316      * * `0` No output
317      * * `1` Commands
318      * * `2` Data and commands
319      * * `3` As 2 plus connection status
320      * * `4` Low-level data output
321      * @type integer
322      * @see SMTP::$do_debug
323      */
324     public $SMTPDebug = 0;
325
326     /**
327      * How to handle debug output.
328      * Options:
329      * * `echo` Output plain-text as-is, appropriate for CLI
330      * * `html` Output escaped, line breaks converted to `<br>`, appropriate for browser output
331      * * `error_log` Output to error log as configured in php.ini
332      *
333      * Alternatively, you can provide a callable expecting two params: a message string and the debug level:
334      * <code>
335      * $mail->Debugoutput = function($str, $level) {echo "debug level $level; message: $str";};
336      * </code>
337      * @type string|callable
338      * @see SMTP::$Debugoutput
339      */
340     public $Debugoutput = 'echo';
341
342     /**
343      * Whether to keep SMTP connection open after each message.
344      * If this is set to true then to close the connection
345      * requires an explicit call to smtpClose().
346      * @type boolean
347      */
348     public $SMTPKeepAlive = false;
349
350     /**
351      * Whether to split multiple to addresses into multiple messages
352      * or send them all in one message.
353      * @type boolean
354      */
355     public $SingleTo = false;
356
357     /**
358      * Storage for addresses when SingleTo is enabled.
359      * @type array
360      * @TODO This should really not be public
361      */
362     public $SingleToArray = array();
363
364     /**
365      * Whether to generate VERP addresses on send.
366      * Only applicable when sending via SMTP.
367      * @link http://en.wikipedia.org/wiki/Variable_envelope_return_path
368      * @link http://www.postfix.org/VERP_README.html Postfix VERP info
369      * @type boolean
370      */
371     public $do_verp = false;
372
373     /**
374      * Whether to allow sending messages with an empty body.
375      * @type boolean
376      */
377     public $AllowEmpty = false;
378
379     /**
380      * The default line ending.
381      * @note The default remains "\n". We force CRLF where we know
382      *        it must be used via self::CRLF.
383      * @type string
384      */
385     public $LE = "\n";
386
387     /**
388      * DKIM selector.
389      * @type string
390      */
391     public $DKIM_selector = '';
392
393     /**
394      * DKIM Identity.
395      * Usually the email address used as the source of the email
396      * @type string
397      */
398     public $DKIM_identity = '';
399
400     /**
401      * DKIM passphrase.
402      * Used if your key is encrypted.
403      * @type string
404      */
405     public $DKIM_passphrase = '';
406
407     /**
408      * DKIM signing domain name.
409      * @example 'example.com'
410      * @type string
411      */
412     public $DKIM_domain = '';
413
414     /**
415      * DKIM private key file path.
416      * @type string
417      */
418     public $DKIM_private = '';
419
420     /**
421      * Callback Action function name.
422      *
423      * The function that handles the result of the send email action.
424      * It is called out by send() for each email sent.
425      *
426      * Value can be any php callable: http://www.php.net/is_callable
427      *
428      * Parameters:
429      *   boolean $result        result of the send action
430      *   string  $to            email address of the recipient
431      *   string  $cc            cc email addresses
432      *   string  $bcc           bcc email addresses
433      *   string  $subject       the subject
434      *   string  $body          the email body
435      *   string  $from          email address of sender
436      * @type string
437      */
438     public $action_function = '';
439
440     /**
441      * What to put in the X-Mailer header.
442      * Options: An empty string for PHPMailer default, whitespace for none, or a string to use
443      * @type string
444      */
445     public $XMailer = '';
446
447     /**
448      * An instance of the SMTP sender class.
449      * @type SMTP
450      * @access protected
451      */
452     protected $smtp = null;
453
454     /**
455      * The array of 'to' addresses.
456      * @type array
457      * @access protected
458      */
459     protected $to = array();
460
461     /**
462      * The array of 'cc' addresses.
463      * @type array
464      * @access protected
465      */
466     protected $cc = array();
467
468     /**
469      * The array of 'bcc' addresses.
470      * @type array
471      * @access protected
472      */
473     protected $bcc = array();
474
475     /**
476      * The array of reply-to names and addresses.
477      * @type array
478      * @access protected
479      */
480     protected $ReplyTo = array();
481
482     /**
483      * An array of all kinds of addresses.
484      * Includes all of $to, $cc, $bcc
485      * @type array
486      * @access protected
487      */
488     protected $all_recipients = array();
489
490     /**
491      * The array of attachments.
492      * @type array
493      * @access protected
494      */
495     protected $attachment = array();
496
497     /**
498      * The array of custom headers.
499      * @type array
500      * @access protected
501      */
502     protected $CustomHeader = array();
503
504     /**
505      * The most recent Message-ID (including angular brackets).
506      * @type string
507      * @access protected
508      */
509     protected $lastMessageID = '';
510
511     /**
512      * The message's MIME type.
513      * @type string
514      * @access protected
515      */
516     protected $message_type = '';
517
518     /**
519      * The array of MIME boundary strings.
520      * @type array
521      * @access protected
522      */
523     protected $boundary = array();
524
525     /**
526      * The array of available languages.
527      * @type array
528      * @access protected
529      */
530     protected $language = array();
531
532     /**
533      * The number of errors encountered.
534      * @type integer
535      * @access protected
536      */
537     protected $error_count = 0;
538
539     /**
540      * The S/MIME certificate file path.
541      * @type string
542      * @access protected
543      */
544     protected $sign_cert_file = '';
545
546     /**
547      * The S/MIME key file path.
548      * @type string
549      * @access protected
550      */
551     protected $sign_key_file = '';
552
553     /**
554      * The optional S/MIME extra certificates ("CA Chain") file path.
555      * @type string
556      * @access protected
557      */
558     protected $sign_extracerts_file = '';
559
560     /**
561      * The S/MIME password for the key.
562      * Used only if the key is encrypted.
563      * @type string
564      * @access protected
565      */
566     protected $sign_key_pass = '';
567
568     /**
569      * Whether to throw exceptions for errors.
570      * @type boolean
571      * @access protected
572      */
573     protected $exceptions = false;
574
575     /**
576      * Unique ID used for message ID and boundaries.
577      * @type string
578      * @access protected
579      */
580     protected $uniqueid = '';
581
582     /**
583      * Error severity: message only, continue processing.
584      */
585     const STOP_MESSAGE = 0;
586
587     /**
588      * Error severity: message, likely ok to continue processing.
589      */
590     const STOP_CONTINUE = 1;
591
592     /**
593      * Error severity: message, plus full stop, critical error reached.
594      */
595     const STOP_CRITICAL = 2;
596
597     /**
598      * SMTP RFC standard line ending.
599      */
600     const CRLF = "\r\n";
601
602     /**
603      * The maximum line length allowed by RFC 2822 section 2.1.1
604      * @type integer
605      */
606     const MAX_LINE_LENGTH = 998;
607
608     /**
609      * Constructor.
610      * @param boolean $exceptions Should we throw external exceptions?
611      */
612     public function __construct($exceptions = false)
613     {
614         $this->exceptions = (boolean)$exceptions;
615     }
616
617     /**
618      * Destructor.
619      */
620     public function __destruct()
621     {
622         //Close any open SMTP connection nicely
623         if ($this->Mailer == 'smtp') {
624             $this->smtpClose();
625         }
626     }
627
628     /**
629      * Call mail() in a safe_mode-aware fashion.
630      * Also, unless sendmail_path points to sendmail (or something that
631      * claims to be sendmail), don't pass params (not a perfect fix,
632      * but it will do)
633      * @param string $to To
634      * @param string $subject Subject
635      * @param string $body Message Body
636      * @param string $header Additional Header(s)
637      * @param string $params Params
638      * @access private
639      * @return boolean
640      */
641     private function mailPassthru($to, $subject, $body, $header, $params)
642     {
643         //Check overloading of mail function to avoid double-encoding
644         if (ini_get('mbstring.func_overload') & 1) {
645             $subject = $this->secureHeader($subject);
646         } else {
647             $subject = $this->encodeHeader($this->secureHeader($subject));
648         }
649         if (ini_get('safe_mode') || !($this->UseSendmailOptions)) {
650             $result = @mail($to, $subject, $body, $header);
651         } else {
652             $result = @mail($to, $subject, $body, $header, $params);
653         }
654         return $result;
655     }
656
657     /**
658      * Output debugging info via user-defined method.
659      * Only generates output if SMTP debug output is enabled (@see SMTP::$do_debug).
660      * @see PHPMailer::$Debugoutput
661      * @see PHPMailer::$SMTPDebug
662      * @param string $str
663      */
664     protected function edebug($str)
665     {
666         if ($this->SMTPDebug <= 0) {
667             return;
668         }
669         //Avoid clash with built-in function names
670         if (!in_array($this->Debugoutput, array('error_log', 'html', 'echo')) and is_callable($this->Debugoutput)) {
671             call_user_func($this->Debugoutput, $str, $this->SMTPDebug);
672             return;
673         }
674         switch ($this->Debugoutput) {
675             case 'error_log':
676                 //Don't output, just log
677                 error_log($str);
678                 break;
679             case 'html':
680                 //Cleans up output a bit for a better looking, HTML-safe output
681                 echo htmlentities(
682                     preg_replace('/[\r\n]+/', '', $str),
683                     ENT_QUOTES,
684                     'UTF-8'
685                 )
686                 . "<br>\n";
687                 break;
688             case 'echo':
689             default:
690                 //Normalize line breaks
691                 $str = preg_replace('/(\r\n|\r|\n)/ms', "\n", $str);
692                 echo gmdate('Y-m-d H:i:s') . "\t" . str_replace(
693                     "\n",
694                     "\n                   \t                  ",
695                     trim($str)
696                 ) . "\n";
697         }
698     }
699
700     /**
701      * Sets message type to HTML or plain.
702      * @param boolean $isHtml True for HTML mode.
703      * @return void
704      */
705     public function isHTML($isHtml = true)
706     {
707         if ($isHtml) {
708             $this->ContentType = 'text/html';
709         } else {
710             $this->ContentType = 'text/plain';
711         }
712     }
713
714     /**
715      * Send messages using SMTP.
716      * @return void
717      */
718     public function isSMTP()
719     {
720         $this->Mailer = 'smtp';
721     }
722
723     /**
724      * Send messages using PHP's mail() function.
725      * @return void
726      */
727     public function isMail()
728     {
729         $this->Mailer = 'mail';
730     }
731
732     /**
733      * Send messages using $Sendmail.
734      * @return void
735      */
736     public function isSendmail()
737     {
738         $ini_sendmail_path = ini_get('sendmail_path');
739
740         if (!stristr($ini_sendmail_path, 'sendmail')) {
741             $this->Sendmail = '/usr/sbin/sendmail';
742         } else {
743             $this->Sendmail = $ini_sendmail_path;
744         }
745         $this->Mailer = 'sendmail';
746     }
747
748     /**
749      * Send messages using qmail.
750      * @return void
751      */
752     public function isQmail()
753     {
754         $ini_sendmail_path = ini_get('sendmail_path');
755
756         if (!stristr($ini_sendmail_path, 'qmail')) {
757             $this->Sendmail = '/var/qmail/bin/qmail-inject';
758         } else {
759             $this->Sendmail = $ini_sendmail_path;
760         }
761         $this->Mailer = 'qmail';
762     }
763
764     /**
765      * Add a "To" address.
766      * @param string $address
767      * @param string $name
768      * @return boolean true on success, false if address already used
769      */
770     public function addAddress($address, $name = '')
771     {
772         return $this->addAnAddress('to', $address, $name);
773     }
774
775     /**
776      * Add a "CC" address.
777      * @note: This function works with the SMTP mailer on win32, not with the "mail" mailer.
778      * @param string $address
779      * @param string $name
780      * @return boolean true on success, false if address already used
781      */
782     public function addCC($address, $name = '')
783     {
784         return $this->addAnAddress('cc', $address, $name);
785     }
786
787     /**
788      * Add a "BCC" address.
789      * @note: This function works with the SMTP mailer on win32, not with the "mail" mailer.
790      * @param string $address
791      * @param string $name
792      * @return boolean true on success, false if address already used
793      */
794     public function addBCC($address, $name = '')
795     {
796         return $this->addAnAddress('bcc', $address, $name);
797     }
798
799     /**
800      * Add a "Reply-to" address.
801      * @param string $address
802      * @param string $name
803      * @return boolean
804      */
805     public function addReplyTo($address, $name = '')
806     {
807         return $this->addAnAddress('Reply-To', $address, $name);
808     }
809
810     /**
811      * Add an address to one of the recipient arrays.
812      * Addresses that have been added already return false, but do not throw exceptions
813      * @param string $kind One of 'to', 'cc', 'bcc', 'ReplyTo'
814      * @param string $address The email address to send to
815      * @param string $name
816      * @throws phpmailerException
817      * @return boolean true on success, false if address already used or invalid in some way
818      * @access protected
819      */
820     protected function addAnAddress($kind, $address, $name = '')
821     {
822         if (!preg_match('/^(to|cc|bcc|Reply-To)$/', $kind)) {
823             $this->setError($this->lang('Invalid recipient array') . ': ' . $kind);
824             $this->edebug($this->lang('Invalid recipient array') . ': ' . $kind);
825             if ($this->exceptions) {
826                 throw new phpmailerException('Invalid recipient array: ' . $kind);
827             }
828             return false;
829         }
830         $address = trim($address);
831         $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
832         if (!$this->validateAddress($address)) {
833             $this->setError($this->lang('invalid_address') . ': ' . $address);
834             $this->edebug($this->lang('invalid_address') . ': ' . $address);
835             if ($this->exceptions) {
836                 throw new phpmailerException($this->lang('invalid_address') . ': ' . $address);
837             }
838             return false;
839         }
840         if ($kind != 'Reply-To') {
841             if (!isset($this->all_recipients[strtolower($address)])) {
842                 array_push($this->$kind, array($address, $name));
843                 $this->all_recipients[strtolower($address)] = true;
844                 return true;
845             }
846         } else {
847             if (!array_key_exists(strtolower($address), $this->ReplyTo)) {
848                 $this->ReplyTo[strtolower($address)] = array($address, $name);
849                 return true;
850             }
851         }
852         return false;
853     }
854
855     /**
856      * Set the From and FromName properties.
857      * @param string $address
858      * @param string $name
859      * @param boolean $auto Whether to also set the Sender address, defaults to true
860      * @throws phpmailerException
861      * @return boolean
862      */
863     public function setFrom($address, $name = '', $auto = true)
864     {
865         $address = trim($address);
866         $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
867         if (!$this->validateAddress($address)) {
868             $this->setError($this->lang('invalid_address') . ': ' . $address);
869             $this->edebug($this->lang('invalid_address') . ': ' . $address);
870             if ($this->exceptions) {
871                 throw new phpmailerException($this->lang('invalid_address') . ': ' . $address);
872             }
873             return false;
874         }
875         $this->From = $address;
876         $this->FromName = $name;
877         if ($auto) {
878             if (empty($this->Sender)) {
879                 $this->Sender = $address;
880             }
881         }
882         return true;
883     }
884
885     /**
886      * Return the Message-ID header of the last email.
887      * Technically this is the value from the last time the headers were created,
888      * but it's also the message ID of the last sent message except in
889      * pathological cases.
890      * @return string
891      */
892     public function getLastMessageID()
893     {
894         return $this->lastMessageID;
895     }
896
897     /**
898      * Check that a string looks like an email address.
899      * @param string $address The email address to check
900      * @param string $patternselect A selector for the validation pattern to use :
901      * * `auto` Pick strictest one automatically;
902      * * `pcre8` Use the squiloople.com pattern, requires PCRE > 8.0, PHP >= 5.3.2, 5.2.14;
903      * * `pcre` Use old PCRE implementation;
904      * * `php` Use PHP built-in FILTER_VALIDATE_EMAIL; same as pcre8 but does not allow 'dotless' domains;
905      * * `html5` Use the pattern given by the HTML5 spec for 'email' type form input elements.
906      * * `noregex` Don't use a regex: super fast, really dumb.
907      * @return boolean
908      * @static
909      * @access public
910      */
911     public static function validateAddress($address, $patternselect = 'auto')
912     {
913         if (!$patternselect or $patternselect == 'auto') {
914             //Check this constant first so it works when extension_loaded() is disabled by safe mode
915             //Constant was added in PHP 5.2.4
916             if (defined('PCRE_VERSION')) {
917                 //This pattern can get stuck in a recursive loop in PCRE <= 8.0.2
918                 if (version_compare(PCRE_VERSION, '8.0.3') >= 0) {
919                     $patternselect = 'pcre8';
920                 } else {
921                     $patternselect = 'pcre';
922                 }
923             } elseif (function_exists('extension_loaded') and extension_loaded('pcre')) {
924                 //Fall back to older PCRE
925                 $patternselect = 'pcre';
926             } else {
927                 //Filter_var appeared in PHP 5.2.0 and does not require the PCRE extension
928                 if (version_compare(PHP_VERSION, '5.2.0') >= 0) {
929                     $patternselect = 'php';
930                 } else {
931                     $patternselect = 'noregex';
932                 }
933             }
934         }
935         switch ($patternselect) {
936             case 'pcre8':
937                 /**
938                  * Uses the same RFC5322 regex on which FILTER_VALIDATE_EMAIL is based, but allows dotless domains.
939                  * @link http://squiloople.com/2009/12/20/email-address-validation/
940                  * @copyright 2009-2010 Michael Rushton
941                  * Feel free to use and redistribute this code. But please keep this copyright notice.
942                  */
943                 return (boolean)preg_match(
944                     '/^(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){255,})(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){65,}@)' .
945                     '((?>(?>(?>((?>(?>(?>\x0D\x0A)?[\t ])+|(?>[\t ]*\x0D\x0A)?[\t ]+)?)(\((?>(?2)' .
946                     '(?>[\x01-\x08\x0B\x0C\x0E-\'*-\[\]-\x7F]|\\\[\x00-\x7F]|(?3)))*(?2)\)))+(?2))|(?2))?)' .
947                     '([!#-\'*+\/-9=?^-~-]+|"(?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\x7F]))*' .
948                     '(?2)")(?>(?1)\.(?1)(?4))*(?1)@(?!(?1)[a-z0-9-]{64,})(?1)(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)' .
949                     '(?>(?1)\.(?!(?1)[a-z0-9-]{64,})(?1)(?5)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?6)){7}' .
950                     '|(?!(?:.*[a-f0-9][:\]]){8,})((?6)(?>:(?6)){0,6})?::(?7)?))|(?>(?>IPv6:(?>(?6)(?>:(?6)){5}:' .
951                     '|(?!(?:.*[a-f0-9]:){6,})(?8)?::(?>((?6)(?>:(?6)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}' .
952                     '|[1-9]?[0-9])(?>\.(?9)){3}))\])(?1)$/isD',
953                     $address
954                 );
955             case 'pcre':
956                 //An older regex that doesn't need a recent PCRE
957                 return (boolean)preg_match(
958                     '/^(?!(?>"?(?>\\\[ -~]|[^"])"?){255,})(?!(?>"?(?>\\\[ -~]|[^"])"?){65,}@)(?>' .
959                     '[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*")' .
960                     '(?>\.(?>[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*"))*' .
961                     '@(?>(?![a-z0-9-]{64,})(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>\.(?![a-z0-9-]{64,})' .
962                     '(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)){0,126}|\[(?:(?>IPv6:(?>(?>[a-f0-9]{1,4})(?>:' .
963                     '[a-f0-9]{1,4}){7}|(?!(?:.*[a-f0-9][:\]]){8,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?' .
964                     '::(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?))|(?>(?>IPv6:(?>[a-f0-9]{1,4}(?>:' .
965                     '[a-f0-9]{1,4}){5}:|(?!(?:.*[a-f0-9]:){6,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4})?' .
966                     '::(?>(?:[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4}):)?))?(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}' .
967                     '|[1-9]?[0-9])(?>\.(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}))\])$/isD',
968                     $address
969                 );
970             case 'html5':
971                 /**
972                  * This is the pattern used in the HTML5 spec for validation of 'email' type form input elements.
973                  * @link http://www.whatwg.org/specs/web-apps/current-work/#e-mail-state-(type=email)
974                  */
975                 return (boolean)preg_match(
976                     '/^[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}' .
977                     '[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/sD',
978                     $address
979                 );
980             case 'noregex':
981                 //No PCRE! Do something _very_ approximate!
982                 //Check the address is 3 chars or longer and contains an @ that's not the first or last char
983                 return (strlen($address) >= 3
984                     and strpos($address, '@') >= 1
985                     and strpos($address, '@') != strlen($address) - 1);
986             case 'php':
987             default:
988                 return (boolean)filter_var($address, FILTER_VALIDATE_EMAIL);
989         }
990     }
991
992     /**
993      * Create a message and send it.
994      * Uses the sending method specified by $Mailer.
995      * @throws phpmailerException
996      * @return boolean false on error - See the ErrorInfo property for details of the error.
997      */
998     public function send()
999     {
1000         try {
1001             if (!$this->preSend()) {
1002                 return false;
1003             }
1004             return $this->postSend();
1005         } catch (phpmailerException $exc) {
1006             $this->mailHeader = '';
1007             $this->setError($exc->getMessage());
1008             if ($this->exceptions) {
1009                 throw $exc;
1010             }
1011             return false;
1012         }
1013     }
1014
1015     /**
1016      * Prepare a message for sending.
1017      * @throws phpmailerException
1018      * @return boolean
1019      */
1020     public function preSend()
1021     {
1022         try {
1023             $this->mailHeader = '';
1024             if ((count($this->to) + count($this->cc) + count($this->bcc)) < 1) {
1025                 throw new phpmailerException($this->lang('provide_address'), self::STOP_CRITICAL);
1026             }
1027
1028             // Set whether the message is multipart/alternative
1029             if (!empty($this->AltBody)) {
1030                 $this->ContentType = 'multipart/alternative';
1031             }
1032
1033             $this->error_count = 0; // Reset errors
1034             $this->setMessageType();
1035             // Refuse to send an empty message unless we are specifically allowing it
1036             if (!$this->AllowEmpty and empty($this->Body)) {
1037                 throw new phpmailerException($this->lang('empty_message'), self::STOP_CRITICAL);
1038             }
1039
1040             // Create body before headers in case body makes changes to headers (e.g. altering transfer encoding)
1041             $this->MIMEHeader = '';
1042             $this->MIMEBody = $this->createBody();
1043             // createBody may have added some headers, so retain them
1044             $tempheaders = $this->MIMEHeader;
1045             $this->MIMEHeader = $this->createHeader();
1046             $this->MIMEHeader .= $tempheaders;
1047
1048             // To capture the complete message when using mail(), create
1049             // an extra header list which createHeader() doesn't fold in
1050             if ($this->Mailer == 'mail') {
1051                 if (count($this->to) > 0) {
1052                     $this->mailHeader .= $this->addrAppend('To', $this->to);
1053                 } else {
1054                     $this->mailHeader .= $this->headerLine('To', 'undisclosed-recipients:;');
1055                 }
1056                 $this->mailHeader .= $this->headerLine(
1057                     'Subject',
1058                     $this->encodeHeader($this->secureHeader(trim($this->Subject)))
1059                 );
1060             }
1061
1062             // Sign with DKIM if enabled
1063             if (!empty($this->DKIM_domain)
1064                 && !empty($this->DKIM_private)
1065                 && !empty($this->DKIM_selector)
1066                 && file_exists($this->DKIM_private)) {
1067                 $header_dkim = $this->DKIM_Add(
1068                     $this->MIMEHeader . $this->mailHeader,
1069                     $this->encodeHeader($this->secureHeader($this->Subject)),
1070                     $this->MIMEBody
1071                 );
1072                 $this->MIMEHeader = rtrim($this->MIMEHeader, "\r\n ") . self::CRLF .
1073                     str_replace("\r\n", "\n", $header_dkim) . self::CRLF;
1074             }
1075             return true;
1076         } catch (phpmailerException $exc) {
1077             $this->setError($exc->getMessage());
1078             if ($this->exceptions) {
1079                 throw $exc;
1080             }
1081             return false;
1082         }
1083     }
1084
1085     /**
1086      * Actually send a message.
1087      * Send the email via the selected mechanism
1088      * @throws phpmailerException
1089      * @return boolean
1090      */
1091     public function postSend()
1092     {
1093         try {
1094             // Choose the mailer and send through it
1095             switch ($this->Mailer) {
1096                 case 'sendmail':
1097                 case 'qmail':
1098                     return $this->sendmailSend($this->MIMEHeader, $this->MIMEBody);
1099                 case 'smtp':
1100                     return $this->smtpSend($this->MIMEHeader, $this->MIMEBody);
1101                 case 'mail':
1102                     return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
1103                 default:
1104                     $sendMethod = $this->Mailer.'Send';
1105                     if (method_exists($this, $sendMethod)) {
1106                         return $this->$sendMethod($this->MIMEHeader, $this->MIMEBody);
1107                     }
1108
1109                     return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
1110             }
1111         } catch (phpmailerException $exc) {
1112             $this->setError($exc->getMessage());
1113             $this->edebug($exc->getMessage());
1114             if ($this->exceptions) {
1115                 throw $exc;
1116             }
1117         }
1118         return false;
1119     }
1120
1121     /**
1122      * Send mail using the $Sendmail program.
1123      * @param string $header The message headers
1124      * @param string $body The message body
1125      * @see PHPMailer::$Sendmail
1126      * @throws phpmailerException
1127      * @access protected
1128      * @return boolean
1129      */
1130     protected function sendmailSend($header, $body)
1131     {
1132         if ($this->Sender != '') {
1133             if ($this->Mailer == 'qmail') {
1134                 $sendmail = sprintf('%s -f%s', escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
1135             } else {
1136                 $sendmail = sprintf('%s -oi -f%s -t', escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
1137             }
1138         } else {
1139             if ($this->Mailer == 'qmail') {
1140                 $sendmail = sprintf('%s', escapeshellcmd($this->Sendmail));
1141             } else {
1142                 $sendmail = sprintf('%s -oi -t', escapeshellcmd($this->Sendmail));
1143             }
1144         }
1145         if ($this->SingleTo) {
1146             foreach ($this->SingleToArray as $toAddr) {
1147                 if (!@$mail = popen($sendmail, 'w')) {
1148                     throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
1149                 }
1150                 fputs($mail, 'To: ' . $toAddr . "\n");
1151                 fputs($mail, $header);
1152                 fputs($mail, $body);
1153                 $result = pclose($mail);
1154                 $this->doCallback(
1155                     ($result == 0),
1156                     array($toAddr),
1157                     $this->cc,
1158                     $this->bcc,
1159                     $this->Subject,
1160                     $body,
1161                     $this->From
1162                 );
1163                 if ($result != 0) {
1164                     throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
1165                 }
1166             }
1167         } else {
1168             if (!@$mail = popen($sendmail, 'w')) {
1169                 throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
1170             }
1171             fputs($mail, $header);
1172             fputs($mail, $body);
1173             $result = pclose($mail);
1174             $this->doCallback(($result == 0), $this->to, $this->cc, $this->bcc, $this->Subject, $body, $this->From);
1175             if ($result != 0) {
1176                 throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
1177             }
1178         }
1179         return true;
1180     }
1181
1182     /**
1183      * Send mail using the PHP mail() function.
1184      * @param string $header The message headers
1185      * @param string $body The message body
1186      * @link http://www.php.net/manual/en/book.mail.php
1187      * @throws phpmailerException
1188      * @access protected
1189      * @return boolean
1190      */
1191     protected function mailSend($header, $body)
1192     {
1193         $toArr = array();
1194         foreach ($this->to as $toaddr) {
1195             $toArr[] = $this->addrFormat($toaddr);
1196         }
1197         $to = implode(', ', $toArr);
1198
1199         if (empty($this->Sender)) {
1200             $params = ' ';
1201         } else {
1202             $params = sprintf('-f%s', $this->Sender);
1203         }
1204         if ($this->Sender != '' and !ini_get('safe_mode')) {
1205             $old_from = ini_get('sendmail_from');
1206             ini_set('sendmail_from', $this->Sender);
1207         }
1208         $result = false;
1209         if ($this->SingleTo && count($toArr) > 1) {
1210             foreach ($toArr as $toAddr) {
1211                 $result = $this->mailPassthru($toAddr, $this->Subject, $body, $header, $params);
1212                 $this->doCallback($result, array($toAddr), $this->cc, $this->bcc, $this->Subject, $body, $this->From);
1213             }
1214         } else {
1215             $result = $this->mailPassthru($to, $this->Subject, $body, $header, $params);
1216             $this->doCallback($result, $this->to, $this->cc, $this->bcc, $this->Subject, $body, $this->From);
1217         }
1218         if (isset($old_from)) {
1219             ini_set('sendmail_from', $old_from);
1220         }
1221         if (!$result) {
1222             throw new phpmailerException($this->lang('instantiate'), self::STOP_CRITICAL);
1223         }
1224         return true;
1225     }
1226
1227     /**
1228      * Get an instance to use for SMTP operations.
1229      * Override this function to load your own SMTP implementation
1230      * @return SMTP
1231      */
1232     public function getSMTPInstance()
1233     {
1234         if (!is_object($this->smtp)) {
1235                 require_once( 'class-smtp.php' );
1236             $this->smtp = new SMTP;
1237         }
1238         return $this->smtp;
1239     }
1240
1241     /**
1242      * Send mail via SMTP.
1243      * Returns false if there is a bad MAIL FROM, RCPT, or DATA input.
1244      * Uses the PHPMailerSMTP class by default.
1245      * @see PHPMailer::getSMTPInstance() to use a different class.
1246      * @param string $header The message headers
1247      * @param string $body The message body
1248      * @throws phpmailerException
1249      * @uses SMTP
1250      * @access protected
1251      * @return boolean
1252      */
1253     protected function smtpSend($header, $body)
1254     {
1255         $bad_rcpt = array();
1256         if (!$this->smtpConnect($this->SMTPOptions)) {
1257             throw new phpmailerException($this->lang('smtp_connect_failed'), self::STOP_CRITICAL);
1258         }
1259         if ('' == $this->Sender) {
1260             $smtp_from = $this->From;
1261         } else {
1262             $smtp_from = $this->Sender;
1263         }
1264         if (!$this->smtp->mail($smtp_from)) {
1265             $this->setError($this->lang('from_failed') . $smtp_from . ' : ' . implode(',', $this->smtp->getError()));
1266             throw new phpmailerException($this->ErrorInfo, self::STOP_CRITICAL);
1267         }
1268
1269         // Attempt to send to all recipients
1270         foreach (array($this->to, $this->cc, $this->bcc) as $togroup) {
1271             foreach ($togroup as $to) {
1272                 if (!$this->smtp->recipient($to[0])) {
1273                     $error = $this->smtp->getError();
1274                     $bad_rcpt[] = array('to' => $to[0], 'error' => $error['detail']);
1275                     $isSent = false;
1276                 } else {
1277                     $isSent = true;
1278                 }
1279                 $this->doCallback($isSent, array($to[0]), array(), array(), $this->Subject, $body, $this->From);
1280             }
1281         }
1282
1283         // Only send the DATA command if we have viable recipients
1284         if ((count($this->all_recipients) > count($bad_rcpt)) and !$this->smtp->data($header . $body)) {
1285             throw new phpmailerException($this->lang('data_not_accepted'), self::STOP_CRITICAL);
1286         }
1287         if ($this->SMTPKeepAlive) {
1288             $this->smtp->reset();
1289         } else {
1290             $this->smtp->quit();
1291             $this->smtp->close();
1292         }
1293         //Create error message for any bad addresses
1294         if (count($bad_rcpt) > 0) {
1295             $errstr = '';
1296             foreach ($bad_rcpt as $bad) {
1297                 $errstr .= $bad['to'] . ': ' . $bad['error'];
1298             }
1299             throw new phpmailerException(
1300                 $this->lang('recipients_failed') . $errstr,
1301                 self::STOP_CONTINUE
1302             );
1303         }
1304         return true;
1305     }
1306
1307     /**
1308      * Initiate a connection to an SMTP server.
1309      * Returns false if the operation failed.
1310      * @param array $options An array of options compatible with stream_context_create()
1311      * @uses SMTP
1312      * @access public
1313      * @throws phpmailerException
1314      * @return boolean
1315      */
1316     public function smtpConnect($options = array())
1317     {
1318         if (is_null($this->smtp)) {
1319             $this->smtp = $this->getSMTPInstance();
1320         }
1321
1322         // Already connected?
1323         if ($this->smtp->connected()) {
1324             return true;
1325         }
1326
1327         $this->smtp->setTimeout($this->Timeout);
1328         $this->smtp->setDebugLevel($this->SMTPDebug);
1329         $this->smtp->setDebugOutput($this->Debugoutput);
1330         $this->smtp->setVerp($this->do_verp);
1331         $hosts = explode(';', $this->Host);
1332         $lastexception = null;
1333
1334         foreach ($hosts as $hostentry) {
1335             $hostinfo = array();
1336             if (!preg_match('/^((ssl|tls):\/\/)*([a-zA-Z0-9\.-]*):?([0-9]*)$/', trim($hostentry), $hostinfo)) {
1337                 // Not a valid host entry
1338                 continue;
1339             }
1340             // $hostinfo[2]: optional ssl or tls prefix
1341             // $hostinfo[3]: the hostname
1342             // $hostinfo[4]: optional port number
1343             // The host string prefix can temporarily override the current setting for SMTPSecure
1344             // If it's not specified, the default value is used
1345             $prefix = '';
1346             $secure = $this->SMTPSecure;
1347             $tls = ($this->SMTPSecure == 'tls');
1348             if ('ssl' == $hostinfo[2] or ('' == $hostinfo[2] and 'ssl' == $this->SMTPSecure)) {
1349                 $prefix = 'ssl://';
1350                 $tls = false; // Can't have SSL and TLS at the same time
1351                 $secure = 'ssl';
1352             } elseif ($hostinfo[2] == 'tls') {
1353                 $tls = true;
1354                 // tls doesn't use a prefix
1355                 $secure = 'tls';
1356             }
1357             //Do we need the OpenSSL extension?
1358             $sslext = defined('OPENSSL_ALGO_SHA1');
1359             if ('tls' === $secure or 'ssl' === $secure) {
1360                 //Check for an OpenSSL constant rather than using extension_loaded, which is sometimes disabled
1361                 if (!$sslext) {
1362                     throw new phpmailerException($this->lang('extension_missing').'openssl', self::STOP_CRITICAL);
1363                 }
1364             }
1365             $host = $hostinfo[3];
1366             $port = $this->Port;
1367             $tport = (integer)$hostinfo[4];
1368             if ($tport > 0 and $tport < 65536) {
1369                 $port = $tport;
1370             }
1371             if ($this->smtp->connect($prefix . $host, $port, $this->Timeout, $options)) {
1372                 try {
1373                     if ($this->Helo) {
1374                         $hello = $this->Helo;
1375                     } else {
1376                         $hello = $this->serverHostname();
1377                     }
1378                     $this->smtp->hello($hello);
1379                     //Automatically enable TLS encryption if:
1380                     // * it's not disabled
1381                     // * we have openssl extension
1382                     // * we are not already using SSL
1383                     // * the server offers STARTTLS
1384                     if ($this->SMTPAutoTLS and $sslext and $secure != 'ssl' and $this->smtp->getServerExt('STARTTLS')) {
1385                         $tls = true;
1386                     }
1387                     if ($tls) {
1388                         if (!$this->smtp->startTLS()) {
1389                             throw new phpmailerException($this->lang('connect_host'));
1390                         }
1391                         // We must resend HELO after tls negotiation
1392                         $this->smtp->hello($hello);
1393                     }
1394                     if ($this->SMTPAuth) {
1395                         if (!$this->smtp->authenticate(
1396                             $this->Username,
1397                             $this->Password,
1398                             $this->AuthType,
1399                             $this->Realm,
1400                             $this->Workstation
1401                         )
1402                         ) {
1403                             throw new phpmailerException($this->lang('authenticate'));
1404                         }
1405                     }
1406                     return true;
1407                 } catch (phpmailerException $exc) {
1408                     $lastexception = $exc;
1409                     $this->edebug($exc->getMessage());
1410                     // We must have connected, but then failed TLS or Auth, so close connection nicely
1411                     $this->smtp->quit();
1412                 }
1413             }
1414         }
1415         // If we get here, all connection attempts have failed, so close connection hard
1416         $this->smtp->close();
1417         // As we've caught all exceptions, just report whatever the last one was
1418         if ($this->exceptions and !is_null($lastexception)) {
1419             throw $lastexception;
1420         }
1421         return false;
1422     }
1423
1424     /**
1425      * Close the active SMTP session if one exists.
1426      * @return void
1427      */
1428     public function smtpClose()
1429     {
1430         if ($this->smtp !== null) {
1431             if ($this->smtp->connected()) {
1432                 $this->smtp->quit();
1433                 $this->smtp->close();
1434             }
1435         }
1436     }
1437
1438     /**
1439      * Set the language for error messages.
1440      * Returns false if it cannot load the language file.
1441      * The default language is English.
1442      * @param string $langcode ISO 639-1 2-character language code (e.g. French is "fr")
1443      * @param string $lang_path Path to the language file directory, with trailing separator (slash)
1444      * @return boolean
1445      * @access public
1446      */
1447     public function setLanguage($langcode = 'en', $lang_path = '')
1448     {
1449         // Define full set of translatable strings in English
1450         $PHPMAILER_LANG = array(
1451             'authenticate' => 'SMTP Error: Could not authenticate.',
1452             'connect_host' => 'SMTP Error: Could not connect to SMTP host.',
1453             'data_not_accepted' => 'SMTP Error: data not accepted.',
1454             'empty_message' => 'Message body empty',
1455             'encoding' => 'Unknown encoding: ',
1456             'execute' => 'Could not execute: ',
1457             'file_access' => 'Could not access file: ',
1458             'file_open' => 'File Error: Could not open file: ',
1459             'from_failed' => 'The following From address failed: ',
1460             'instantiate' => 'Could not instantiate mail function.',
1461             'invalid_address' => 'Invalid address',
1462             'mailer_not_supported' => ' mailer is not supported.',
1463             'provide_address' => 'You must provide at least one recipient email address.',
1464             'recipients_failed' => 'SMTP Error: The following recipients failed: ',
1465             'signing' => 'Signing Error: ',
1466             'smtp_connect_failed' => 'SMTP connect() failed.',
1467             'smtp_error' => 'SMTP server error: ',
1468             'variable_set' => 'Cannot set or reset variable: ',
1469             'extension_missing' => 'Extension missing: '
1470         );
1471         if (empty($lang_path)) {
1472             // Calculate an absolute path so it can work if CWD is not here
1473             $lang_path = dirname(__FILE__). DIRECTORY_SEPARATOR . 'language'. DIRECTORY_SEPARATOR;
1474         }
1475         $foundlang = true;
1476         $lang_file = $lang_path . 'phpmailer.lang-' . $langcode . '.php';
1477         // There is no English translation file
1478         if ($langcode != 'en') {
1479             // Make sure language file path is readable
1480             if (!is_readable($lang_file)) {
1481                 $foundlang = false;
1482             } else {
1483                 // Overwrite language-specific strings.
1484                 // This way we'll never have missing translation keys.
1485                 $foundlang = include $lang_file;
1486             }
1487         }
1488         $this->language = $PHPMAILER_LANG;
1489         return (boolean)$foundlang; // Returns false if language not found
1490     }
1491
1492     /**
1493      * Get the array of strings for the current language.
1494      * @return array
1495      */
1496     public function getTranslations()
1497     {
1498         return $this->language;
1499     }
1500
1501     /**
1502      * Create recipient headers.
1503      * @access public
1504      * @param string $type
1505      * @param array $addr An array of recipient,
1506      * where each recipient is a 2-element indexed array with element 0 containing an address
1507      * and element 1 containing a name, like:
1508      * array(array('joe@example.com', 'Joe User'), array('zoe@example.com', 'Zoe User'))
1509      * @return string
1510      */
1511     public function addrAppend($type, $addr)
1512     {
1513         $addresses = array();
1514         foreach ($addr as $address) {
1515             $addresses[] = $this->addrFormat($address);
1516         }
1517         return $type . ': ' . implode(', ', $addresses) . $this->LE;
1518     }
1519
1520     /**
1521      * Format an address for use in a message header.
1522      * @access public
1523      * @param array $addr A 2-element indexed array, element 0 containing an address, element 1 containing a name
1524      *      like array('joe@example.com', 'Joe User')
1525      * @return string
1526      */
1527     public function addrFormat($addr)
1528     {
1529         if (empty($addr[1])) { // No name provided
1530             return $this->secureHeader($addr[0]);
1531         } else {
1532             return $this->encodeHeader($this->secureHeader($addr[1]), 'phrase') . ' <' . $this->secureHeader(
1533                 $addr[0]
1534             ) . '>';
1535         }
1536     }
1537
1538     /**
1539      * Word-wrap message.
1540      * For use with mailers that do not automatically perform wrapping
1541      * and for quoted-printable encoded messages.
1542      * Original written by philippe.
1543      * @param string $message The message to wrap
1544      * @param integer $length The line length to wrap to
1545      * @param boolean $qp_mode Whether to run in Quoted-Printable mode
1546      * @access public
1547      * @return string
1548      */
1549     public function wrapText($message, $length, $qp_mode = false)
1550     {
1551         if ($qp_mode) {
1552             $soft_break = sprintf(' =%s', $this->LE);
1553         } else {
1554             $soft_break = $this->LE;
1555         }
1556         // If utf-8 encoding is used, we will need to make sure we don't
1557         // split multibyte characters when we wrap
1558         $is_utf8 = (strtolower($this->CharSet) == 'utf-8');
1559         $lelen = strlen($this->LE);
1560         $crlflen = strlen(self::CRLF);
1561
1562         $message = $this->fixEOL($message);
1563         //Remove a trailing line break
1564         if (substr($message, -$lelen) == $this->LE) {
1565             $message = substr($message, 0, -$lelen);
1566         }
1567
1568         //Split message into lines
1569         $lines = explode($this->LE, $message);
1570         //Message will be rebuilt in here
1571         $message = '';
1572         foreach ($lines as $line) {
1573             $words = explode(' ', $line);
1574             $buf = '';
1575             $firstword = true;
1576             foreach ($words as $word) {
1577                 if ($qp_mode and (strlen($word) > $length)) {
1578                     $space_left = $length - strlen($buf) - $crlflen;
1579                     if (!$firstword) {
1580                         if ($space_left > 20) {
1581                             $len = $space_left;
1582                             if ($is_utf8) {
1583                                 $len = $this->utf8CharBoundary($word, $len);
1584                             } elseif (substr($word, $len - 1, 1) == '=') {
1585                                 $len--;
1586                             } elseif (substr($word, $len - 2, 1) == '=') {
1587                                 $len -= 2;
1588                             }
1589                             $part = substr($word, 0, $len);
1590                             $word = substr($word, $len);
1591                             $buf .= ' ' . $part;
1592                             $message .= $buf . sprintf('=%s', self::CRLF);
1593                         } else {
1594                             $message .= $buf . $soft_break;
1595                         }
1596                         $buf = '';
1597                     }
1598                     while (strlen($word) > 0) {
1599                         if ($length <= 0) {
1600                             break;
1601                         }
1602                         $len = $length;
1603                         if ($is_utf8) {
1604                             $len = $this->utf8CharBoundary($word, $len);
1605                         } elseif (substr($word, $len - 1, 1) == '=') {
1606                             $len--;
1607                         } elseif (substr($word, $len - 2, 1) == '=') {
1608                             $len -= 2;
1609                         }
1610                         $part = substr($word, 0, $len);
1611                         $word = substr($word, $len);
1612
1613                         if (strlen($word) > 0) {
1614                             $message .= $part . sprintf('=%s', self::CRLF);
1615                         } else {
1616                             $buf = $part;
1617                         }
1618                     }
1619                 } else {
1620                     $buf_o = $buf;
1621                     if (!$firstword) {
1622                         $buf .= ' ';
1623                     }
1624                     $buf .= $word;
1625
1626                     if (strlen($buf) > $length and $buf_o != '') {
1627                         $message .= $buf_o . $soft_break;
1628                         $buf = $word;
1629                     }
1630                 }
1631                 $firstword = false;
1632             }
1633             $message .= $buf . self::CRLF;
1634         }
1635
1636         return $message;
1637     }
1638
1639     /**
1640      * Find the last character boundary prior to $maxLength in a utf-8
1641      * quoted-printable encoded string.
1642      * Original written by Colin Brown.
1643      * @access public
1644      * @param string $encodedText utf-8 QP text
1645      * @param integer $maxLength Find the last character boundary prior to this length
1646      * @return integer
1647      */
1648     public function utf8CharBoundary($encodedText, $maxLength)
1649     {
1650         $foundSplitPos = false;
1651         $lookBack = 3;
1652         while (!$foundSplitPos) {
1653             $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack);
1654             $encodedCharPos = strpos($lastChunk, '=');
1655             if (false !== $encodedCharPos) {
1656                 // Found start of encoded character byte within $lookBack block.
1657                 // Check the encoded byte value (the 2 chars after the '=')
1658                 $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2);
1659                 $dec = hexdec($hex);
1660                 if ($dec < 128) {
1661                     // Single byte character.
1662                     // If the encoded char was found at pos 0, it will fit
1663                     // otherwise reduce maxLength to start of the encoded char
1664                     if ($encodedCharPos > 0) {
1665                         $maxLength = $maxLength - ($lookBack - $encodedCharPos);
1666                     }
1667                     $foundSplitPos = true;
1668                 } elseif ($dec >= 192) {
1669                     // First byte of a multi byte character
1670                     // Reduce maxLength to split at start of character
1671                     $maxLength = $maxLength - ($lookBack - $encodedCharPos);
1672                     $foundSplitPos = true;
1673                 } elseif ($dec < 192) {
1674                     // Middle byte of a multi byte character, look further back
1675                     $lookBack += 3;
1676                 }
1677             } else {
1678                 // No encoded character found
1679                 $foundSplitPos = true;
1680             }
1681         }
1682         return $maxLength;
1683     }
1684
1685     /**
1686      * Apply word wrapping to the message body.
1687      * Wraps the message body to the number of chars set in the WordWrap property.
1688      * You should only do this to plain-text bodies as wrapping HTML tags may break them.
1689      * This is called automatically by createBody(), so you don't need to call it yourself.
1690      * @access public
1691      * @return void
1692      */
1693     public function setWordWrap()
1694     {
1695         if ($this->WordWrap < 1) {
1696             return;
1697         }
1698
1699         switch ($this->message_type) {
1700             case 'alt':
1701             case 'alt_inline':
1702             case 'alt_attach':
1703             case 'alt_inline_attach':
1704                 $this->AltBody = $this->wrapText($this->AltBody, $this->WordWrap);
1705                 break;
1706             default:
1707                 $this->Body = $this->wrapText($this->Body, $this->WordWrap);
1708                 break;
1709         }
1710     }
1711
1712     /**
1713      * Assemble message headers.
1714      * @access public
1715      * @return string The assembled headers
1716      */
1717     public function createHeader()
1718     {
1719         $result = '';
1720
1721         if ($this->MessageDate == '') {
1722             $this->MessageDate = self::rfcDate();
1723         }
1724         $result .= $this->headerLine('Date', $this->MessageDate);
1725
1726
1727         // To be created automatically by mail()
1728         if ($this->SingleTo) {
1729             if ($this->Mailer != 'mail') {
1730                 foreach ($this->to as $toaddr) {
1731                     $this->SingleToArray[] = $this->addrFormat($toaddr);
1732                 }
1733             }
1734         } else {
1735             if (count($this->to) > 0) {
1736                 if ($this->Mailer != 'mail') {
1737                     $result .= $this->addrAppend('To', $this->to);
1738                 }
1739             } elseif (count($this->cc) == 0) {
1740                 $result .= $this->headerLine('To', 'undisclosed-recipients:;');
1741             }
1742         }
1743
1744         $result .= $this->addrAppend('From', array(array(trim($this->From), $this->FromName)));
1745
1746         // sendmail and mail() extract Cc from the header before sending
1747         if (count($this->cc) > 0) {
1748             $result .= $this->addrAppend('Cc', $this->cc);
1749         }
1750
1751         // sendmail and mail() extract Bcc from the header before sending
1752         if ((
1753                 $this->Mailer == 'sendmail' or $this->Mailer == 'qmail' or $this->Mailer == 'mail'
1754             )
1755             and count($this->bcc) > 0
1756         ) {
1757             $result .= $this->addrAppend('Bcc', $this->bcc);
1758         }
1759
1760         if (count($this->ReplyTo) > 0) {
1761             $result .= $this->addrAppend('Reply-To', $this->ReplyTo);
1762         }
1763
1764         // mail() sets the subject itself
1765         if ($this->Mailer != 'mail') {
1766             $result .= $this->headerLine('Subject', $this->encodeHeader($this->secureHeader($this->Subject)));
1767         }
1768
1769         if ($this->MessageID != '') {
1770             $this->lastMessageID = $this->MessageID;
1771         } else {
1772             $this->lastMessageID = sprintf('<%s@%s>', $this->uniqueid, $this->ServerHostname());
1773         }
1774         $result .= $this->headerLine('Message-ID', $this->lastMessageID);
1775         $result .= $this->headerLine('X-Priority', $this->Priority);
1776         if ($this->XMailer == '') {
1777             $result .= $this->headerLine(
1778                 'X-Mailer',
1779                 'PHPMailer ' . $this->Version . ' (https://github.com/PHPMailer/PHPMailer/)'
1780             );
1781         } else {
1782             $myXmailer = trim($this->XMailer);
1783             if ($myXmailer) {
1784                 $result .= $this->headerLine('X-Mailer', $myXmailer);
1785             }
1786         }
1787
1788         if ($this->ConfirmReadingTo != '') {
1789             $result .= $this->headerLine('Disposition-Notification-To', '<' . trim($this->ConfirmReadingTo) . '>');
1790         }
1791
1792         // Add custom headers
1793         foreach ($this->CustomHeader as $header) {
1794             $result .= $this->headerLine(
1795                 trim($header[0]),
1796                 $this->encodeHeader(trim($header[1]))
1797             );
1798         }
1799         if (!$this->sign_key_file) {
1800             $result .= $this->headerLine('MIME-Version', '1.0');
1801             $result .= $this->getMailMIME();
1802         }
1803
1804         return $result;
1805     }
1806
1807     /**
1808      * Get the message MIME type headers.
1809      * @access public
1810      * @return string
1811      */
1812     public function getMailMIME()
1813     {
1814         $result = '';
1815         $ismultipart = true;
1816         switch ($this->message_type) {
1817             case 'inline':
1818                 $result .= $this->headerLine('Content-Type', 'multipart/related;');
1819                 $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
1820                 break;
1821             case 'attach':
1822             case 'inline_attach':
1823             case 'alt_attach':
1824             case 'alt_inline_attach':
1825                 $result .= $this->headerLine('Content-Type', 'multipart/mixed;');
1826                 $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
1827                 break;
1828             case 'alt':
1829             case 'alt_inline':
1830                 $result .= $this->headerLine('Content-Type', 'multipart/alternative;');
1831                 $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
1832                 break;
1833             default:
1834                 // Catches case 'plain': and case '':
1835                 $result .= $this->textLine('Content-Type: ' . $this->ContentType . '; charset=' . $this->CharSet);
1836                 $ismultipart = false;
1837                 break;
1838         }
1839         // RFC1341 part 5 says 7bit is assumed if not specified
1840         if ($this->Encoding != '7bit') {
1841             // RFC 2045 section 6.4 says multipart MIME parts may only use 7bit, 8bit or binary CTE
1842             if ($ismultipart) {
1843                 if ($this->Encoding == '8bit') {
1844                     $result .= $this->headerLine('Content-Transfer-Encoding', '8bit');
1845                 }
1846                 // The only remaining alternatives are quoted-printable and base64, which are both 7bit compatible
1847             } else {
1848                 $result .= $this->headerLine('Content-Transfer-Encoding', $this->Encoding);
1849             }
1850         }
1851
1852         if ($this->Mailer != 'mail') {
1853             $result .= $this->LE;
1854         }
1855
1856         return $result;
1857     }
1858
1859     /**
1860      * Returns the whole MIME message.
1861      * Includes complete headers and body.
1862      * Only valid post preSend().
1863      * @see PHPMailer::preSend()
1864      * @access public
1865      * @return string
1866      */
1867     public function getSentMIMEMessage()
1868     {
1869         return $this->MIMEHeader . $this->mailHeader . self::CRLF . $this->MIMEBody;
1870     }
1871
1872     /**
1873      * Assemble the message body.
1874      * Returns an empty string on failure.
1875      * @access public
1876      * @throws phpmailerException
1877      * @return string The assembled message body
1878      */
1879     public function createBody()
1880     {
1881         $body = '';
1882         //Create unique IDs and preset boundaries
1883         $this->uniqueid = md5(uniqid(time()));
1884         $this->boundary[1] = 'b1_' . $this->uniqueid;
1885         $this->boundary[2] = 'b2_' . $this->uniqueid;
1886         $this->boundary[3] = 'b3_' . $this->uniqueid;
1887
1888         if ($this->sign_key_file) {
1889             $body .= $this->getMailMIME() . $this->LE;
1890         }
1891
1892         $this->setWordWrap();
1893
1894         $bodyEncoding = $this->Encoding;
1895         $bodyCharSet = $this->CharSet;
1896         //Can we do a 7-bit downgrade?
1897         if ($bodyEncoding == '8bit' and !$this->has8bitChars($this->Body)) {
1898             $bodyEncoding = '7bit';
1899             $bodyCharSet = 'us-ascii';
1900         }
1901         //If lines are too long, change to quoted-printable transfer encoding
1902         if (self::hasLineLongerThanMax($this->Body)) {
1903             $this->Encoding = 'quoted-printable';
1904             $bodyEncoding = 'quoted-printable';
1905         }
1906
1907         $altBodyEncoding = $this->Encoding;
1908         $altBodyCharSet = $this->CharSet;
1909         //Can we do a 7-bit downgrade?
1910         if ($altBodyEncoding == '8bit' and !$this->has8bitChars($this->AltBody)) {
1911             $altBodyEncoding = '7bit';
1912             $altBodyCharSet = 'us-ascii';
1913         }
1914         //If lines are too long, change to quoted-printable transfer encoding
1915         if (self::hasLineLongerThanMax($this->AltBody)) {
1916             $altBodyEncoding = 'quoted-printable';
1917         }
1918         //Use this as a preamble in all multipart message types
1919         $mimepre = "This is a multi-part message in MIME format." . $this->LE . $this->LE;
1920         switch ($this->message_type) {
1921             case 'inline':
1922                 $body .= $mimepre;
1923                 $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding);
1924                 $body .= $this->encodeString($this->Body, $bodyEncoding);
1925                 $body .= $this->LE . $this->LE;
1926                 $body .= $this->attachAll('inline', $this->boundary[1]);
1927                 break;
1928             case 'attach':
1929                 $body .= $mimepre;
1930                 $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding);
1931                 $body .= $this->encodeString($this->Body, $bodyEncoding);
1932                 $body .= $this->LE . $this->LE;
1933                 $body .= $this->attachAll('attachment', $this->boundary[1]);
1934                 break;
1935             case 'inline_attach':
1936                 $body .= $mimepre;
1937                 $body .= $this->textLine('--' . $this->boundary[1]);
1938                 $body .= $this->headerLine('Content-Type', 'multipart/related;');
1939                 $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
1940                 $body .= $this->LE;
1941                 $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, '', $bodyEncoding);
1942                 $body .= $this->encodeString($this->Body, $bodyEncoding);
1943                 $body .= $this->LE . $this->LE;
1944                 $body .= $this->attachAll('inline', $this->boundary[2]);
1945                 $body .= $this->LE;
1946                 $body .= $this->attachAll('attachment', $this->boundary[1]);
1947                 break;
1948             case 'alt':
1949                 $body .= $mimepre;
1950                 $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding);
1951                 $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
1952                 $body .= $this->LE . $this->LE;
1953                 $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, 'text/html', $bodyEncoding);
1954                 $body .= $this->encodeString($this->Body, $bodyEncoding);
1955                 $body .= $this->LE . $this->LE;
1956                 if (!empty($this->Ical)) {
1957                     $body .= $this->getBoundary($this->boundary[1], '', 'text/calendar; method=REQUEST', '');
1958                     $body .= $this->encodeString($this->Ical, $this->Encoding);
1959                     $body .= $this->LE . $this->LE;
1960                 }
1961                 $body .= $this->endBoundary($this->boundary[1]);
1962                 break;
1963             case 'alt_inline':
1964                 $body .= $mimepre;
1965                 $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding);
1966                 $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
1967                 $body .= $this->LE . $this->LE;
1968                 $body .= $this->textLine('--' . $this->boundary[1]);
1969                 $body .= $this->headerLine('Content-Type', 'multipart/related;');
1970                 $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
1971                 $body .= $this->LE;
1972                 $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding);
1973                 $body .= $this->encodeString($this->Body, $bodyEncoding);
1974                 $body .= $this->LE . $this->LE;
1975                 $body .= $this->attachAll('inline', $this->boundary[2]);
1976                 $body .= $this->LE;
1977                 $body .= $this->endBoundary($this->boundary[1]);
1978                 break;
1979             case 'alt_attach':
1980                 $body .= $mimepre;
1981                 $body .= $this->textLine('--' . $this->boundary[1]);
1982                 $body .= $this->headerLine('Content-Type', 'multipart/alternative;');
1983                 $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
1984                 $body .= $this->LE;
1985                 $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding);
1986                 $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
1987                 $body .= $this->LE . $this->LE;
1988                 $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding);
1989                 $body .= $this->encodeString($this->Body, $bodyEncoding);
1990                 $body .= $this->LE . $this->LE;
1991                 $body .= $this->endBoundary($this->boundary[2]);
1992                 $body .= $this->LE;
1993                 $body .= $this->attachAll('attachment', $this->boundary[1]);
1994                 break;
1995             case 'alt_inline_attach':
1996                 $body .= $mimepre;
1997                 $body .= $this->textLine('--' . $this->boundary[1]);
1998                 $body .= $this->headerLine('Content-Type', 'multipart/alternative;');
1999                 $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
2000                 $body .= $this->LE;
2001                 $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding);
2002                 $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
2003                 $body .= $this->LE . $this->LE;
2004                 $body .= $this->textLine('--' . $this->boundary[2]);
2005                 $body .= $this->headerLine('Content-Type', 'multipart/related;');
2006                 $body .= $this->textLine("\tboundary=\"" . $this->boundary[3] . '"');
2007                 $body .= $this->LE;
2008                 $body .= $this->getBoundary($this->boundary[3], $bodyCharSet, 'text/html', $bodyEncoding);
2009                 $body .= $this->encodeString($this->Body, $bodyEncoding);
2010                 $body .= $this->LE . $this->LE;
2011                 $body .= $this->attachAll('inline', $this->boundary[3]);
2012                 $body .= $this->LE;
2013                 $body .= $this->endBoundary($this->boundary[2]);
2014                 $body .= $this->LE;
2015                 $body .= $this->attachAll('attachment', $this->boundary[1]);
2016                 break;
2017             default:
2018                 // catch case 'plain' and case ''
2019                 $body .= $this->encodeString($this->Body, $bodyEncoding);
2020                 break;
2021         }
2022
2023         if ($this->isError()) {
2024             $body = '';
2025         } elseif ($this->sign_key_file) {
2026             try {
2027                 if (!defined('PKCS7_TEXT')) {
2028                     throw new phpmailerException($this->lang('extension_missing') . 'openssl');
2029                 }
2030                 // @TODO would be nice to use php://temp streams here, but need to wrap for PHP < 5.1
2031                 $file = tempnam(sys_get_temp_dir(), 'mail');
2032                 if (false === file_put_contents($file, $body)) {
2033                     throw new phpmailerException($this->lang('signing') . ' Could not write temp file');
2034                 }
2035                 $signed = tempnam(sys_get_temp_dir(), 'signed');
2036                 //Workaround for PHP bug https://bugs.php.net/bug.php?id=69197
2037                 if (empty($this->sign_extracerts_file)) {
2038                     $sign = @openssl_pkcs7_sign(
2039                         $file,
2040                         $signed,
2041                         'file://' . realpath($this->sign_cert_file),
2042                         array('file://' . realpath($this->sign_key_file), $this->sign_key_pass),
2043                         null
2044                     );
2045                 } else {
2046                     $sign = @openssl_pkcs7_sign(
2047                         $file,
2048                         $signed,
2049                         'file://' . realpath($this->sign_cert_file),
2050                         array('file://' . realpath($this->sign_key_file), $this->sign_key_pass),
2051                         null,
2052                         PKCS7_DETACHED,
2053                         $this->sign_extracerts_file
2054                     );
2055                 }
2056                 if ($sign) {
2057                     @unlink($file);
2058                     $body = file_get_contents($signed);
2059                     @unlink($signed);
2060                     //The message returned by openssl contains both headers and body, so need to split them up
2061                     $parts = explode("\n\n", $body, 2);
2062                     $this->MIMEHeader .= $parts[0] . $this->LE . $this->LE;
2063                     $body = $parts[1];
2064                 } else {
2065                     @unlink($file);
2066                     @unlink($signed);
2067                     throw new phpmailerException($this->lang('signing') . openssl_error_string());
2068                 }
2069             } catch (phpmailerException $exc) {
2070                 $body = '';
2071                 if ($this->exceptions) {
2072                     throw $exc;
2073                 }
2074             }
2075         }
2076         return $body;
2077     }
2078
2079     /**
2080      * Return the start of a message boundary.
2081      * @access protected
2082      * @param string $boundary
2083      * @param string $charSet
2084      * @param string $contentType
2085      * @param string $encoding
2086      * @return string
2087      */
2088     protected function getBoundary($boundary, $charSet, $contentType, $encoding)
2089     {
2090         $result = '';
2091         if ($charSet == '') {
2092             $charSet = $this->CharSet;
2093         }
2094         if ($contentType == '') {
2095             $contentType = $this->ContentType;
2096         }
2097         if ($encoding == '') {
2098             $encoding = $this->Encoding;
2099         }
2100         $result .= $this->textLine('--' . $boundary);
2101         $result .= sprintf('Content-Type: %s; charset=%s', $contentType, $charSet);
2102         $result .= $this->LE;
2103         // RFC1341 part 5 says 7bit is assumed if not specified
2104         if ($encoding != '7bit') {
2105             $result .= $this->headerLine('Content-Transfer-Encoding', $encoding);
2106         }
2107         $result .= $this->LE;
2108
2109         return $result;
2110     }
2111
2112     /**
2113      * Return the end of a message boundary.
2114      * @access protected
2115      * @param string $boundary
2116      * @return string
2117      */
2118     protected function endBoundary($boundary)
2119     {
2120         return $this->LE . '--' . $boundary . '--' . $this->LE;
2121     }
2122
2123     /**
2124      * Set the message type.
2125      * PHPMailer only supports some preset message types,
2126      * not arbitrary MIME structures.
2127      * @access protected
2128      * @return void
2129      */
2130     protected function setMessageType()
2131     {
2132         $type = array();
2133         if ($this->alternativeExists()) {
2134             $type[] = 'alt';
2135         }
2136         if ($this->inlineImageExists()) {
2137             $type[] = 'inline';
2138         }
2139         if ($this->attachmentExists()) {
2140             $type[] = 'attach';
2141         }
2142         $this->message_type = implode('_', $type);
2143         if ($this->message_type == '') {
2144             $this->message_type = 'plain';
2145         }
2146     }
2147
2148     /**
2149      * Format a header line.
2150      * @access public
2151      * @param string $name
2152      * @param string $value
2153      * @return string
2154      */
2155     public function headerLine($name, $value)
2156     {
2157         return $name . ': ' . $value . $this->LE;
2158     }
2159
2160     /**
2161      * Return a formatted mail line.
2162      * @access public
2163      * @param string $value
2164      * @return string
2165      */
2166     public function textLine($value)
2167     {
2168         return $value . $this->LE;
2169     }
2170
2171     /**
2172      * Add an attachment from a path on the filesystem.
2173      * Returns false if the file could not be found or read.
2174      * @param string $path Path to the attachment.
2175      * @param string $name Overrides the attachment name.
2176      * @param string $encoding File encoding (see $Encoding).
2177      * @param string $type File extension (MIME) type.
2178      * @param string $disposition Disposition to use
2179      * @throws phpmailerException
2180      * @return boolean
2181      */
2182     public function addAttachment($path, $name = '', $encoding = 'base64', $type = '', $disposition = 'attachment')
2183     {
2184         try {
2185             if (!@is_file($path)) {
2186                 throw new phpmailerException($this->lang('file_access') . $path, self::STOP_CONTINUE);
2187             }
2188
2189             // If a MIME type is not specified, try to work it out from the file name
2190             if ($type == '') {
2191                 $type = self::filenameToType($path);
2192             }
2193
2194             $filename = basename($path);
2195             if ($name == '') {
2196                 $name = $filename;
2197             }
2198
2199             $this->attachment[] = array(
2200                 0 => $path,
2201                 1 => $filename,
2202                 2 => $name,
2203                 3 => $encoding,
2204                 4 => $type,
2205                 5 => false, // isStringAttachment
2206                 6 => $disposition,
2207                 7 => 0
2208             );
2209
2210         } catch (phpmailerException $exc) {
2211             $this->setError($exc->getMessage());
2212             $this->edebug($exc->getMessage());
2213             if ($this->exceptions) {
2214                 throw $exc;
2215             }
2216             return false;
2217         }
2218         return true;
2219     }
2220
2221     /**
2222      * Return the array of attachments.
2223      * @return array
2224      */
2225     public function getAttachments()
2226     {
2227         return $this->attachment;
2228     }
2229
2230     /**
2231      * Attach all file, string, and binary attachments to the message.
2232      * Returns an empty string on failure.
2233      * @access protected
2234      * @param string $disposition_type
2235      * @param string $boundary
2236      * @return string
2237      */
2238     protected function attachAll($disposition_type, $boundary)
2239     {
2240         // Return text of body
2241         $mime = array();
2242         $cidUniq = array();
2243         $incl = array();
2244
2245         // Add all attachments
2246         foreach ($this->attachment as $attachment) {
2247             // Check if it is a valid disposition_filter
2248             if ($attachment[6] == $disposition_type) {
2249                 // Check for string attachment
2250                 $string = '';
2251                 $path = '';
2252                 $bString = $attachment[5];
2253                 if ($bString) {
2254                     $string = $attachment[0];
2255                 } else {
2256                     $path = $attachment[0];
2257                 }
2258
2259                 $inclhash = md5(serialize($attachment));
2260                 if (in_array($inclhash, $incl)) {
2261                     continue;
2262                 }
2263                 $incl[] = $inclhash;
2264                 $name = $attachment[2];
2265                 $encoding = $attachment[3];
2266                 $type = $attachment[4];
2267                 $disposition = $attachment[6];
2268                 $cid = $attachment[7];
2269                 if ($disposition == 'inline' && isset($cidUniq[$cid])) {
2270                     continue;
2271                 }
2272                 $cidUniq[$cid] = true;
2273
2274                 $mime[] = sprintf('--%s%s', $boundary, $this->LE);
2275                 $mime[] = sprintf(
2276                     'Content-Type: %s; name="%s"%s',
2277                     $type,
2278                     $this->encodeHeader($this->secureHeader($name)),
2279                     $this->LE
2280                 );
2281                 // RFC1341 part 5 says 7bit is assumed if not specified
2282                 if ($encoding != '7bit') {
2283                     $mime[] = sprintf('Content-Transfer-Encoding: %s%s', $encoding, $this->LE);
2284                 }
2285
2286                 if ($disposition == 'inline') {
2287                     $mime[] = sprintf('Content-ID: <%s>%s', $cid, $this->LE);
2288                 }
2289
2290                 // If a filename contains any of these chars, it should be quoted,
2291                 // but not otherwise: RFC2183 & RFC2045 5.1
2292                 // Fixes a warning in IETF's msglint MIME checker
2293                 // Allow for bypassing the Content-Disposition header totally
2294                 if (!(empty($disposition))) {
2295                     $encoded_name = $this->encodeHeader($this->secureHeader($name));
2296                     if (preg_match('/[ \(\)<>@,;:\\"\/\[\]\?=]/', $encoded_name)) {
2297                         $mime[] = sprintf(
2298                             'Content-Disposition: %s; filename="%s"%s',
2299                             $disposition,
2300                             $encoded_name,
2301                             $this->LE . $this->LE
2302                         );
2303                     } else {
2304                         $mime[] = sprintf(
2305                             'Content-Disposition: %s; filename=%s%s',
2306                             $disposition,
2307                             $encoded_name,
2308                             $this->LE . $this->LE
2309                         );
2310                     }
2311                 } else {
2312                     $mime[] = $this->LE;
2313                 }
2314
2315                 // Encode as string attachment
2316                 if ($bString) {
2317                     $mime[] = $this->encodeString($string, $encoding);
2318                     if ($this->isError()) {
2319                         return '';
2320                     }
2321                     $mime[] = $this->LE . $this->LE;
2322                 } else {
2323                     $mime[] = $this->encodeFile($path, $encoding);
2324                     if ($this->isError()) {
2325                         return '';
2326                     }
2327                     $mime[] = $this->LE . $this->LE;
2328                 }
2329             }
2330         }
2331
2332         $mime[] = sprintf('--%s--%s', $boundary, $this->LE);
2333
2334         return implode('', $mime);
2335     }
2336
2337     /**
2338      * Encode a file attachment in requested format.
2339      * Returns an empty string on failure.
2340      * @param string $path The full path to the file
2341      * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
2342      * @throws phpmailerException
2343      * @see EncodeFile(encodeFile
2344      * @access protected
2345      * @return string
2346      */
2347     protected function encodeFile($path, $encoding = 'base64')
2348     {
2349         try {
2350             if (!is_readable($path)) {
2351                 throw new phpmailerException($this->lang('file_open') . $path, self::STOP_CONTINUE);
2352             }
2353             $magic_quotes = get_magic_quotes_runtime();
2354             if ($magic_quotes) {
2355                 if (version_compare(PHP_VERSION, '5.3.0', '<')) {
2356                     set_magic_quotes_runtime(false);
2357                 } else {
2358                     //Doesn't exist in PHP 5.4, but we don't need to check because
2359                     //get_magic_quotes_runtime always returns false in 5.4+
2360                     //so it will never get here
2361                     ini_set('magic_quotes_runtime', false);
2362                 }
2363             }
2364             $file_buffer = file_get_contents($path);
2365             $file_buffer = $this->encodeString($file_buffer, $encoding);
2366             if ($magic_quotes) {
2367                 if (version_compare(PHP_VERSION, '5.3.0', '<')) {
2368                     set_magic_quotes_runtime($magic_quotes);
2369                 } else {
2370                     ini_set('magic_quotes_runtime', $magic_quotes);
2371                 }
2372             }
2373             return $file_buffer;
2374         } catch (Exception $exc) {
2375             $this->setError($exc->getMessage());
2376             return '';
2377         }
2378     }
2379
2380     /**
2381      * Encode a string in requested format.
2382      * Returns an empty string on failure.
2383      * @param string $str The text to encode
2384      * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
2385      * @access public
2386      * @return string
2387      */
2388     public function encodeString($str, $encoding = 'base64')
2389     {
2390         $encoded = '';
2391         switch (strtolower($encoding)) {
2392             case 'base64':
2393                 $encoded = chunk_split(base64_encode($str), 76, $this->LE);
2394                 break;
2395             case '7bit':
2396             case '8bit':
2397                 $encoded = $this->fixEOL($str);
2398                 // Make sure it ends with a line break
2399                 if (substr($encoded, -(strlen($this->LE))) != $this->LE) {
2400                     $encoded .= $this->LE;
2401                 }
2402                 break;
2403             case 'binary':
2404                 $encoded = $str;
2405                 break;
2406             case 'quoted-printable':
2407                 $encoded = $this->encodeQP($str);
2408                 break;
2409             default:
2410                 $this->setError($this->lang('encoding') . $encoding);
2411                 break;
2412         }
2413         return $encoded;
2414     }
2415
2416     /**
2417      * Encode a header string optimally.
2418      * Picks shortest of Q, B, quoted-printable or none.
2419      * @access public
2420      * @param string $str
2421      * @param string $position
2422      * @return string
2423      */
2424     public function encodeHeader($str, $position = 'text')
2425     {
2426         $matchcount = 0;
2427         switch (strtolower($position)) {
2428             case 'phrase':
2429                 if (!preg_match('/[\200-\377]/', $str)) {
2430                     // Can't use addslashes as we don't know the value of magic_quotes_sybase
2431                     $encoded = addcslashes($str, "\0..\37\177\\\"");
2432                     if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) {
2433                         return ($encoded);
2434                     } else {
2435                         return ("\"$encoded\"");
2436                     }
2437                 }
2438                 $matchcount = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches);
2439                 break;
2440             /** @noinspection PhpMissingBreakStatementInspection */
2441             case 'comment':
2442                 $matchcount = preg_match_all('/[()"]/', $str, $matches);
2443                 // Intentional fall-through
2444             case 'text':
2445             default:
2446                 $matchcount += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches);
2447                 break;
2448         }
2449
2450         //There are no chars that need encoding
2451         if ($matchcount == 0) {
2452             return ($str);
2453         }
2454
2455         $maxlen = 75 - 7 - strlen($this->CharSet);
2456         // Try to select the encoding which should produce the shortest output
2457         if ($matchcount > strlen($str) / 3) {
2458             // More than a third of the content will need encoding, so B encoding will be most efficient
2459             $encoding = 'B';
2460             if (function_exists('mb_strlen') && $this->hasMultiBytes($str)) {
2461                 // Use a custom function which correctly encodes and wraps long
2462                 // multibyte strings without breaking lines within a character
2463                 $encoded = $this->base64EncodeWrapMB($str, "\n");
2464             } else {
2465                 $encoded = base64_encode($str);
2466                 $maxlen -= $maxlen % 4;
2467                 $encoded = trim(chunk_split($encoded, $maxlen, "\n"));
2468             }
2469         } else {
2470             $encoding = 'Q';
2471             $encoded = $this->encodeQ($str, $position);
2472             $encoded = $this->wrapText($encoded, $maxlen, true);
2473             $encoded = str_replace('=' . self::CRLF, "\n", trim($encoded));
2474         }
2475
2476         $encoded = preg_replace('/^(.*)$/m', ' =?' . $this->CharSet . "?$encoding?\\1?=", $encoded);
2477         $encoded = trim(str_replace("\n", $this->LE, $encoded));
2478
2479         return $encoded;
2480     }
2481
2482     /**
2483      * Check if a string contains multi-byte characters.
2484      * @access public
2485      * @param string $str multi-byte text to wrap encode
2486      * @return boolean
2487      */
2488     public function hasMultiBytes($str)
2489     {
2490         if (function_exists('mb_strlen')) {
2491             return (strlen($str) > mb_strlen($str, $this->CharSet));
2492         } else { // Assume no multibytes (we can't handle without mbstring functions anyway)
2493             return false;
2494         }
2495     }
2496
2497     /**
2498      * Does a string contain any 8-bit chars (in any charset)?
2499      * @param string $text
2500      * @return boolean
2501      */
2502     public function has8bitChars($text)
2503     {
2504         return (boolean)preg_match('/[\x80-\xFF]/', $text);
2505     }
2506
2507     /**
2508      * Encode and wrap long multibyte strings for mail headers
2509      * without breaking lines within a character.
2510      * Adapted from a function by paravoid
2511      * @link http://www.php.net/manual/en/function.mb-encode-mimeheader.php#60283
2512      * @access public
2513      * @param string $str multi-byte text to wrap encode
2514      * @param string $linebreak string to use as linefeed/end-of-line
2515      * @return string
2516      */
2517     public function base64EncodeWrapMB($str, $linebreak = null)
2518     {
2519         $start = '=?' . $this->CharSet . '?B?';
2520         $end = '?=';
2521         $encoded = '';
2522         if ($linebreak === null) {
2523             $linebreak = $this->LE;
2524         }
2525
2526         $mb_length = mb_strlen($str, $this->CharSet);
2527         // Each line must have length <= 75, including $start and $end
2528         $length = 75 - strlen($start) - strlen($end);
2529         // Average multi-byte ratio
2530         $ratio = $mb_length / strlen($str);
2531         // Base64 has a 4:3 ratio
2532         $avgLength = floor($length * $ratio * .75);
2533
2534         for ($i = 0; $i < $mb_length; $i += $offset) {
2535             $lookBack = 0;
2536             do {
2537                 $offset = $avgLength - $lookBack;
2538                 $chunk = mb_substr($str, $i, $offset, $this->CharSet);
2539                 $chunk = base64_encode($chunk);
2540                 $lookBack++;
2541             } while (strlen($chunk) > $length);
2542             $encoded .= $chunk . $linebreak;
2543         }
2544
2545         // Chomp the last linefeed
2546         $encoded = substr($encoded, 0, -strlen($linebreak));
2547         return $encoded;
2548     }
2549
2550     /**
2551      * Encode a string in quoted-printable format.
2552      * According to RFC2045 section 6.7.
2553      * @access public
2554      * @param string $string The text to encode
2555      * @param integer $line_max Number of chars allowed on a line before wrapping
2556      * @return string
2557      * @link http://www.php.net/manual/en/function.quoted-printable-decode.php#89417 Adapted from this comment
2558      */
2559     public function encodeQP($string, $line_max = 76)
2560     {
2561         // Use native function if it's available (>= PHP5.3)
2562         if (function_exists('quoted_printable_encode')) {
2563             return $this->fixEOL(quoted_printable_encode($string));
2564         }
2565         // Fall back to a pure PHP implementation
2566         $string = str_replace(
2567             array('%20', '%0D%0A.', '%0D%0A', '%'),
2568             array(' ', "\r\n=2E", "\r\n", '='),
2569             rawurlencode($string)
2570         );
2571         $string = preg_replace('/[^\r\n]{' . ($line_max - 3) . '}[^=\r\n]{2}/', "$0=\r\n", $string);
2572         return $this->fixEOL($string);
2573     }
2574
2575     /**
2576      * Backward compatibility wrapper for an old QP encoding function that was removed.
2577      * @see PHPMailer::encodeQP()
2578      * @access public
2579      * @param string $string
2580      * @param integer $line_max
2581      * @param boolean $space_conv
2582      * @return string
2583      * @deprecated Use encodeQP instead.
2584      */
2585     public function encodeQPphp(
2586         $string,
2587         $line_max = 76,
2588         /** @noinspection PhpUnusedParameterInspection */ $space_conv = false
2589     ) {
2590         return $this->encodeQP($string, $line_max);
2591     }
2592
2593     /**
2594      * Encode a string using Q encoding.
2595      * @link http://tools.ietf.org/html/rfc2047
2596      * @param string $str the text to encode
2597      * @param string $position Where the text is going to be used, see the RFC for what that means
2598      * @access public
2599      * @return string
2600      */
2601     public function encodeQ($str, $position = 'text')
2602     {
2603         // There should not be any EOL in the string
2604         $pattern = '';
2605         $encoded = str_replace(array("\r", "\n"), '', $str);
2606         switch (strtolower($position)) {
2607             case 'phrase':
2608                 // RFC 2047 section 5.3
2609                 $pattern = '^A-Za-z0-9!*+\/ -';
2610                 break;
2611             /** @noinspection PhpMissingBreakStatementInspection */
2612             case 'comment':
2613                 // RFC 2047 section 5.2
2614                 $pattern = '\(\)"';
2615                 // intentional fall-through
2616                 // for this reason we build the $pattern without including delimiters and []
2617             case 'text':
2618             default:
2619                 // RFC 2047 section 5.1
2620                 // Replace every high ascii, control, =, ? and _ characters
2621                 $pattern = '\000-\011\013\014\016-\037\075\077\137\177-\377' . $pattern;
2622                 break;
2623         }
2624         $matches = array();
2625         if (preg_match_all("/[{$pattern}]/", $encoded, $matches)) {
2626             // If the string contains an '=', make sure it's the first thing we replace
2627             // so as to avoid double-encoding
2628             $eqkey = array_search('=', $matches[0]);
2629             if (false !== $eqkey) {
2630                 unset($matches[0][$eqkey]);
2631                 array_unshift($matches[0], '=');
2632             }
2633             foreach (array_unique($matches[0]) as $char) {
2634                 $encoded = str_replace($char, '=' . sprintf('%02X', ord($char)), $encoded);
2635             }
2636         }
2637         // Replace every spaces to _ (more readable than =20)
2638         return str_replace(' ', '_', $encoded);
2639     }
2640
2641
2642     /**
2643      * Add a string or binary attachment (non-filesystem).
2644      * This method can be used to attach ascii or binary data,
2645      * such as a BLOB record from a database.
2646      * @param string $string String attachment data.
2647      * @param string $filename Name of the attachment.
2648      * @param string $encoding File encoding (see $Encoding).
2649      * @param string $type File extension (MIME) type.
2650      * @param string $disposition Disposition to use
2651      * @return void
2652      */
2653     public function addStringAttachment(
2654         $string,
2655         $filename,
2656         $encoding = 'base64',
2657         $type = '',
2658         $disposition = 'attachment'
2659     ) {
2660         // If a MIME type is not specified, try to work it out from the file name
2661         if ($type == '') {
2662             $type = self::filenameToType($filename);
2663         }
2664         // Append to $attachment array
2665         $this->attachment[] = array(
2666             0 => $string,
2667             1 => $filename,
2668             2 => basename($filename),
2669             3 => $encoding,
2670             4 => $type,
2671             5 => true, // isStringAttachment
2672             6 => $disposition,
2673             7 => 0
2674         );
2675     }
2676
2677     /**
2678      * Add an embedded (inline) attachment from a file.
2679      * This can include images, sounds, and just about any other document type.
2680      * These differ from 'regular' attachments in that they are intended to be
2681      * displayed inline with the message, not just attached for download.
2682      * This is used in HTML messages that embed the images
2683      * the HTML refers to using the $cid value.
2684      * @param string $path Path to the attachment.
2685      * @param string $cid Content ID of the attachment; Use this to reference
2686      *        the content when using an embedded image in HTML.
2687      * @param string $name Overrides the attachment name.
2688      * @param string $encoding File encoding (see $Encoding).
2689      * @param string $type File MIME type.
2690      * @param string $disposition Disposition to use
2691      * @return boolean True on successfully adding an attachment
2692      */
2693     public function addEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = '', $disposition = 'inline')
2694     {
2695         if (!@is_file($path)) {
2696             $this->setError($this->lang('file_access') . $path);
2697             return false;
2698         }
2699
2700         // If a MIME type is not specified, try to work it out from the file name
2701         if ($type == '') {
2702             $type = self::filenameToType($path);
2703         }
2704
2705         $filename = basename($path);
2706         if ($name == '') {
2707             $name = $filename;
2708         }
2709
2710         // Append to $attachment array
2711         $this->attachment[] = array(
2712             0 => $path,
2713             1 => $filename,
2714             2 => $name,
2715             3 => $encoding,
2716             4 => $type,
2717             5 => false, // isStringAttachment
2718             6 => $disposition,
2719             7 => $cid
2720         );
2721         return true;
2722     }
2723
2724     /**
2725      * Add an embedded stringified attachment.
2726      * This can include images, sounds, and just about any other document type.
2727      * Be sure to set the $type to an image type for images:
2728      * JPEG images use 'image/jpeg', GIF uses 'image/gif', PNG uses 'image/png'.
2729      * @param string $string The attachment binary data.
2730      * @param string $cid Content ID of the attachment; Use this to reference
2731      *        the content when using an embedded image in HTML.
2732      * @param string $name
2733      * @param string $encoding File encoding (see $Encoding).
2734      * @param string $type MIME type.
2735      * @param string $disposition Disposition to use
2736      * @return boolean True on successfully adding an attachment
2737      */
2738     public function addStringEmbeddedImage(
2739         $string,
2740         $cid,
2741         $name = '',
2742         $encoding = 'base64',
2743         $type = '',
2744         $disposition = 'inline'
2745     ) {
2746         // If a MIME type is not specified, try to work it out from the name
2747         if ($type == '') {
2748             $type = self::filenameToType($name);
2749         }
2750
2751         // Append to $attachment array
2752         $this->attachment[] = array(
2753             0 => $string,
2754             1 => $name,
2755             2 => $name,
2756             3 => $encoding,
2757             4 => $type,
2758             5 => true, // isStringAttachment
2759             6 => $disposition,
2760             7 => $cid
2761         );
2762         return true;
2763     }
2764
2765     /**
2766      * Check if an inline attachment is present.
2767      * @access public
2768      * @return boolean
2769      */
2770     public function inlineImageExists()
2771     {
2772         foreach ($this->attachment as $attachment) {
2773             if ($attachment[6] == 'inline') {
2774                 return true;
2775             }
2776         }
2777         return false;
2778     }
2779
2780     /**
2781      * Check if an attachment (non-inline) is present.
2782      * @return boolean
2783      */
2784     public function attachmentExists()
2785     {
2786         foreach ($this->attachment as $attachment) {
2787             if ($attachment[6] == 'attachment') {
2788                 return true;
2789             }
2790         }
2791         return false;
2792     }
2793
2794     /**
2795      * Check if this message has an alternative body set.
2796      * @return boolean
2797      */
2798     public function alternativeExists()
2799     {
2800         return !empty($this->AltBody);
2801     }
2802
2803     /**
2804      * Clear all To recipients.
2805      * @return void
2806      */
2807     public function clearAddresses()
2808     {
2809         foreach ($this->to as $to) {
2810             unset($this->all_recipients[strtolower($to[0])]);
2811         }
2812         $this->to = array();
2813     }
2814
2815     /**
2816      * Clear all CC recipients.
2817      * @return void
2818      */
2819     public function clearCCs()
2820     {
2821         foreach ($this->cc as $cc) {
2822             unset($this->all_recipients[strtolower($cc[0])]);
2823         }
2824         $this->cc = array();
2825     }
2826
2827     /**
2828      * Clear all BCC recipients.
2829      * @return void
2830      */
2831     public function clearBCCs()
2832     {
2833         foreach ($this->bcc as $bcc) {
2834             unset($this->all_recipients[strtolower($bcc[0])]);
2835         }
2836         $this->bcc = array();
2837     }
2838
2839     /**
2840      * Clear all ReplyTo recipients.
2841      * @return void
2842      */
2843     public function clearReplyTos()
2844     {
2845         $this->ReplyTo = array();
2846     }
2847
2848     /**
2849      * Clear all recipient types.
2850      * @return void
2851      */
2852     public function clearAllRecipients()
2853     {
2854         $this->to = array();
2855         $this->cc = array();
2856         $this->bcc = array();
2857         $this->all_recipients = array();
2858     }
2859
2860     /**
2861      * Clear all filesystem, string, and binary attachments.
2862      * @return void
2863      */
2864     public function clearAttachments()
2865     {
2866         $this->attachment = array();
2867     }
2868
2869     /**
2870      * Clear all custom headers.
2871      * @return void
2872      */
2873     public function clearCustomHeaders()
2874     {
2875         $this->CustomHeader = array();
2876     }
2877
2878     /**
2879      * Add an error message to the error container.
2880      * @access protected
2881      * @param string $msg
2882      * @return void
2883      */
2884     protected function setError($msg)
2885     {
2886         $this->error_count++;
2887         if ($this->Mailer == 'smtp' and !is_null($this->smtp)) {
2888             $lasterror = $this->smtp->getError();
2889             if (!empty($lasterror['error'])) {
2890                 $msg .= $this->lang('smtp_error') . $lasterror['error'];
2891                 if (!empty($lasterror['detail'])) {
2892                     $msg .= ' Detail: '. $lasterror['detail'];
2893                 }
2894                 if (!empty($lasterror['smtp_code'])) {
2895                     $msg .= ' SMTP code: ' . $lasterror['smtp_code'];
2896                 }
2897                 if (!empty($lasterror['smtp_code_ex'])) {
2898                     $msg .= ' Additional SMTP info: ' . $lasterror['smtp_code_ex'];
2899                 }
2900             }
2901         }
2902         $this->ErrorInfo = $msg;
2903     }
2904
2905     /**
2906      * Return an RFC 822 formatted date.
2907      * @access public
2908      * @return string
2909      * @static
2910      */
2911     public static function rfcDate()
2912     {
2913         // Set the time zone to whatever the default is to avoid 500 errors
2914         // Will default to UTC if it's not set properly in php.ini
2915         date_default_timezone_set(@date_default_timezone_get());
2916         return date('D, j M Y H:i:s O');
2917     }
2918
2919     /**
2920      * Get the server hostname.
2921      * Returns 'localhost.localdomain' if unknown.
2922      * @access protected
2923      * @return string
2924      */
2925     protected function serverHostname()
2926     {
2927         $result = 'localhost.localdomain';
2928         if (!empty($this->Hostname)) {
2929             $result = $this->Hostname;
2930         } elseif (isset($_SERVER) and array_key_exists('SERVER_NAME', $_SERVER) and !empty($_SERVER['SERVER_NAME'])) {
2931             $result = $_SERVER['SERVER_NAME'];
2932         } elseif (function_exists('gethostname') && gethostname() !== false) {
2933             $result = gethostname();
2934         } elseif (php_uname('n') !== false) {
2935             $result = php_uname('n');
2936         }
2937         return $result;
2938     }
2939
2940     /**
2941      * Get an error message in the current language.
2942      * @access protected
2943      * @param string $key
2944      * @return string
2945      */
2946     protected function lang($key)
2947     {
2948         if (count($this->language) < 1) {
2949             $this->setLanguage('en'); // set the default language
2950         }
2951
2952         if (array_key_exists($key, $this->language)) {
2953             if ($key == 'smtp_connect_failed') {
2954                 //Include a link to troubleshooting docs on SMTP connection failure
2955                 //this is by far the biggest cause of support questions
2956                 //but it's usually not PHPMailer's fault.
2957                 return $this->language[$key] . ' https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting';
2958             }
2959             return $this->language[$key];
2960         } else {
2961             //Return the key as a fallback
2962             return $key;
2963         }
2964     }
2965
2966     /**
2967      * Check if an error occurred.
2968      * @access public
2969      * @return boolean True if an error did occur.
2970      */
2971     public function isError()
2972     {
2973         return ($this->error_count > 0);
2974     }
2975
2976     /**
2977      * Ensure consistent line endings in a string.
2978      * Changes every end of line from CRLF, CR or LF to $this->LE.
2979      * @access public
2980      * @param string $str String to fixEOL
2981      * @return string
2982      */
2983     public function fixEOL($str)
2984     {
2985         // Normalise to \n
2986         $nstr = str_replace(array("\r\n", "\r"), "\n", $str);
2987         // Now convert LE as needed
2988         if ($this->LE !== "\n") {
2989             $nstr = str_replace("\n", $this->LE, $nstr);
2990         }
2991         return $nstr;
2992     }
2993
2994     /**
2995      * Add a custom header.
2996      * $name value can be overloaded to contain
2997      * both header name and value (name:value)
2998      * @access public
2999      * @param string $name Custom header name
3000      * @param string $value Header value
3001      * @return void
3002      */
3003     public function addCustomHeader($name, $value = null)
3004     {
3005         if ($value === null) {
3006             // Value passed in as name:value
3007             $this->CustomHeader[] = explode(':', $name, 2);
3008         } else {
3009             $this->CustomHeader[] = array($name, $value);
3010         }
3011     }
3012
3013     /**
3014      * Returns all custom headers
3015      *
3016      * @return array
3017      */
3018     public function getCustomHeaders()
3019     {
3020         return $this->CustomHeader;
3021     }
3022
3023     /**
3024      * Create a message from an HTML string.
3025      * Automatically makes modifications for inline images and backgrounds
3026      * and creates a plain-text version by converting the HTML.
3027      * Overwrites any existing values in $this->Body and $this->AltBody
3028      * @access public
3029      * @param string $message HTML message string
3030      * @param string $basedir baseline directory for path
3031      * @param boolean|callable $advanced Whether to use the internal HTML to text converter
3032      *    or your own custom converter @see html2text()
3033      * @return string $message
3034      */
3035     public function msgHTML($message, $basedir = '', $advanced = false)
3036     {
3037         preg_match_all('/(src|background)=["\'](.*)["\']/Ui', $message, $images);
3038         if (isset($images[2])) {
3039             foreach ($images[2] as $imgindex => $url) {
3040                 // Convert data URIs into embedded images
3041                 if (preg_match('#^data:(image[^;,]*)(;base64)?,#', $url, $match)) {
3042                     $data = substr($url, strpos($url, ','));
3043                     if ($match[2]) {
3044                         $data = base64_decode($data);
3045                     } else {
3046                         $data = rawurldecode($data);
3047                     }
3048                     $cid = md5($url) . '@phpmailer.0'; // RFC2392 S 2
3049                     if ($this->addStringEmbeddedImage($data, $cid, '', 'base64', $match[1])) {
3050                         $message = str_replace(
3051                             $images[0][$imgindex],
3052                             $images[1][$imgindex] . '="cid:' . $cid . '"',
3053                             $message
3054                         );
3055                     }
3056                 } elseif (!preg_match('#^[A-z]+://#', $url)) {
3057                     // Do not change urls for absolute images (thanks to corvuscorax)
3058                     $filename = basename($url);
3059                     $directory = dirname($url);
3060                     if ($directory == '.') {
3061                         $directory = '';
3062                     }
3063                     $cid = md5($url) . '@phpmailer.0'; // RFC2392 S 2
3064                     if (strlen($basedir) > 1 && substr($basedir, -1) != '/') {
3065                         $basedir .= '/';
3066                     }
3067                     if (strlen($directory) > 1 && substr($directory, -1) != '/') {
3068                         $directory .= '/';
3069                     }
3070                     if ($this->addEmbeddedImage(
3071                         $basedir . $directory . $filename,
3072                         $cid,
3073                         $filename,
3074                         'base64',
3075                         self::_mime_types((string)self::mb_pathinfo($filename, PATHINFO_EXTENSION))
3076                     )
3077                     ) {
3078                         $message = preg_replace(
3079                             '/' . $images[1][$imgindex] . '=["\']' . preg_quote($url, '/') . '["\']/Ui',
3080                             $images[1][$imgindex] . '="cid:' . $cid . '"',
3081                             $message
3082                         );
3083                     }
3084                 }
3085             }
3086         }
3087         $this->isHTML(true);
3088         // Convert all message body line breaks to CRLF, makes quoted-printable encoding work much better
3089         $this->Body = $this->normalizeBreaks($message);
3090         $this->AltBody = $this->normalizeBreaks($this->html2text($message, $advanced));
3091         if (empty($this->AltBody)) {
3092             $this->AltBody = 'To view this email message, open it in a program that understands HTML!' .
3093                 self::CRLF . self::CRLF;
3094         }
3095         return $this->Body;
3096     }
3097
3098     /**
3099      * Convert an HTML string into plain text.
3100      * This is used by msgHTML().
3101      * Note - older versions of this function used a bundled advanced converter
3102      * which was been removed for license reasons in #232
3103      * Example usage:
3104      * <code>
3105      * // Use default conversion
3106      * $plain = $mail->html2text($html);
3107      * // Use your own custom converter
3108      * $plain = $mail->html2text($html, function($html) {
3109      *     $converter = new MyHtml2text($html);
3110      *     return $converter->get_text();
3111      * });
3112      * </code>
3113      * @param string $html The HTML text to convert
3114      * @param boolean|callable $advanced Any boolean value to use the internal converter,
3115      *   or provide your own callable for custom conversion.
3116      * @return string
3117      */
3118     public function html2text($html, $advanced = false)
3119     {
3120         if (is_callable($advanced)) {
3121             return call_user_func($advanced, $html);
3122         }
3123         return html_entity_decode(
3124             trim(strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/\\1>/si', '', $html))),
3125             ENT_QUOTES,
3126             $this->CharSet
3127         );
3128     }
3129
3130     /**
3131      * Get the MIME type for a file extension.
3132      * @param string $ext File extension
3133      * @access public
3134      * @return string MIME type of file.
3135      * @static
3136      */
3137     public static function _mime_types($ext = '')
3138     {
3139         $mimes = array(
3140             'xl'    => 'application/excel',
3141             'js'    => 'application/javascript',
3142             'hqx'   => 'application/mac-binhex40',
3143             'cpt'   => 'application/mac-compactpro',
3144             'bin'   => 'application/macbinary',
3145             'doc'   => 'application/msword',
3146             'word'  => 'application/msword',
3147             'class' => 'application/octet-stream',
3148             'dll'   => 'application/octet-stream',
3149             'dms'   => 'application/octet-stream',
3150             'exe'   => 'application/octet-stream',
3151             'lha'   => 'application/octet-stream',
3152             'lzh'   => 'application/octet-stream',
3153             'psd'   => 'application/octet-stream',
3154             'sea'   => 'application/octet-stream',
3155             'so'    => 'application/octet-stream',
3156             'oda'   => 'application/oda',
3157             'pdf'   => 'application/pdf',
3158             'ai'    => 'application/postscript',
3159             'eps'   => 'application/postscript',
3160             'ps'    => 'application/postscript',
3161             'smi'   => 'application/smil',
3162             'smil'  => 'application/smil',
3163             'mif'   => 'application/vnd.mif',
3164             'xls'   => 'application/vnd.ms-excel',
3165             'ppt'   => 'application/vnd.ms-powerpoint',
3166             'wbxml' => 'application/vnd.wap.wbxml',
3167             'wmlc'  => 'application/vnd.wap.wmlc',
3168             'dcr'   => 'application/x-director',
3169             'dir'   => 'application/x-director',
3170             'dxr'   => 'application/x-director',
3171             'dvi'   => 'application/x-dvi',
3172             'gtar'  => 'application/x-gtar',
3173             'php3'  => 'application/x-httpd-php',
3174             'php4'  => 'application/x-httpd-php',
3175             'php'   => 'application/x-httpd-php',
3176             'phtml' => 'application/x-httpd-php',
3177             'phps'  => 'application/x-httpd-php-source',
3178             'swf'   => 'application/x-shockwave-flash',
3179             'sit'   => 'application/x-stuffit',
3180             'tar'   => 'application/x-tar',
3181             'tgz'   => 'application/x-tar',
3182             'xht'   => 'application/xhtml+xml',
3183             'xhtml' => 'application/xhtml+xml',
3184             'zip'   => 'application/zip',
3185             'mid'   => 'audio/midi',
3186             'midi'  => 'audio/midi',
3187             'mp2'   => 'audio/mpeg',
3188             'mp3'   => 'audio/mpeg',
3189             'mpga'  => 'audio/mpeg',
3190             'aif'   => 'audio/x-aiff',
3191             'aifc'  => 'audio/x-aiff',
3192             'aiff'  => 'audio/x-aiff',
3193             'ram'   => 'audio/x-pn-realaudio',
3194             'rm'    => 'audio/x-pn-realaudio',
3195             'rpm'   => 'audio/x-pn-realaudio-plugin',
3196             'ra'    => 'audio/x-realaudio',
3197             'wav'   => 'audio/x-wav',
3198             'bmp'   => 'image/bmp',
3199             'gif'   => 'image/gif',
3200             'jpeg'  => 'image/jpeg',
3201             'jpe'   => 'image/jpeg',
3202             'jpg'   => 'image/jpeg',
3203             'png'   => 'image/png',
3204             'tiff'  => 'image/tiff',
3205             'tif'   => 'image/tiff',
3206             'eml'   => 'message/rfc822',
3207             'css'   => 'text/css',
3208             'html'  => 'text/html',
3209             'htm'   => 'text/html',
3210             'shtml' => 'text/html',
3211             'log'   => 'text/plain',
3212             'text'  => 'text/plain',
3213             'txt'   => 'text/plain',
3214             'rtx'   => 'text/richtext',
3215             'rtf'   => 'text/rtf',
3216             'vcf'   => 'text/vcard',
3217             'vcard' => 'text/vcard',
3218             'xml'   => 'text/xml',
3219             'xsl'   => 'text/xml',
3220             'mpeg'  => 'video/mpeg',
3221             'mpe'   => 'video/mpeg',
3222             'mpg'   => 'video/mpeg',
3223             'mov'   => 'video/quicktime',
3224             'qt'    => 'video/quicktime',
3225             'rv'    => 'video/vnd.rn-realvideo',
3226             'avi'   => 'video/x-msvideo',
3227             'movie' => 'video/x-sgi-movie'
3228         );
3229         if (array_key_exists(strtolower($ext), $mimes)) {
3230             return $mimes[strtolower($ext)];
3231         }
3232         return 'application/octet-stream';
3233     }
3234
3235     /**
3236      * Map a file name to a MIME type.
3237      * Defaults to 'application/octet-stream', i.e.. arbitrary binary data.
3238      * @param string $filename A file name or full path, does not need to exist as a file
3239      * @return string
3240      * @static
3241      */
3242     public static function filenameToType($filename)
3243     {
3244         // In case the path is a URL, strip any query string before getting extension
3245         $qpos = strpos($filename, '?');
3246         if (false !== $qpos) {
3247             $filename = substr($filename, 0, $qpos);
3248         }
3249         $pathinfo = self::mb_pathinfo($filename);
3250         return self::_mime_types($pathinfo['extension']);
3251     }
3252
3253     /**
3254      * Multi-byte-safe pathinfo replacement.
3255      * Drop-in replacement for pathinfo(), but multibyte-safe, cross-platform-safe, old-version-safe.
3256      * Works similarly to the one in PHP >= 5.2.0
3257      * @link http://www.php.net/manual/en/function.pathinfo.php#107461
3258      * @param string $path A filename or path, does not need to exist as a file
3259      * @param integer|string $options Either a PATHINFO_* constant,
3260      *      or a string name to return only the specified piece, allows 'filename' to work on PHP < 5.2
3261      * @return string|array
3262      * @static
3263      */
3264     public static function mb_pathinfo($path, $options = null)
3265     {
3266         $ret = array('dirname' => '', 'basename' => '', 'extension' => '', 'filename' => '');
3267         $pathinfo = array();
3268         if (preg_match('%^(.*?)[\\\\/]*(([^/\\\\]*?)(\.([^\.\\\\/]+?)|))[\\\\/\.]*$%im', $path, $pathinfo)) {
3269             if (array_key_exists(1, $pathinfo)) {
3270                 $ret['dirname'] = $pathinfo[1];
3271             }
3272             if (array_key_exists(2, $pathinfo)) {
3273                 $ret['basename'] = $pathinfo[2];
3274             }
3275             if (array_key_exists(5, $pathinfo)) {
3276                 $ret['extension'] = $pathinfo[5];
3277             }
3278             if (array_key_exists(3, $pathinfo)) {
3279                 $ret['filename'] = $pathinfo[3];
3280             }
3281         }
3282         switch ($options) {
3283             case PATHINFO_DIRNAME:
3284             case 'dirname':
3285                 return $ret['dirname'];
3286             case PATHINFO_BASENAME:
3287             case 'basename':
3288                 return $ret['basename'];
3289             case PATHINFO_EXTENSION:
3290             case 'extension':
3291                 return $ret['extension'];
3292             case PATHINFO_FILENAME:
3293             case 'filename':
3294                 return $ret['filename'];
3295             default:
3296                 return $ret;
3297         }
3298     }
3299
3300     /**
3301      * Set or reset instance properties.
3302      * You should avoid this function - it's more verbose, less efficient, more error-prone and
3303      * harder to debug than setting properties directly.
3304      * Usage Example:
3305      * `$mail->set('SMTPSecure', 'tls');`
3306      *   is the same as:
3307      * `$mail->SMTPSecure = 'tls';`
3308      * @access public
3309      * @param string $name The property name to set
3310      * @param mixed $value The value to set the property to
3311      * @return boolean
3312      * @TODO Should this not be using the __set() magic function?
3313      */
3314     public function set($name, $value = '')
3315     {
3316         if (property_exists($this, $name)) {
3317             $this->$name = $value;
3318             return true;
3319         } else {
3320             $this->setError($this->lang('variable_set') . $name);
3321             return false;
3322         }
3323     }
3324
3325     /**
3326      * Strip newlines to prevent header injection.
3327      * @access public
3328      * @param string $str
3329      * @return string
3330      */
3331     public function secureHeader($str)
3332     {
3333         return trim(str_replace(array("\r", "\n"), '', $str));
3334     }
3335
3336     /**
3337      * Normalize line breaks in a string.
3338      * Converts UNIX LF, Mac CR and Windows CRLF line breaks into a single line break format.
3339      * Defaults to CRLF (for message bodies) and preserves consecutive breaks.
3340      * @param string $text
3341      * @param string $breaktype What kind of line break to use, defaults to CRLF
3342      * @return string
3343      * @access public
3344      * @static
3345      */
3346     public static function normalizeBreaks($text, $breaktype = "\r\n")
3347     {
3348         return preg_replace('/(\r\n|\r|\n)/ms', $breaktype, $text);
3349     }
3350
3351
3352     /**
3353      * Set the public and private key files and password for S/MIME signing.
3354      * @access public
3355      * @param string $cert_filename
3356      * @param string $key_filename
3357      * @param string $key_pass Password for private key
3358      * @param string $extracerts_filename Optional path to chain certificate
3359      */
3360     public function sign($cert_filename, $key_filename, $key_pass, $extracerts_filename = '')
3361     {
3362         $this->sign_cert_file = $cert_filename;
3363         $this->sign_key_file = $key_filename;
3364         $this->sign_key_pass = $key_pass;
3365         $this->sign_extracerts_file = $extracerts_filename;
3366     }
3367
3368     /**
3369      * Quoted-Printable-encode a DKIM header.
3370      * @access public
3371      * @param string $txt
3372      * @return string
3373      */
3374     public function DKIM_QP($txt)
3375     {
3376         $line = '';
3377         for ($i = 0; $i < strlen($txt); $i++) {
3378             $ord = ord($txt[$i]);
3379             if (((0x21 <= $ord) && ($ord <= 0x3A)) || $ord == 0x3C || ((0x3E <= $ord) && ($ord <= 0x7E))) {
3380                 $line .= $txt[$i];
3381             } else {
3382                 $line .= '=' . sprintf('%02X', $ord);
3383             }
3384         }
3385         return $line;
3386     }
3387
3388     /**
3389      * Generate a DKIM signature.
3390      * @access public
3391      * @param string $signHeader
3392      * @throws phpmailerException
3393      * @return string
3394      */
3395     public function DKIM_Sign($signHeader)
3396     {
3397         if (!defined('PKCS7_TEXT')) {
3398             if ($this->exceptions) {
3399                 throw new phpmailerException($this->lang('extension_missing') . 'openssl');
3400             }
3401             return '';
3402         }
3403         $privKeyStr = file_get_contents($this->DKIM_private);
3404         if ($this->DKIM_passphrase != '') {
3405             $privKey = openssl_pkey_get_private($privKeyStr, $this->DKIM_passphrase);
3406         } else {
3407             $privKey = $privKeyStr;
3408         }
3409         if (openssl_sign($signHeader, $signature, $privKey)) {
3410             return base64_encode($signature);
3411         }
3412         return '';
3413     }
3414
3415     /**
3416      * Generate a DKIM canonicalization header.
3417      * @access public
3418      * @param string $signHeader Header
3419      * @return string
3420      */
3421     public function DKIM_HeaderC($signHeader)
3422     {
3423         $signHeader = preg_replace('/\r\n\s+/', ' ', $signHeader);
3424         $lines = explode("\r\n", $signHeader);
3425         foreach ($lines as $key => $line) {
3426             list($heading, $value) = explode(':', $line, 2);
3427             $heading = strtolower($heading);
3428             $value = preg_replace('/\s+/', ' ', $value); // Compress useless spaces
3429             $lines[$key] = $heading . ':' . trim($value); // Don't forget to remove WSP around the value
3430         }
3431         $signHeader = implode("\r\n", $lines);
3432         return $signHeader;
3433     }
3434
3435     /**
3436      * Generate a DKIM canonicalization body.
3437      * @access public
3438      * @param string $body Message Body
3439      * @return string
3440      */
3441     public function DKIM_BodyC($body)
3442     {
3443         if ($body == '') {
3444             return "\r\n";
3445         }
3446         // stabilize line endings
3447         $body = str_replace("\r\n", "\n", $body);
3448         $body = str_replace("\n", "\r\n", $body);
3449         // END stabilize line endings
3450         while (substr($body, strlen($body) - 4, 4) == "\r\n\r\n") {
3451             $body = substr($body, 0, strlen($body) - 2);
3452         }
3453         return $body;
3454     }
3455
3456     /**
3457      * Create the DKIM header and body in a new message header.
3458      * @access public
3459      * @param string $headers_line Header lines
3460      * @param string $subject Subject
3461      * @param string $body Body
3462      * @return string
3463      */
3464     public function DKIM_Add($headers_line, $subject, $body)
3465     {
3466         $DKIMsignatureType = 'rsa-sha1'; // Signature & hash algorithms
3467         $DKIMcanonicalization = 'relaxed/simple'; // Canonicalization of header/body
3468         $DKIMquery = 'dns/txt'; // Query method
3469         $DKIMtime = time(); // Signature Timestamp = seconds since 00:00:00 - Jan 1, 1970 (UTC time zone)
3470         $subject_header = "Subject: $subject";
3471         $headers = explode($this->LE, $headers_line);
3472         $from_header = '';
3473         $to_header = '';
3474         $current = '';
3475         foreach ($headers as $header) {
3476             if (strpos($header, 'From:') === 0) {
3477                 $from_header = $header;
3478                 $current = 'from_header';
3479             } elseif (strpos($header, 'To:') === 0) {
3480                 $to_header = $header;
3481                 $current = 'to_header';
3482             } else {
3483                 if (!empty($$current) && strpos($header, ' =?') === 0) {
3484                     $$current .= $header;
3485                 } else {
3486                     $current = '';
3487                 }
3488             }
3489         }
3490         $from = str_replace('|', '=7C', $this->DKIM_QP($from_header));
3491         $to = str_replace('|', '=7C', $this->DKIM_QP($to_header));
3492         $subject = str_replace(
3493             '|',
3494             '=7C',
3495             $this->DKIM_QP($subject_header)
3496         ); // Copied header fields (dkim-quoted-printable)
3497         $body = $this->DKIM_BodyC($body);
3498         $DKIMlen = strlen($body); // Length of body
3499         $DKIMb64 = base64_encode(pack('H*', sha1($body))); // Base64 of packed binary SHA-1 hash of body
3500         if ('' == $this->DKIM_identity) {
3501             $ident = '';
3502         } else {
3503             $ident = ' i=' . $this->DKIM_identity . ';';
3504         }
3505         $dkimhdrs = 'DKIM-Signature: v=1; a=' .
3506             $DKIMsignatureType . '; q=' .
3507             $DKIMquery . '; l=' .
3508             $DKIMlen . '; s=' .
3509             $this->DKIM_selector .
3510             ";\r\n" .
3511             "\tt=" . $DKIMtime . '; c=' . $DKIMcanonicalization . ";\r\n" .
3512             "\th=From:To:Subject;\r\n" .
3513             "\td=" . $this->DKIM_domain . ';' . $ident . "\r\n" .
3514             "\tz=$from\r\n" .
3515             "\t|$to\r\n" .
3516             "\t|$subject;\r\n" .
3517             "\tbh=" . $DKIMb64 . ";\r\n" .
3518             "\tb=";
3519         $toSign = $this->DKIM_HeaderC(
3520             $from_header . "\r\n" . $to_header . "\r\n" . $subject_header . "\r\n" . $dkimhdrs
3521         );
3522         $signed = $this->DKIM_Sign($toSign);
3523         return $dkimhdrs . $signed . "\r\n";
3524     }
3525
3526     /**
3527      * Detect if a string contains a line longer than the maximum line length allowed.
3528      * @param string $str
3529      * @return boolean
3530      * @static
3531      */
3532     public static function hasLineLongerThanMax($str)
3533     {
3534         //+2 to include CRLF line break for a 1000 total
3535         return (boolean)preg_match('/^(.{'.(self::MAX_LINE_LENGTH + 2).',})/m', $str);
3536     }
3537
3538     /**
3539      * Allows for public read access to 'to' property.
3540      * @access public
3541      * @return array
3542      */
3543     public function getToAddresses()
3544     {
3545         return $this->to;
3546     }
3547
3548     /**
3549      * Allows for public read access to 'cc' property.
3550      * @access public
3551      * @return array
3552      */
3553     public function getCcAddresses()
3554     {
3555         return $this->cc;
3556     }
3557
3558     /**
3559      * Allows for public read access to 'bcc' property.
3560      * @access public
3561      * @return array
3562      */
3563     public function getBccAddresses()
3564     {
3565         return $this->bcc;
3566     }
3567
3568     /**
3569      * Allows for public read access to 'ReplyTo' property.
3570      * @access public
3571      * @return array
3572      */
3573     public function getReplyToAddresses()
3574     {
3575         return $this->ReplyTo;
3576     }
3577
3578     /**
3579      * Allows for public read access to 'all_recipients' property.
3580      * @access public
3581      * @return array
3582      */
3583     public function getAllRecipientAddresses()
3584     {
3585         return $this->all_recipients;
3586     }
3587
3588     /**
3589      * Perform a callback.
3590      * @param boolean $isSent
3591      * @param array $to
3592      * @param array $cc
3593      * @param array $bcc
3594      * @param string $subject
3595      * @param string $body
3596      * @param string $from
3597      */
3598     protected function doCallback($isSent, $to, $cc, $bcc, $subject, $body, $from)
3599     {
3600         if (!empty($this->action_function) && is_callable($this->action_function)) {
3601             $params = array($isSent, $to, $cc, $bcc, $subject, $body, $from);
3602             call_user_func_array($this->action_function, $params);
3603         }
3604     }
3605 }
3606
3607 /**
3608  * PHPMailer exception handler
3609  * @package PHPMailer
3610  */
3611 class phpmailerException extends Exception
3612 {
3613     /**
3614      * Prettify error message output
3615      * @return string
3616      */
3617     public function errorMessage()
3618     {
3619         $errorMsg = '<strong>' . $this->getMessage() . "</strong><br />\n";
3620         return $errorMsg;
3621     }
3622 }