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