WordPress.org

Make WordPress Core

Ticket #48467: 48467.diff

File 48467.diff, 200.0 KB (added by finchps, 16 months ago)
  • src/wp-admin/includes/class-wp-filesystem-ssh2.php

     
    99 * Complie libssh2 (Note: Only 0.14 is officaly working with PHP 5.2.6+ right now, But many users have found the latest versions work)
    1010 *
    1111 * cd /usr/src
    12  * wget http://surfnet.dl.sourceforge.net/sourceforge/libssh2/libssh2-0.14.tar.gz
     12 * wget https://www.libssh2.org/download/libssh2-0.14.tar.gz
    1313 * tar -zxvf libssh2-0.14.tar.gz
    1414 * cd libssh2-0.14/
    1515 * ./configure
     
    6565                $this->errors = new WP_Error();
    6666
    6767                //Check if possible to use ssh2 functions.
    68                 if ( ! extension_loaded( 'ssh2' ) ) {
     68                if ( !extension_loaded( 'ssh2' ) ) {
    6969                        $this->errors->add( 'no_ssh2_ext', __( 'The ssh2 PHP extension is not available' ) );
    7070                        return;
    7171                }
    72                 if ( ! function_exists( 'stream_get_contents' ) ) {
     72                if ( !function_exists( 'stream_get_contents' ) ) {
    7373                        $this->errors->add(
    7474                                'ssh2_php_requirement',
    7575                                sprintf(
     
    9595                }
    9696
    9797                // Check if the options provided are OK.
    98                 if ( ! empty( $opt['public_key'] ) && ! empty( $opt['private_key'] ) ) {
     98                if ( !empty( $opt['public_key'] ) && !empty( $opt['private_key'] ) ) {
    9999                        $this->options['public_key']  = $opt['public_key'];
    100100                        $this->options['private_key'] = $opt['private_key'];
    101101
    102                         $this->options['hostkey'] = array( 'hostkey' => 'ssh-rsa' );
     102                        $this->options['hostkey'] = array('hostkey' => 'ssh-rsa');
    103103
    104104                        $this->keys = true;
    105105                } elseif ( empty( $opt['username'] ) ) {
    106106                        $this->errors->add( 'empty_username', __( 'SSH2 username is required' ) );
    107107                }
    108108
    109                 if ( ! empty( $opt['username'] ) ) {
     109                if ( !empty( $opt['username'] ) ) {
    110110                        $this->options['username'] = $opt['username'];
    111111                }
    112112
    113113                if ( empty( $opt['password'] ) ) {
    114114                        // Password can be blank if we are using keys.
    115                         if ( ! $this->keys ) {
     115                        if ( !$this->keys ) {
    116116                                $this->errors->add( 'empty_password', __( 'SSH2 password is required' ) );
    117117                        }
    118118                } else {
     
    128128         * @return bool True on success, false on failure.
    129129         */
    130130        public function connect() {
    131                 if ( ! $this->keys ) {
     131                if ( !$this->keys ) {
    132132                        $this->link = @ssh2_connect( $this->options['hostname'], $this->options['port'] );
    133133                } else {
    134134                        $this->link = @ssh2_connect( $this->options['hostname'], $this->options['port'], $this->options['hostkey'] );
    135135                }
    136136
    137                 if ( ! $this->link ) {
     137                if ( !$this->link ) {
    138138                        $this->errors->add(
    139139                                'connect',
    140140                                sprintf(
     
    146146                        return false;
    147147                }
    148148
    149                 if ( ! $this->keys ) {
    150                         if ( ! @ssh2_auth_password( $this->link, $this->options['username'], $this->options['password'] ) ) {
     149                if ( !$this->keys ) {
     150                        if ( !@ssh2_auth_password( $this->link, $this->options['username'], $this->options['password'] ) ) {
    151151                                $this->errors->add(
    152152                                        'auth',
    153153                                        sprintf(
     
    159159                                return false;
    160160                        }
    161161                } else {
    162                         if ( ! @ssh2_auth_pubkey_file( $this->link, $this->options['username'], $this->options['public_key'], $this->options['private_key'], $this->options['password'] ) ) {
     162                        if ( !@ssh2_auth_pubkey_file( $this->link, $this->options['username'], $this->options['public_key'], $this->options['private_key'], $this->options['password'] ) ) {
    163163                                $this->errors->add(
    164164                                        'auth',
    165165                                        sprintf(
     
    173173                }
    174174
    175175                $this->sftp_link = ssh2_sftp( $this->link );
    176                 if ( ! $this->sftp_link ) {
     176                if ( !$this->sftp_link ) {
    177177                        $this->errors->add(
    178178                                'connect',
    179179                                sprintf(
     
    217217         *                     is false (default), and data from the resulting stream was retrieved.
    218218         */
    219219        public function run_command( $command, $returnbool = false ) {
    220                 if ( ! $this->link ) {
     220                if ( !$this->link ) {
    221221                        return false;
    222222                }
    223223
    224224                $stream = ssh2_exec( $this->link, $command );
    225                 if ( ! $stream ) {
     225                if ( !$stream ) {
    226226                        $this->errors->add(
    227227                                'command',
    228228                                sprintf(
     
    333333         * @return bool True on success, false on failure.
    334334         */
    335335        public function chgrp( $file, $group, $recursive = false ) {
    336                 if ( ! $this->exists( $file ) ) {
     336                if ( !$this->exists( $file ) ) {
    337337                        return false;
    338338                }
    339                 if ( ! $recursive || ! $this->is_dir( $file ) ) {
     339                if ( !$recursive || !$this->is_dir( $file ) ) {
    340340                        return $this->run_command( sprintf( 'chgrp %s %s', escapeshellarg( $group ), escapeshellarg( $file ) ), true );
    341341                }
    342342                return $this->run_command( sprintf( 'chgrp -R %s %s', escapeshellarg( $group ), escapeshellarg( $file ) ), true );
     
    355355         * @return bool True on success, false on failure.
    356356         */
    357357        public function chmod( $file, $mode = false, $recursive = false ) {
    358                 if ( ! $this->exists( $file ) ) {
     358                if ( !$this->exists( $file ) ) {
    359359                        return false;
    360360                }
    361361
    362                 if ( ! $mode ) {
     362                if ( !$mode ) {
    363363                        if ( $this->is_file( $file ) ) {
    364364                                $mode = FS_CHMOD_FILE;
    365365                        } elseif ( $this->is_dir( $file ) ) {
     
    369369                        }
    370370                }
    371371
    372                 if ( ! $recursive || ! $this->is_dir( $file ) ) {
     372                if ( !$recursive || !$this->is_dir( $file ) ) {
    373373                        return $this->run_command( sprintf( 'chmod %o %s', $mode, escapeshellarg( $file ) ), true );
    374374                }
    375375                return $this->run_command( sprintf( 'chmod -R %o %s', $mode, escapeshellarg( $file ) ), true );
     
    387387         * @return bool True on success, false on failure.
    388388         */
    389389        public function chown( $file, $owner, $recursive = false ) {
    390                 if ( ! $this->exists( $file ) ) {
     390                if ( !$this->exists( $file ) ) {
    391391                        return false;
    392392                }
    393                 if ( ! $recursive || ! $this->is_dir( $file ) ) {
     393                if ( !$recursive || !$this->is_dir( $file ) ) {
    394394                        return $this->run_command( sprintf( 'chown %s %s', escapeshellarg( $owner ), escapeshellarg( $file ) ), true );
    395395                }
    396396                return $this->run_command( sprintf( 'chown -R %s %s', escapeshellarg( $owner ), escapeshellarg( $file ) ), true );
     
    406406         */
    407407        public function owner( $file ) {
    408408                $owneruid = @fileowner( $this->sftp_path( $file ) );
    409                 if ( ! $owneruid ) {
     409                if ( !$owneruid ) {
    410410                        return false;
    411411                }
    412                 if ( ! function_exists( 'posix_getpwuid' ) ) {
     412                if ( !function_exists( 'posix_getpwuid' ) ) {
    413413                        return $owneruid;
    414414                }
    415415                $ownerarray = posix_getpwuid( $owneruid );
     
    438438         */
    439439        public function group( $file ) {
    440440                $gid = @filegroup( $this->sftp_path( $file ) );
    441                 if ( ! $gid ) {
     441                if ( !$gid ) {
    442442                        return false;
    443443                }
    444                 if ( ! function_exists( 'posix_getgrgid' ) ) {
     444                if ( !function_exists( 'posix_getgrgid' ) ) {
    445445                        return $gid;
    446446                }
    447447                $grouparray = posix_getgrgid( $gid );
     
    462462         * @return bool True on success, false on failure.
    463463         */
    464464        public function copy( $source, $destination, $overwrite = false, $mode = false ) {
    465                 if ( ! $overwrite && $this->exists( $destination ) ) {
     465                if ( !$overwrite && $this->exists( $destination ) ) {
    466466                        return false;
    467467                }
    468468                $content = $this->get_contents( $source );
     
    513513                if ( 'f' == $type || $this->is_file( $file ) ) {
    514514                        return ssh2_sftp_unlink( $this->sftp_link, $file );
    515515                }
    516                 if ( ! $recursive ) {
     516                if ( !$recursive ) {
    517517                        return ssh2_sftp_rmdir( $this->sftp_link, $file );
    518518                }
    519519                $filelist = $this->dirlist( $file );
     
    659659                        return false;
    660660                }
    661661
    662                 if ( ! $chmod ) {
     662                if ( !$chmod ) {
    663663                        $chmod = FS_CHMOD_DIR;
    664664                }
    665                 if ( ! ssh2_sftp_mkdir( $this->sftp_link, $path, $chmod, true ) ) {
     665                if ( !ssh2_sftp_mkdir( $this->sftp_link, $path, $chmod, true ) ) {
    666666                        return false;
    667667                }
    668668                if ( $chown ) {
     
    721721                        $limit_file = false;
    722722                }
    723723
    724                 if ( ! $this->is_dir( $path ) || ! $this->is_readable( $path ) ) {
     724                if ( !$this->is_dir( $path ) || !$this->is_readable( $path ) ) {
    725725                        return false;
    726726                }
    727727
    728728                $ret = array();
    729729                $dir = dir( $this->sftp_path( $path ) );
    730730
    731                 if ( ! $dir ) {
     731                if ( !$dir ) {
    732732                        return false;
    733733                }
    734734
     
    740740                                continue; //Do not care about these folders.
    741741                        }
    742742
    743                         if ( ! $include_hidden && '.' == $struc['name'][0] ) {
     743                        if ( !$include_hidden && '.' == $struc['name'][0] ) {
    744744                                continue;
    745745                        }
    746746
     
    767767                                }
    768768                        }
    769769
    770                         $ret[ $struc['name'] ] = $struc;
     770                        $ret[$struc['name']] = $struc;
    771771                }
    772772                $dir->close();
    773773                unset( $dir );
  • src/wp-includes/class-phpmailer.php

     
    2525 * @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
    2626 * @author Brent R. Matzelle (original founder)
    2727 */
    28 class PHPMailer
    29 {
    30     /**
    31      * The PHPMailer Version number.
    32      * @var string
    33      */
    34     public $Version = '5.2.27';
    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      *   array   $to            email addresses of the recipients
    444      *   array   $cc            cc email addresses
    445      *   array   $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         //Pick an appropriate debug output format automatically
    663         $this->Debugoutput = (strpos(PHP_SAPI, 'cli') !== false ? 'echo' : 'html');
    664     }
    665 
    666     /**
    667      * Destructor.
    668      */
    669     public function __destruct()
    670     {
    671         //Close any open SMTP connection nicely
    672         $this->smtpClose();
    673     }
    674 
    675     /**
    676      * Call mail() in a safe_mode-aware fashion.
    677      * Also, unless sendmail_path points to sendmail (or something that
    678      * claims to be sendmail), don't pass params (not a perfect fix,
    679      * but it will do)
    680      * @param string $to To
    681      * @param string $subject Subject
    682      * @param string $body Message Body
    683      * @param string $header Additional Header(s)
    684      * @param string $params Params
    685      * @access private
    686      * @return boolean
    687      */
    688     private function mailPassthru($to, $subject, $body, $header, $params)
    689     {
    690         //Check overloading of mail function to avoid double-encoding
    691         if (ini_get('mbstring.func_overload') & 1) {
    692             $subject = $this->secureHeader($subject);
    693         } else {
    694             $subject = $this->encodeHeader($this->secureHeader($subject));
    695         }
    696 
    697         //Can't use additional_parameters in safe_mode, calling mail() with null params breaks
    698         //@link http://php.net/manual/en/function.mail.php
    699         if (ini_get('safe_mode') or !$this->UseSendmailOptions or is_null($params)) {
    700             $result = @mail($to, $subject, $body, $header);
    701         } else {
    702             $result = @mail($to, $subject, $body, $header, $params);
    703         }
    704         return $result;
    705     }
    706     /**
    707      * Output debugging info via user-defined method.
    708      * Only generates output if SMTP debug output is enabled (@see SMTP::$do_debug).
    709      * @see PHPMailer::$Debugoutput
    710      * @see PHPMailer::$SMTPDebug
    711      * @param string $str
    712      */
    713     protected function edebug($str)
    714     {
    715         if ($this->SMTPDebug <= 0) {
    716             return;
    717         }
    718         //Avoid clash with built-in function names
    719         if (!in_array($this->Debugoutput, array('error_log', 'html', 'echo')) and is_callable($this->Debugoutput)) {
    720             call_user_func($this->Debugoutput, $str, $this->SMTPDebug);
    721             return;
    722         }
    723         switch ($this->Debugoutput) {
     28class PHPMailer {
     29        /**
     30         * The PHPMailer Version number.
     31         * @var string
     32         */
     33        public $Version = '5.2.27';
     34
     35        /**
     36         * Email priority.
     37         * Options: null (default), 1 = High, 3 = Normal, 5 = low.
     38         * When null, the header is not set at all.
     39         * @var integer
     40         */
     41        public $Priority = null;
     42
     43        /**
     44         * The character set of the message.
     45         * @var string
     46         */
     47        public $CharSet = 'iso-8859-1';
     48
     49        /**
     50         * The MIME Content-type of the message.
     51         * @var string
     52         */
     53        public $ContentType = 'text/plain';
     54
     55        /**
     56         * The message encoding.
     57         * Options: "8bit", "7bit", "binary", "base64", and "quoted-printable".
     58         * @var string
     59         */
     60        public $Encoding = '8bit';
     61
     62        /**
     63         * Holds the most recent mailer error message.
     64         * @var string
     65         */
     66        public $ErrorInfo = '';
     67
     68        /**
     69         * The From email address for the message.
     70         * @var string
     71         */
     72        public $From = 'root@localhost';
     73
     74        /**
     75         * The From name of the message.
     76         * @var string
     77         */
     78        public $FromName = 'Root User';
     79
     80        /**
     81         * The Sender email (Return-Path) of the message.
     82         * If not empty, will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode.
     83         * @var string
     84         */
     85        public $Sender = '';
     86
     87        /**
     88         * The Return-Path of the message.
     89         * If empty, it will be set to either From or Sender.
     90         * @var string
     91         * @deprecated Email senders should never set a return-path header;
     92         * it's the receiver's job (RFC5321 section 4.4), so this no longer does anything.
     93         * @link https://tools.ietf.org/html/rfc5321#section-4.4 RFC5321 reference
     94         */
     95        public $ReturnPath = '';
     96
     97        /**
     98         * The Subject of the message.
     99         * @var string
     100         */
     101        public $Subject = '';
     102
     103        /**
     104         * An HTML or plain text message body.
     105         * If HTML then call isHTML(true).
     106         * @var string
     107         */
     108        public $Body = '';
     109
     110        /**
     111         * The plain-text message body.
     112         * This body can be read by mail clients that do not have HTML email
     113         * capability such as mutt & Eudora.
     114         * Clients that can read HTML will view the normal Body.
     115         * @var string
     116         */
     117        public $AltBody = '';
     118
     119        /**
     120         * An iCal message part body.
     121         * Only supported in simple alt or alt_inline message types
     122         * To generate iCal events, use the bundled extras/EasyPeasyICS.php class or iCalcreator
     123         * @link http://www.bradym.net/php/creating-icalendar-ics-files-with-php.html
     124         * @link http://kigkonsult.se/iCalcreator/
     125         * @var string
     126         */
     127        public $Ical = '';
     128
     129        /**
     130         * The complete compiled MIME message body.
     131         * @access protected
     132         * @var string
     133         */
     134        protected $MIMEBody = '';
     135
     136        /**
     137         * The complete compiled MIME message headers.
     138         * @var string
     139         * @access protected
     140         */
     141        protected $MIMEHeader = '';
     142
     143        /**
     144         * Extra headers that createHeader() doesn't fold in.
     145         * @var string
     146         * @access protected
     147         */
     148        protected $mailHeader = '';
     149
     150        /**
     151         * Word-wrap the message body to this number of chars.
     152         * Set to 0 to not wrap. A useful value here is 78, for RFC2822 section 2.1.1 compliance.
     153         * @var integer
     154         */
     155        public $WordWrap = 0;
     156
     157        /**
     158         * Which method to use to send mail.
     159         * Options: "mail", "sendmail", or "smtp".
     160         * @var string
     161         */
     162        public $Mailer = 'mail';
     163
     164        /**
     165         * The path to the sendmail program.
     166         * @var string
     167         */
     168        public $Sendmail = '/usr/sbin/sendmail';
     169
     170        /**
     171         * Whether mail() uses a fully sendmail-compatible MTA.
     172         * One which supports sendmail's "-oi -f" options.
     173         * @var boolean
     174         */
     175        public $UseSendmailOptions = true;
     176
     177        /**
     178         * Path to PHPMailer plugins.
     179         * Useful if the SMTP class is not in the PHP include path.
     180         * @var string
     181         * @deprecated Should not be needed now there is an autoloader.
     182         */
     183        public $PluginDir = '';
     184
     185        /**
     186         * The email address that a reading confirmation should be sent to, also known as read receipt.
     187         * @var string
     188         */
     189        public $ConfirmReadingTo = '';
     190
     191        /**
     192         * The hostname to use in the Message-ID header and as default HELO string.
     193         * If empty, PHPMailer attempts to find one with, in order,
     194         * $_SERVER['SERVER_NAME'], gethostname(), php_uname('n'), or the value
     195         * 'localhost.localdomain'.
     196         * @var string
     197         */
     198        public $Hostname = '';
     199
     200        /**
     201         * An ID to be used in the Message-ID header.
     202         * If empty, a unique id will be generated.
     203         * You can set your own, but it must be in the format "<id@domain>",
     204         * as defined in RFC5322 section 3.6.4 or it will be ignored.
     205         * @see https://tools.ietf.org/html/rfc5322#section-3.6.4
     206         * @var string
     207         */
     208        public $MessageID = '';
     209
     210        /**
     211         * The message Date to be used in the Date header.
     212         * If empty, the current date will be added.
     213         * @var string
     214         */
     215        public $MessageDate = '';
     216
     217        /**
     218         * SMTP hosts.
     219         * Either a single hostname or multiple semicolon-delimited hostnames.
     220         * You can also specify a different port
     221         * for each host by using this format: [hostname:port]
     222         * (e.g. "smtp1.example.com:25;smtp2.example.com").
     223         * You can also specify encryption type, for example:
     224         * (e.g. "tls://smtp1.example.com:587;ssl://smtp2.example.com:465").
     225         * Hosts will be tried in order.
     226         * @var string
     227         */
     228        public $Host = 'localhost';
     229
     230        /**
     231         * The default SMTP server port.
     232         * @var integer
     233         * @TODO Why is this needed when the SMTP class takes care of it?
     234         */
     235        public $Port = 25;
     236
     237        /**
     238         * The SMTP HELO of the message.
     239         * Default is $Hostname. If $Hostname is empty, PHPMailer attempts to find
     240         * one with the same method described above for $Hostname.
     241         * @var string
     242         * @see PHPMailer::$Hostname
     243         */
     244        public $Helo = '';
     245
     246        /**
     247         * What kind of encryption to use on the SMTP connection.
     248         * Options: '', 'ssl' or 'tls'
     249         * @var string
     250         */
     251        public $SMTPSecure = '';
     252
     253        /**
     254         * Whether to enable TLS encryption automatically if a server supports it,
     255         * even if `SMTPSecure` is not set to 'tls'.
     256         * Be aware that in PHP >= 5.6 this requires that the server's certificates are valid.
     257         * @var boolean
     258         */
     259        public $SMTPAutoTLS = true;
     260
     261        /**
     262         * Whether to use SMTP authentication.
     263         * Uses the Username and Password properties.
     264         * @var boolean
     265         * @see PHPMailer::$Username
     266         * @see PHPMailer::$Password
     267         */
     268        public $SMTPAuth = false;
     269
     270        /**
     271         * Options array passed to stream_context_create when connecting via SMTP.
     272         * @var array
     273         */
     274        public $SMTPOptions = array();
     275
     276        /**
     277         * SMTP username.
     278         * @var string
     279         */
     280        public $Username = '';
     281
     282        /**
     283         * SMTP password.
     284         * @var string
     285         */
     286        public $Password = '';
     287
     288        /**
     289         * SMTP auth type.
     290         * Options are CRAM-MD5, LOGIN, PLAIN, attempted in that order if not specified
     291         * @var string
     292         */
     293        public $AuthType = '';
     294
     295        /**
     296         * SMTP realm.
     297         * Used for NTLM auth
     298         * @var string
     299         */
     300        public $Realm = '';
     301
     302        /**
     303         * SMTP workstation.
     304         * Used for NTLM auth
     305         * @var string
     306         */
     307        public $Workstation = '';
     308
     309        /**
     310         * The SMTP server timeout in seconds.
     311         * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2
     312         * @var integer
     313         */
     314        public $Timeout = 300;
     315
     316        /**
     317         * SMTP class debug output mode.
     318         * Debug output level.
     319         * Options:
     320         * * `0` No output
     321         * * `1` Commands
     322         * * `2` Data and commands
     323         * * `3` As 2 plus connection status
     324         * * `4` Low-level data output
     325         * @var integer
     326         * @see SMTP::$do_debug
     327         */
     328        public $SMTPDebug = 0;
     329
     330        /**
     331         * How to handle debug output.
     332         * Options:
     333         * * `echo` Output plain-text as-is, appropriate for CLI
     334         * * `html` Output escaped, line breaks converted to `<br>`, appropriate for browser output
     335         * * `error_log` Output to error log as configured in php.ini
     336         *
     337         * Alternatively, you can provide a callable expecting two params: a message string and the debug level:
     338         * <code>
     339         * $mail->Debugoutput = function($str, $level) {echo "debug level $level; message: $str";};
     340         * </code>
     341         * @var string|callable
     342         * @see SMTP::$Debugoutput
     343         */
     344        public $Debugoutput = 'echo';
     345
     346        /**
     347         * Whether to keep SMTP connection open after each message.
     348         * If this is set to true then to close the connection
     349         * requires an explicit call to smtpClose().
     350         * @var boolean
     351         */
     352        public $SMTPKeepAlive = false;
     353
     354        /**
     355         * Whether to split multiple to addresses into multiple messages
     356         * or send them all in one message.
     357         * Only supported in `mail` and `sendmail` transports, not in SMTP.
     358         * @var boolean
     359         */
     360        public $SingleTo = false;
     361
     362        /**
     363         * Storage for addresses when SingleTo is enabled.
     364         * @var array
     365         * @TODO This should really not be public
     366         */
     367        public $SingleToArray = array();
     368
     369        /**
     370         * Whether to generate VERP addresses on send.
     371         * Only applicable when sending via SMTP.
     372         * @link https://en.wikipedia.org/wiki/Variable_envelope_return_path
     373         * @link http://www.postfix.org/VERP_README.html Postfix VERP info
     374         * @var boolean
     375         */
     376        public $do_verp = false;
     377
     378        /**
     379         * Whether to allow sending messages with an empty body.
     380         * @var boolean
     381         */
     382        public $AllowEmpty = false;
     383
     384        /**
     385         * The default line ending.
     386         * @note The default remains "\n". We force CRLF where we know
     387         *        it must be used via self::CRLF.
     388         * @var string
     389         */
     390        public $LE = "\n";
     391
     392        /**
     393         * DKIM selector.
     394         * @var string
     395         */
     396        public $DKIM_selector = '';
     397
     398        /**
     399         * DKIM Identity.
     400         * Usually the email address used as the source of the email.
     401         * @var string
     402         */
     403        public $DKIM_identity = '';
     404
     405        /**
     406         * DKIM passphrase.
     407         * Used if your key is encrypted.
     408         * @var string
     409         */
     410        public $DKIM_passphrase = '';
     411
     412        /**
     413         * DKIM signing domain name.
     414         * @example 'example.com'
     415         * @var string
     416         */
     417        public $DKIM_domain = '';
     418
     419        /**
     420         * DKIM private key file path.
     421         * @var string
     422         */
     423        public $DKIM_private = '';
     424
     425        /**
     426         * DKIM private key string.
     427         * If set, takes precedence over `$DKIM_private`.
     428         * @var string
     429         */
     430        public $DKIM_private_string = '';
     431
     432        /**
     433         * Callback Action function name.
     434         *
     435         * The function that handles the result of the send email action.
     436         * It is called out by send() for each email sent.
     437         *
     438         * Value can be any php callable: http://www.php.net/is_callable
     439         *
     440         * Parameters:
     441         *   boolean $result        result of the send action
     442         *   array   $to            email addresses of the recipients
     443         *   array   $cc            cc email addresses
     444         *   array   $bcc           bcc email addresses
     445         *   string  $subject       the subject
     446         *   string  $body          the email body
     447         *   string  $from          email address of sender
     448         * @var string
     449         */
     450        public $action_function = '';
     451
     452        /**
     453         * What to put in the X-Mailer header.
     454         * Options: An empty string for PHPMailer default, whitespace for none, or a string to use
     455         * @var string
     456         */
     457        public $XMailer = '';
     458
     459        /**
     460         * Which validator to use by default when validating email addresses.
     461         * May be a callable to inject your own validator, but there are several built-in validators.
     462         * @see PHPMailer::validateAddress()
     463         * @var string|callable
     464         * @static
     465         */
     466        public static $validator = 'auto';
     467
     468        /**
     469         * An instance of the SMTP sender class.
     470         * @var SMTP
     471         * @access protected
     472         */
     473        protected $smtp = null;
     474
     475        /**
     476         * The array of 'to' names and addresses.
     477         * @var array
     478         * @access protected
     479         */
     480        protected $to = array();
     481
     482        /**
     483         * The array of 'cc' names and addresses.
     484         * @var array
     485         * @access protected
     486         */
     487        protected $cc = array();
     488
     489        /**
     490         * The array of 'bcc' names and addresses.
     491         * @var array
     492         * @access protected
     493         */
     494        protected $bcc = array();
     495
     496        /**
     497         * The array of reply-to names and addresses.
     498         * @var array
     499         * @access protected
     500         */
     501        protected $ReplyTo = array();
     502
     503        /**
     504         * An array of all kinds of addresses.
     505         * Includes all of $to, $cc, $bcc
     506         * @var array
     507         * @access protected
     508         * @see PHPMailer::$to @see PHPMailer::$cc @see PHPMailer::$bcc
     509         */
     510        protected $all_recipients = array();
     511
     512        /**
     513         * An array of names and addresses queued for validation.
     514         * In send(), valid and non duplicate entries are moved to $all_recipients
     515         * and one of $to, $cc, or $bcc.
     516         * This array is used only for addresses with IDN.
     517         * @var array
     518         * @access protected
     519         * @see PHPMailer::$to @see PHPMailer::$cc @see PHPMailer::$bcc
     520         * @see PHPMailer::$all_recipients
     521         */
     522        protected $RecipientsQueue = array();
     523
     524        /**
     525         * An array of reply-to names and addresses queued for validation.
     526         * In send(), valid and non duplicate entries are moved to $ReplyTo.
     527         * This array is used only for addresses with IDN.
     528         * @var array
     529         * @access protected
     530         * @see PHPMailer::$ReplyTo
     531         */
     532        protected $ReplyToQueue = array();
     533
     534        /**
     535         * The array of attachments.
     536         * @var array
     537         * @access protected
     538         */
     539        protected $attachment = array();
     540
     541        /**
     542         * The array of custom headers.
     543         * @var array
     544         * @access protected
     545         */
     546        protected $CustomHeader = array();
     547
     548        /**
     549         * The most recent Message-ID (including angular brackets).
     550         * @var string
     551         * @access protected
     552         */
     553        protected $lastMessageID = '';
     554
     555        /**
     556         * The message's MIME type.
     557         * @var string
     558         * @access protected
     559         */
     560        protected $message_type = '';
     561
     562        /**
     563         * The array of MIME boundary strings.
     564         * @var array
     565         * @access protected
     566         */
     567        protected $boundary = array();
     568
     569        /**
     570         * The array of available languages.
     571         * @var array
     572         * @access protected
     573         */
     574        protected $language = array();
     575
     576        /**
     577         * The number of errors encountered.
     578         * @var integer
     579         * @access protected
     580         */
     581        protected $error_count = 0;
     582
     583        /**
     584         * The S/MIME certificate file path.
     585         * @var string
     586         * @access protected
     587         */
     588        protected $sign_cert_file = '';
     589
     590        /**
     591         * The S/MIME key file path.
     592         * @var string
     593         * @access protected
     594         */
     595        protected $sign_key_file = '';
     596
     597        /**
     598         * The optional S/MIME extra certificates ("CA Chain") file path.
     599         * @var string
     600         * @access protected
     601         */
     602        protected $sign_extracerts_file = '';
     603
     604        /**
     605         * The S/MIME password for the key.
     606         * Used only if the key is encrypted.
     607         * @var string
     608         * @access protected
     609         */
     610        protected $sign_key_pass = '';
     611
     612        /**
     613         * Whether to throw exceptions for errors.
     614         * @var boolean
     615         * @access protected
     616         */
     617        protected $exceptions = false;
     618
     619        /**
     620         * Unique ID used for message ID and boundaries.
     621         * @var string
     622         * @access protected
     623         */
     624        protected $uniqueid = '';
     625
     626        /**
     627         * Error severity: message only, continue processing.
     628         */
     629        const STOP_MESSAGE = 0;
     630
     631        /**
     632         * Error severity: message, likely ok to continue processing.
     633         */
     634        const STOP_CONTINUE = 1;
     635
     636        /**
     637         * Error severity: message, plus full stop, critical error reached.
     638         */
     639        const STOP_CRITICAL = 2;
     640
     641        /**
     642         * SMTP RFC standard line ending.
     643         */
     644        const CRLF = "\r\n";
     645
     646        /**
     647         * The maximum line length allowed by RFC 2822 section 2.1.1
     648         * @var integer
     649         */
     650        const MAX_LINE_LENGTH = 998;
     651
     652        /**
     653         * Constructor.
     654         * @param boolean $exceptions Should we throw external exceptions?
     655         */
     656        public function __construct($exceptions = null) {
     657                if ($exceptions !== null) {
     658                        $this->exceptions = (boolean) $exceptions;
     659                }
     660                //Pick an appropriate debug output format automatically
     661                $this->Debugoutput = (strpos(PHP_SAPI, 'cli') !== false ? 'echo' : 'html');
     662        }
     663
     664        /**
     665         * Destructor.
     666         */
     667        public function __destruct() {
     668                //Close any open SMTP connection nicely
     669                $this->smtpClose();
     670        }
     671
     672        /**
     673         * Call mail() in a safe_mode-aware fashion.
     674         * Also, unless sendmail_path points to sendmail (or something that
     675         * claims to be sendmail), don't pass params (not a perfect fix,
     676         * but it will do)
     677         * @param string $to To
     678         * @param string $subject Subject
     679         * @param string $body Message Body
     680         * @param string $header Additional Header(s)
     681         * @param string $params Params
     682         * @access private
     683         * @return boolean
     684         */
     685        private function mailPassthru($to, $subject, $body, $header, $params) {
     686                //Check overloading of mail function to avoid double-encoding
     687                if (ini_get('mbstring.func_overload') & 1) {
     688                        $subject = $this->secureHeader($subject);
     689                } else {
     690                        $subject = $this->encodeHeader($this->secureHeader($subject));
     691                }
     692
     693                //Can't use additional_parameters in safe_mode, calling mail() with null params breaks
     694                //@link http://php.net/manual/en/function.mail.php
     695                if (ini_get('safe_mode') or !$this->UseSendmailOptions or is_null($params)) {
     696                        $result = @mail($to, $subject, $body, $header);
     697                } else {
     698                        $result = @mail($to, $subject, $body, $header, $params);
     699                }
     700                return $result;
     701        }
     702
     703        /**
     704         * Output debugging info via user-defined method.
     705         * Only generates output if SMTP debug output is enabled (@see SMTP::$do_debug).
     706         * @see PHPMailer::$Debugoutput
     707         * @see PHPMailer::$SMTPDebug
     708         * @param string $str
     709         */
     710        protected function edebug($str) {
     711                if ($this->SMTPDebug <= 0) {
     712                        return;
     713                }
     714                //Avoid clash with built-in function names
     715                if (!in_array($this->Debugoutput, array('error_log', 'html', 'echo')) and is_callable($this->Debugoutput)) {
     716                        call_user_func($this->Debugoutput, $str, $this->SMTPDebug);
     717                        return;
     718                }
     719                switch ($this->Debugoutput) {
    724720            case 'error_log':
    725721                //Don't output, just log
    726722                error_log($str);
     
    744740                    trim($str)
    745741                ) . "\n";
    746742        }
    747     }
    748 
    749     /**
    750      * Sets message type to HTML or plain.
    751      * @param boolean $isHtml True for HTML mode.
    752      * @return void
    753      */
    754     public function isHTML($isHtml = true)
    755     {
    756         if ($isHtml) {
    757             $this->ContentType = 'text/html';
    758         } else {
    759             $this->ContentType = 'text/plain';
    760         }
    761     }
    762 
    763     /**
    764      * Send messages using SMTP.
    765      * @return void
    766      */
    767     public function isSMTP()
    768     {
    769         $this->Mailer = 'smtp';
    770     }
    771 
    772     /**
    773      * Send messages using PHP's mail() function.
    774      * @return void
    775      */
    776     public function isMail()
    777     {
    778         $this->Mailer = 'mail';
    779     }
    780 
    781     /**
    782      * Send messages using $Sendmail.
    783      * @return void
    784      */
    785     public function isSendmail()
    786     {
    787         $ini_sendmail_path = ini_get('sendmail_path');
    788 
    789         if (!stristr($ini_sendmail_path, 'sendmail')) {
    790             $this->Sendmail = '/usr/sbin/sendmail';
    791         } else {
    792             $this->Sendmail = $ini_sendmail_path;
    793         }
    794         $this->Mailer = 'sendmail';
    795     }
     743        }
    796744
    797     /**
    798      * Send messages using qmail.
    799      * @return void
    800      */
    801     public function isQmail()
    802     {
    803         $ini_sendmail_path = ini_get('sendmail_path');
    804 
    805         if (!stristr($ini_sendmail_path, 'qmail')) {
    806             $this->Sendmail = '/var/qmail/bin/qmail-inject';
    807         } else {
    808             $this->Sendmail = $ini_sendmail_path;
    809         }
    810         $this->Mailer = 'qmail';
    811     }
    812 
    813     /**
    814      * Add a "To" address.
    815      * @param string $address The email address to send to
    816      * @param string $name
    817      * @return boolean true on success, false if address already used or invalid in some way
    818      */
    819     public function addAddress($address, $name = '')
    820     {
    821         return $this->addOrEnqueueAnAddress('to', $address, $name);
    822     }
    823 
    824     /**
    825      * Add a "CC" address.
    826      * @note: This function works with the SMTP mailer on win32, not with the "mail" mailer.
    827      * @param string $address The email address to send to
    828      * @param string $name
    829      * @return boolean true on success, false if address already used or invalid in some way
    830      */
    831     public function addCC($address, $name = '')
    832     {
    833         return $this->addOrEnqueueAnAddress('cc', $address, $name);
    834     }
    835 
    836     /**
    837      * Add a "BCC" address.
    838      * @note: This function works with the SMTP mailer on win32, not with the "mail" mailer.
    839      * @param string $address The email address to send to
    840      * @param string $name
    841      * @return boolean true on success, false if address already used or invalid in some way
    842      */
    843     public function addBCC($address, $name = '')
    844     {
    845         return $this->addOrEnqueueAnAddress('bcc', $address, $name);
    846     }
    847 
    848     /**
    849      * Add a "Reply-To" address.
    850      * @param string $address The email address to reply to
    851      * @param string $name
    852      * @return boolean true on success, false if address already used or invalid in some way
    853      */
    854     public function addReplyTo($address, $name = '')
    855     {
    856         return $this->addOrEnqueueAnAddress('Reply-To', $address, $name);
    857     }
    858 
    859     /**
    860      * Add an address to one of the recipient arrays or to the ReplyTo array. Because PHPMailer
    861      * can't validate addresses with an IDN without knowing the PHPMailer::$CharSet (that can still
    862      * be modified after calling this function), addition of such addresses is delayed until send().
    863      * Addresses that have been added already return false, but do not throw exceptions.
    864      * @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo'
    865      * @param string $address The email address to send, resp. to reply to
    866      * @param string $name
    867      * @throws phpmailerException
    868      * @return boolean true on success, false if address already used or invalid in some way
    869      * @access protected
    870      */
    871     protected function addOrEnqueueAnAddress($kind, $address, $name)
    872     {
    873         $address = trim($address);
    874         $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
    875         if (($pos = strrpos($address, '@')) === false) {
    876             // At-sign is misssing.
    877             $error_message = $this->lang('invalid_address') . " (addAnAddress $kind): $address";
    878             $this->setError($error_message);
    879             $this->edebug($error_message);
    880             if ($this->exceptions) {
    881                 throw new phpmailerException($error_message);
    882             }
    883             return false;
    884         }
    885         $params = array($kind, $address, $name);
    886         // Enqueue addresses with IDN until we know the PHPMailer::$CharSet.
    887         if ($this->has8bitChars(substr($address, ++$pos)) and $this->idnSupported()) {
    888             if ($kind != 'Reply-To') {
    889                 if (!array_key_exists($address, $this->RecipientsQueue)) {
    890                     $this->RecipientsQueue[$address] = $params;
    891                     return true;
    892                 }
    893             } else {
    894                 if (!array_key_exists($address, $this->ReplyToQueue)) {
    895                     $this->ReplyToQueue[$address] = $params;
    896                     return true;
    897                 }
    898             }
    899             return false;
    900         }
    901         // Immediately add standard addresses without IDN.
    902         return call_user_func_array(array($this, 'addAnAddress'), $params);
    903     }
    904 
    905     /**
    906      * Add an address to one of the recipient arrays or to the ReplyTo array.
    907      * Addresses that have been added already return false, but do not throw exceptions.
    908      * @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo'
    909      * @param string $address The email address to send, resp. to reply to
    910      * @param string $name
    911      * @throws phpmailerException
    912      * @return boolean true on success, false if address already used or invalid in some way
    913      * @access protected
    914      */
    915     protected function addAnAddress($kind, $address, $name = '')
    916     {
    917         if (!in_array($kind, array('to', 'cc', 'bcc', 'Reply-To'))) {
    918             $error_message = $this->lang('Invalid recipient kind: ') . $kind;
    919             $this->setError($error_message);
    920             $this->edebug($error_message);
    921             if ($this->exceptions) {
    922                 throw new phpmailerException($error_message);
    923             }
    924             return false;
    925         }
    926         if (!$this->validateAddress($address)) {
    927             $error_message = $this->lang('invalid_address') . " (addAnAddress $kind): $address";
    928             $this->setError($error_message);
    929             $this->edebug($error_message);
    930             if ($this->exceptions) {
    931                 throw new phpmailerException($error_message);
    932             }
    933             return false;
    934         }
    935         if ($kind != 'Reply-To') {
    936             if (!array_key_exists(strtolower($address), $this->all_recipients)) {
    937                 array_push($this->$kind, array($address, $name));
    938                 $this->all_recipients[strtolower($address)] = true;
    939                 return true;
    940             }
    941         } else {
    942             if (!array_key_exists(strtolower($address), $this->ReplyTo)) {
    943                 $this->ReplyTo[strtolower($address)] = array($address, $name);
    944                 return true;
    945             }
    946         }
    947         return false;
    948     }
    949 
    950     /**
    951      * Parse and validate a string containing one or more RFC822-style comma-separated email addresses
    952      * of the form "display name <address>" into an array of name/address pairs.
    953      * Uses the imap_rfc822_parse_adrlist function if the IMAP extension is available.
    954      * Note that quotes in the name part are removed.
    955      * @param string $addrstr The address list string
    956      * @param bool $useimap Whether to use the IMAP extension to parse the list
    957      * @return array
    958      * @link http://www.andrew.cmu.edu/user/agreen1/testing/mrbs/web/Mail/RFC822.php A more careful implementation
    959      */
    960     public function parseAddresses($addrstr, $useimap = true)
    961     {
    962         $addresses = array();
    963         if ($useimap and function_exists('imap_rfc822_parse_adrlist')) {
    964             //Use this built-in parser if it's available
    965             $list = imap_rfc822_parse_adrlist($addrstr, '');
    966             foreach ($list as $address) {
    967                 if ($address->host != '.SYNTAX-ERROR.') {
    968                     if ($this->validateAddress($address->mailbox . '@' . $address->host)) {
    969                         $addresses[] = array(
    970                             'name' => (property_exists($address, 'personal') ? $address->personal : ''),
    971                             'address' => $address->mailbox . '@' . $address->host
    972                         );
    973                     }
    974                 }
    975             }
    976         } else {
    977             //Use this simpler parser
    978             $list = explode(',', $addrstr);
    979             foreach ($list as $address) {
    980                 $address = trim($address);
    981                 //Is there a separate name part?
    982                 if (strpos($address, '<') === false) {
    983                     //No separate name, just use the whole thing
    984                     if ($this->validateAddress($address)) {
    985                         $addresses[] = array(
    986                             'name' => '',
    987                             'address' => $address
    988                         );
    989                     }
    990                 } else {
    991                     list($name, $email) = explode('<', $address);
    992                     $email = trim(str_replace('>', '', $email));
    993                     if ($this->validateAddress($email)) {
    994                         $addresses[] = array(
    995                             'name' => trim(str_replace(array('"', "'"), '', $name)),
    996                             'address' => $email
    997                         );
    998                     }
    999                 }
    1000             }
    1001         }
    1002         return $addresses;
    1003     }
    1004 
    1005     /**
    1006      * Set the From and FromName properties.
    1007      * @param string $address
    1008      * @param string $name
    1009      * @param boolean $auto Whether to also set the Sender address, defaults to true
    1010      * @throws phpmailerException
    1011      * @return boolean
    1012      */
    1013     public function setFrom($address, $name = '', $auto = true)
    1014     {
    1015         $address = trim($address);
    1016         $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
    1017         // Don't validate now addresses with IDN. Will be done in send().
    1018         if (($pos = strrpos($address, '@')) === false or
     745        /**
     746         * Sets message type to HTML or plain.
     747         * @param boolean $isHtml True for HTML mode.
     748         * @return void
     749         */
     750        public function isHTML($isHtml = true) {
     751                if ($isHtml) {
     752                        $this->ContentType = 'text/html';
     753                } else {
     754                        $this->ContentType = 'text/plain';
     755                }
     756        }
     757
     758        /**
     759         * Send messages using SMTP.
     760         * @return void
     761         */
     762        public function isSMTP() {
     763                $this->Mailer = 'smtp';
     764        }
     765
     766        /**
     767         * Send messages using PHP's mail() function.
     768         * @return void
     769         */
     770        public function isMail() {
     771                $this->Mailer = 'mail';
     772        }
     773
     774        /**
     775         * Send messages using $Sendmail.
     776         * @return void
     777         */
     778        public function isSendmail() {
     779                $ini_sendmail_path = ini_get('sendmail_path');
     780
     781                if (!stristr($ini_sendmail_path, 'sendmail')) {
     782                        $this->Sendmail = '/usr/sbin/sendmail';
     783                } else {
     784                        $this->Sendmail = $ini_sendmail_path;
     785                }
     786                $this->Mailer = 'sendmail';
     787        }
     788
     789        /**
     790         * Send messages using qmail.
     791         * @return void
     792         */
     793        public function isQmail() {
     794                $ini_sendmail_path = ini_get('sendmail_path');
     795
     796                if (!stristr($ini_sendmail_path, 'qmail')) {
     797                        $this->Sendmail = '/var/qmail/bin/qmail-inject';
     798                } else {
     799                        $this->Sendmail = $ini_sendmail_path;
     800                }
     801                $this->Mailer = 'qmail';
     802        }
     803
     804        /**
     805         * Add a "To" address.
     806         * @param string $address The email address to send to
     807         * @param string $name
     808         * @return boolean true on success, false if address already used or invalid in some way
     809         */
     810        public function addAddress($address, $name = '') {
     811                return $this->addOrEnqueueAnAddress('to', $address, $name);
     812        }
     813
     814        /**
     815         * Add a "CC" address.
     816         * @note: This function works with the SMTP mailer on win32, not with the "mail" mailer.
     817         * @param string $address The email address to send to
     818         * @param string $name
     819         * @return boolean true on success, false if address already used or invalid in some way
     820         */
     821        public function addCC($address, $name = '') {
     822                return $this->addOrEnqueueAnAddress('cc', $address, $name);
     823        }
     824
     825        /**
     826         * Add a "BCC" address.
     827         * @note: This function works with the SMTP mailer on win32, not with the "mail" mailer.
     828         * @param string $address The email address to send to
     829         * @param string $name
     830         * @return boolean true on success, false if address already used or invalid in some way
     831         */
     832        public function addBCC($address, $name = '') {
     833                return $this->addOrEnqueueAnAddress('bcc', $address, $name);
     834        }
     835
     836        /**
     837         * Add a "Reply-To" address.
     838         * @param string $address The email address to reply to
     839         * @param string $name
     840         * @return boolean true on success, false if address already used or invalid in some way
     841         */
     842        public function addReplyTo($address, $name = '') {
     843                return $this->addOrEnqueueAnAddress('Reply-To', $address, $name);
     844        }
     845
     846        /**
     847         * Add an address to one of the recipient arrays or to the ReplyTo array. Because PHPMailer
     848         * can't validate addresses with an IDN without knowing the PHPMailer::$CharSet (that can still
     849         * be modified after calling this function), addition of such addresses is delayed until send().
     850         * Addresses that have been added already return false, but do not throw exceptions.
     851         * @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo'
     852         * @param string $address The email address to send, resp. to reply to
     853         * @param string $name
     854         * @throws phpmailerException
     855         * @return boolean true on success, false if address already used or invalid in some way
     856         * @access protected
     857         */
     858        protected function addOrEnqueueAnAddress($kind, $address, $name) {
     859                $address = trim($address);
     860                $name    = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
     861                if (($pos = strrpos($address, '@')) === false) {
     862                        // At-sign is misssing.
     863                        $error_message = $this->lang('invalid_address') . " (addAnAddress $kind): $address";
     864                        $this->setError($error_message);
     865                        $this->edebug($error_message);
     866                        if ($this->exceptions) {
     867                                throw new phpmailerException($error_message);
     868                        }
     869                        return false;
     870                }
     871                $params = array($kind, $address, $name);
     872                // Enqueue addresses with IDN until we know the PHPMailer::$CharSet.
     873                if ($this->has8bitChars(substr($address, ++$pos)) and $this->idnSupported()) {
     874                        if ($kind != 'Reply-To') {
     875                                if (!array_key_exists($address, $this->RecipientsQueue)) {
     876                                        $this->RecipientsQueue[$address] = $params;
     877                                        return true;
     878                                }
     879                        } else {
     880                                if (!array_key_exists($address, $this->ReplyToQueue)) {
     881                                        $this->ReplyToQueue[$address] = $params;
     882                                        return true;
     883                                }
     884                        }
     885                        return false;
     886                }
     887                // Immediately add standard addresses without IDN.
     888                return call_user_func_array(array($this, 'addAnAddress'), $params);
     889        }
     890
     891        /**
     892         * Add an address to one of the recipient arrays or to the ReplyTo array.
     893         * Addresses that have been added already return false, but do not throw exceptions.
     894         * @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo'
     895         * @param string $address The email address to send, resp. to reply to
     896         * @param string $name
     897         * @throws phpmailerException
     898         * @return boolean true on success, false if address already used or invalid in some way
     899         * @access protected
     900         */
     901        protected function addAnAddress($kind, $address, $name = '') {
     902                if (!in_array($kind, array('to', 'cc', 'bcc', 'Reply-To'))) {
     903                        $error_message = $this->lang('Invalid recipient kind: ') . $kind;
     904                        $this->setError($error_message);
     905                        $this->edebug($error_message);
     906                        if ($this->exceptions) {
     907                                throw new phpmailerException($error_message);
     908                        }
     909                        return false;
     910                }
     911                if (!$this->validateAddress($address)) {
     912                        $error_message = $this->lang('invalid_address') . " (addAnAddress $kind): $address";
     913                        $this->setError($error_message);
     914                        $this->edebug($error_message);
     915                        if ($this->exceptions) {
     916                                throw new phpmailerException($error_message);
     917                        }
     918                        return false;
     919                }
     920                if ($kind != 'Reply-To') {
     921                        if (!array_key_exists(strtolower($address), $this->all_recipients)) {
     922                                array_push($this->$kind, array($address, $name));
     923                                $this->all_recipients[strtolower($address)] = true;
     924                                return true;
     925                        }
     926                } else {
     927                        if (!array_key_exists(strtolower($address), $this->ReplyTo)) {
     928                                $this->ReplyTo[strtolower($address)] = array($address, $name);
     929                                return true;
     930                        }
     931                }
     932                return false;
     933        }
     934
     935        /**
     936         * Parse and validate a string containing one or more RFC822-style comma-separated email addresses
     937         * of the form "display name <address>" into an array of name/address pairs.
     938         * Uses the imap_rfc822_parse_adrlist function if the IMAP extension is available.
     939         * Note that quotes in the name part are removed.
     940         * @param string $addrstr The address list string
     941         * @param bool $useimap Whether to use the IMAP extension to parse the list
     942         * @return array
     943         * @link http://www.andrew.cmu.edu/user/agreen1/testing/mrbs/web/Mail/RFC822.php A more careful implementation
     944         */
     945        public function parseAddresses($addrstr, $useimap = true) {
     946                $addresses = array();
     947                if ($useimap and function_exists('imap_rfc822_parse_adrlist')) {
     948                        //Use this built-in parser if it's available
     949                        $list = imap_rfc822_parse_adrlist($addrstr, '');
     950                        foreach ($list as $address) {
     951                                if ($address->host != '.SYNTAX-ERROR.') {
     952                                        if ($this->validateAddress($address->mailbox . '@' . $address->host)) {
     953                                                $addresses[] = array(
     954                                                        'name'    => (property_exists($address, 'personal') ? $address->personal : ''),
     955                                                        'address' => $address->mailbox . '@' . $address->host,
     956                                                );
     957                                        }
     958                                }
     959                        }
     960                } else {
     961                        //Use this simpler parser
     962                        $list = explode(',', $addrstr);
     963                        foreach ($list as $address) {
     964                                $address = trim($address);
     965                                //Is there a separate name part?
     966                                if (strpos($address, '<') === false) {
     967                                        //No separate name, just use the whole thing
     968                                        if ($this->validateAddress($address)) {
     969                                                $addresses[] = array(
     970                                                        'name'    => '',
     971                                                        'address' => $address,
     972                                                );
     973                                        }
     974                                } else {
     975                                        list($name, $email) = explode('<', $address);
     976                                        $email              = trim(str_replace('>', '', $email));
     977                                        if ($this->validateAddress($email)) {
     978                                                $addresses[] = array(
     979                                                        'name'    => trim(str_replace(array('"', "'"), '', $name)),
     980                                                        'address' => $email,
     981                                                );
     982                                        }
     983                                }
     984                        }
     985                }
     986                return $addresses;
     987        }
     988
     989        /**
     990         * Set the From and FromName properties.
     991         * @param string $address
     992         * @param string $name
     993         * @param boolean $auto Whether to also set the Sender address, defaults to true
     994         * @throws phpmailerException
     995         * @return boolean
     996         */
     997        public function setFrom($address, $name = '', $auto = true) {
     998                $address = trim($address);
     999                $name    = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
     1000                // Don't validate now addresses with IDN. Will be done in send().
     1001                if (($pos = strrpos($address, '@')) === false or
    10191002            (!$this->has8bitChars(substr($address, ++$pos)) or !$this->idnSupported()) and
    10201003            !$this->validateAddress($address)) {
    1021             $error_message = $this->lang('invalid_address') . " (setFrom) $address";
    1022             $this->setError($error_message);
    1023             $this->edebug($error_message);
    1024             if ($this->exceptions) {
    1025                 throw new phpmailerException($error_message);
    1026             }
    1027             return false;
    1028         }
    1029         $this->From = $address;
    1030         $this->FromName = $name;
    1031         if ($auto) {
    1032             if (empty($this->Sender)) {
    1033                 $this->Sender = $address;
    1034             }
    1035         }
    1036         return true;
    1037     }
    1038 
    1039     /**
    1040      * Return the Message-ID header of the last email.
    1041      * Technically this is the value from the last time the headers were created,
    1042      * but it's also the message ID of the last sent message except in
    1043      * pathological cases.
    1044      * @return string
    1045      */
    1046     public function getLastMessageID()
    1047     {
    1048         return $this->lastMessageID;
    1049     }
    1050 
    1051     /**
    1052      * Check that a string looks like an email address.
    1053      * @param string $address The email address to check
    1054      * @param string|callable $patternselect A selector for the validation pattern to use :
    1055      * * `auto` Pick best pattern automatically;
    1056      * * `pcre8` Use the squiloople.com pattern, requires PCRE > 8.0, PHP >= 5.3.2, 5.2.14;
    1057      * * `pcre` Use old PCRE implementation;
    1058      * * `php` Use PHP built-in FILTER_VALIDATE_EMAIL;
    1059      * * `html5` Use the pattern given by the HTML5 spec for 'email' type form input elements.
    1060      * * `noregex` Don't use a regex: super fast, really dumb.
    1061      * Alternatively you may pass in a callable to inject your own validator, for example:
    1062      * PHPMailer::validateAddress('user@example.com', function($address) {
    1063      *     return (strpos($address, '@') !== false);
    1064      * });
    1065      * You can also set the PHPMailer::$validator static to a callable, allowing built-in methods to use your validator.
    1066      * @return boolean
    1067      * @static
    1068      * @access public
    1069      */
    1070     public static function validateAddress($address, $patternselect = null)
    1071     {
    1072         if (is_null($patternselect)) {
    1073             $patternselect = self::$validator;
    1074         }
    1075         if (is_callable($patternselect)) {
    1076             return call_user_func($patternselect, $address);
    1077         }
    1078         //Reject line breaks in addresses; it's valid RFC5322, but not RFC5321
    1079         if (strpos($address, "\n") !== false or strpos($address, "\r") !== false) {
    1080             return false;
    1081         }
    1082         if (!$patternselect or $patternselect == 'auto') {
    1083             //Check this constant first so it works when extension_loaded() is disabled by safe mode
    1084             //Constant was added in PHP 5.2.4
    1085             if (defined('PCRE_VERSION')) {
    1086                 //This pattern can get stuck in a recursive loop in PCRE <= 8.0.2
    1087                 if (version_compare(PCRE_VERSION, '8.0.3') >= 0) {
    1088                     $patternselect = 'pcre8';
    1089                 } else {
    1090                     $patternselect = 'pcre';
    1091                 }
    1092             } elseif (function_exists('extension_loaded') and extension_loaded('pcre')) {
    1093                 //Fall back to older PCRE
    1094                 $patternselect = 'pcre';
    1095             } else {
    1096                 //Filter_var appeared in PHP 5.2.0 and does not require the PCRE extension
    1097                 if (version_compare(PHP_VERSION, '5.2.0') >= 0) {
    1098                     $patternselect = 'php';
    1099                 } else {
    1100                     $patternselect = 'noregex';
    1101                 }
    1102             }
    1103         }
    1104         switch ($patternselect) {
     1004                        $error_message = $this->lang('invalid_address') . " (setFrom) $address";
     1005                        $this->setError($error_message);
     1006                        $this->edebug($error_message);
     1007                        if ($this->exceptions) {
     1008                                throw new phpmailerException($error_message);
     1009                        }
     1010                        return false;
     1011                }
     1012                $this->From     = $address;
     1013                $this->FromName = $name;
     1014                if ($auto) {
     1015                        if (empty($this->Sender)) {
     1016                                $this->Sender = $address;
     1017                        }
     1018                }
     1019                return true;
     1020        }
     1021
     1022        /**
     1023         * Return the Message-ID header of the last email.
     1024         * Technically this is the value from the last time the headers were created,
     1025         * but it's also the message ID of the last sent message except in
     1026         * pathological cases.
     1027         * @return string
     1028         */
     1029        public function getLastMessageID() {
     1030                return $this->lastMessageID;
     1031        }
     1032
     1033        /**
     1034         * Check that a string looks like an email address.
     1035         * @param string $address The email address to check
     1036         * @param string|callable $patternselect A selector for the validation pattern to use :
     1037         * * `auto` Pick best pattern automatically;
     1038         * * `pcre8` Use the squiloople.com pattern, requires PCRE > 8.0, PHP >= 5.3.2, 5.2.14;
     1039         * * `pcre` Use old PCRE implementation;
     1040         * * `php` Use PHP built-in FILTER_VALIDATE_EMAIL;
     1041         * * `html5` Use the pattern given by the HTML5 spec for 'email' type form input elements.
     1042         * * `noregex` Don't use a regex: super fast, really dumb.
     1043         * Alternatively you may pass in a callable to inject your own validator, for example:
     1044         * PHPMailer::validateAddress('user@example.com', function($address) {
     1045         *     return (strpos($address, '@') !== false);
     1046         * });
     1047         * You can also set the PHPMailer::$validator static to a callable, allowing built-in methods to use your validator.
     1048         * @return boolean
     1049         * @static
     1050         * @access public
     1051         */
     1052        public static function validateAddress($address, $patternselect = null) {
     1053                if (is_null($patternselect)) {
     1054                        $patternselect = self::$validator;
     1055                }
     1056                if (is_callable($patternselect)) {
     1057                        return call_user_func($patternselect, $address);
     1058                }
     1059                //Reject line breaks in addresses; it's valid RFC5322, but not RFC5321
     1060                if (strpos($address, "\n") !== false or strpos($address, "\r") !== false) {
     1061                        return false;
     1062                }
     1063                if (!$patternselect or $patternselect == 'auto') {
     1064                        //Check this constant first so it works when extension_loaded() is disabled by safe mode
     1065                        //Constant was added in PHP 5.2.4
     1066                        if (defined('PCRE_VERSION')) {
     1067                                //This pattern can get stuck in a recursive loop in PCRE <= 8.0.2
     1068                                if (version_compare(PCRE_VERSION, '8.0.3') >= 0) {
     1069                                        $patternselect = 'pcre8';
     1070                                } else {
     1071                                        $patternselect = 'pcre';
     1072                                }
     1073                        } elseif (function_exists('extension_loaded') and extension_loaded('pcre')) {
     1074                                //Fall back to older PCRE
     1075                                $patternselect = 'pcre';
     1076                        } else {
     1077                                //Filter_var appeared in PHP 5.2.0 and does not require the PCRE extension
     1078                                if (version_compare(PHP_VERSION, '5.2.0') >= 0) {
     1079                                        $patternselect = 'php';
     1080                                } else {
     1081                                        $patternselect = 'noregex';
     1082                                }
     1083                        }
     1084                }
     1085                switch ($patternselect) {
    11051086            case 'pcre8':
    11061087                /**
    11071088                 * Uses the same RFC5322 regex on which FILTER_VALIDATE_EMAIL is based, but allows dotless domains.
     
    11091090                 * @copyright 2009-2010 Michael Rushton
    11101091                 * Feel free to use and redistribute this code. But please keep this copyright notice.
    11111092                 */
    1112                 return (boolean)preg_match(
     1093                return (boolean) preg_match(
    11131094                    '/^(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){255,})(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){65,}@)' .
    11141095                    '((?>(?>(?>((?>(?>(?>\x0D\x0A)?[\t ])+|(?>[\t ]*\x0D\x0A)?[\t ]+)?)(\((?>(?2)' .
    11151096                    '(?>[\x01-\x08\x0B\x0C\x0E-\'*-\[\]-\x7F]|\\\[\x00-\x7F]|(?3)))*(?2)\)))+(?2))|(?2))?)' .
     
    11231104                );
    11241105            case 'pcre':
    11251106                //An older regex that doesn't need a recent PCRE
    1126                 return (boolean)preg_match(
     1107                return (boolean) preg_match(
    11271108                    '/^(?!(?>"?(?>\\\[ -~]|[^"])"?){255,})(?!(?>"?(?>\\\[ -~]|[^"])"?){65,}@)(?>' .
    11281109                    '[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*")' .
    11291110                    '(?>\.(?>[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*"))*' .
     
    11411122                 * This is the pattern used in the HTML5 spec for validation of 'email' type form input elements.
    11421123                 * @link http://www.whatwg.org/specs/web-apps/current-work/#e-mail-state-(type=email)
    11431124                 */
    1144                 return (boolean)preg_match(
     1125                return (boolean) preg_match(
    11451126                    '/^[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}' .
    11461127                    '[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/sD',
    11471128                    $address
     
    11541135                    and strpos($address, '@') != strlen($address) - 1);
    11551136            case 'php':
    11561137            default:
    1157                 return (boolean)filter_var($address, FILTER_VALIDATE_EMAIL);
     1138                return (boolean) filter_var($address, FILTER_VALIDATE_EMAIL);
    11581139        }
    1159     }
     1140        }
    11601141
    1161     /**
    1162      * Tells whether IDNs (Internationalized Domain Names) are supported or not. This requires the
    1163      * "intl" and "mbstring" PHP extensions.
    1164      * @return bool "true" if required functions for IDN support are present
    1165      */
    1166     public function idnSupported()
    1167     {
    1168         // @TODO: Write our own "idn_to_ascii" function for PHP <= 5.2.
    1169         return function_exists('idn_to_ascii') and function_exists('mb_convert_encoding');
    1170     }
    1171 
    1172     /**
    1173      * Converts IDN in given email address to its ASCII form, also known as punycode, if possible.
    1174      * Important: Address must be passed in same encoding as currently set in PHPMailer::$CharSet.
    1175      * This function silently returns unmodified address if:
    1176      * - No conversion is necessary (i.e. domain name is not an IDN, or is already in ASCII form)
    1177      * - Conversion to punycode is impossible (e.g. required PHP functions are not available)
    1178      *   or fails for any reason (e.g. domain has characters not allowed in an IDN)
    1179      * @see PHPMailer::$CharSet
    1180      * @param string $address The email address to convert
    1181      * @return string The encoded address in ASCII form
    1182      */
    1183     public function punyencodeAddress($address)
    1184     {
    1185         // Verify we have required functions, CharSet, and at-sign.
    1186         if ($this->idnSupported() and
     1142        /**
     1143         * Tells whether IDNs (Internationalized Domain Names) are supported or not. This requires the
     1144         * "intl" and "mbstring" PHP extensions.
     1145         * @return bool "true" if required functions for IDN support are present
     1146         */
     1147        public function idnSupported() {
     1148                // @TODO: Write our own "idn_to_ascii" function for PHP <= 5.2.
     1149                return function_exists('idn_to_ascii') and function_exists('mb_convert_encoding');
     1150        }
     1151
     1152        /**
     1153         * Converts IDN in given email address to its ASCII form, also known as punycode, if possible.
     1154         * Important: Address must be passed in same encoding as currently set in PHPMailer::$CharSet.
     1155         * This function silently returns unmodified address if:
     1156         * - No conversion is necessary (i.e. domain name is not an IDN, or is already in ASCII form)
     1157         * - Conversion to punycode is impossible (e.g. required PHP functions are not available)
     1158         *   or fails for any reason (e.g. domain has characters not allowed in an IDN)
     1159         * @see PHPMailer::$CharSet
     1160         * @param string $address The email address to convert
     1161         * @return string The encoded address in ASCII form
     1162         */
     1163        public function punyencodeAddress($address) {
     1164                // Verify we have required functions, CharSet, and at-sign.
     1165                if ($this->idnSupported() and
    11871166            !empty($this->CharSet) and
    11881167            ($pos = strrpos($address, '@')) !== false) {
    1189             $domain = substr($address, ++$pos);
    1190             // Verify CharSet string is a valid one, and domain properly encoded in this CharSet.
    1191             if ($this->has8bitChars($domain) and @mb_check_encoding($domain, $this->CharSet)) {
    1192                 $domain = mb_convert_encoding($domain, 'UTF-8', $this->CharSet);
    1193                 if (($punycode = defined('INTL_IDNA_VARIANT_UTS46') ?
     1168                        $domain = substr($address, ++$pos);
     1169                        // Verify CharSet string is a valid one, and domain properly encoded in this CharSet.
     1170                        if ($this->has8bitChars($domain) and @mb_check_encoding($domain, $this->CharSet)) {
     1171                                $domain = mb_convert_encoding($domain, 'UTF-8', $this->CharSet);
     1172                                if (($punycode = defined('INTL_IDNA_VARIANT_UTS46') ?
    11941173                    idn_to_ascii($domain, 0, INTL_IDNA_VARIANT_UTS46) :
    11951174                    idn_to_ascii($domain)) !== false) {
    1196                     return substr($address, 0, $pos) . $punycode;
    1197                 }
    1198             }
    1199         }
    1200         return $address;
    1201     }
    1202 
    1203     /**
    1204      * Create a message and send it.
    1205      * Uses the sending method specified by $Mailer.
    1206      * @throws phpmailerException
    1207      * @return boolean false on error - See the ErrorInfo property for details of the error.
    1208      */
    1209     public function send()
    1210     {
    1211         try {
    1212             if (!$this->preSend()) {
    1213                 return false;
    1214             }
    1215             return $this->postSend();
    1216         } catch (phpmailerException $exc) {
    1217             $this->mailHeader = '';
    1218             $this->setError($exc->getMessage());
    1219             if ($this->exceptions) {
    1220                 throw $exc;
    1221             }
    1222             return false;
    1223         }
    1224     }
    1225 
    1226     /**
    1227      * Prepare a message for sending.
    1228      * @throws phpmailerException
    1229      * @return boolean
    1230      */
    1231     public function preSend()
    1232     {
    1233         try {
    1234             $this->error_count = 0; // Reset errors
    1235             $this->mailHeader = '';
    1236 
    1237             // Dequeue recipient and Reply-To addresses with IDN
    1238             foreach (array_merge($this->RecipientsQueue, $this->ReplyToQueue) as $params) {
    1239                 $params[1] = $this->punyencodeAddress($params[1]);
    1240                 call_user_func_array(array($this, 'addAnAddress'), $params);
    1241             }
    1242             if ((count($this->to) + count($this->cc) + count($this->bcc)) < 1) {
    1243                 throw new phpmailerException($this->lang('provide_address'), self::STOP_CRITICAL);
    1244             }
    1245 
    1246             // Validate From, Sender, and ConfirmReadingTo addresses
    1247             foreach (array('From', 'Sender', 'ConfirmReadingTo') as $address_kind) {
    1248                 $this->$address_kind = trim($this->$address_kind);
    1249                 if (empty($this->$address_kind)) {
    1250                     continue;
    1251                 }
    1252                 $this->$address_kind = $this->punyencodeAddress($this->$address_kind);
    1253                 if (!$this->validateAddress($this->$address_kind)) {
    1254                     $error_message = $this->lang('invalid_address') . ' (punyEncode) ' . $this->$address_kind;
    1255                     $this->setError($error_message);
    1256                     $this->edebug($error_message);
    1257                     if ($this->exceptions) {
    1258                         throw new phpmailerException($error_message);
    1259                     }
    1260                     return false;
    1261                 }
    1262             }
    1263 
    1264             // Set whether the message is multipart/alternative
    1265             if ($this->alternativeExists()) {
    1266                 $this->ContentType = 'multipart/alternative';
    1267             }
    1268 
    1269             $this->setMessageType();
    1270             // Refuse to send an empty message unless we are specifically allowing it
    1271             if (!$this->AllowEmpty and empty($this->Body)) {
    1272                 throw new phpmailerException($this->lang('empty_message'), self::STOP_CRITICAL);
    1273             }
    1274 
    1275             // Create body before headers in case body makes changes to headers (e.g. altering transfer encoding)
    1276             $this->MIMEHeader = '';
    1277             $this->MIMEBody = $this->createBody();
    1278             // createBody may have added some headers, so retain them
    1279             $tempheaders = $this->MIMEHeader;
    1280             $this->MIMEHeader = $this->createHeader();
    1281             $this->MIMEHeader .= $tempheaders;
    1282 
    1283             // To capture the complete message when using mail(), create
    1284             // an extra header list which createHeader() doesn't fold in
    1285             if ($this->Mailer == 'mail') {
    1286                 if (count($this->to) > 0) {
    1287                     $this->mailHeader .= $this->addrAppend('To', $this->to);
    1288                 } else {
    1289                     $this->mailHeader .= $this->headerLine('To', 'undisclosed-recipients:;');
    1290                 }
    1291                 $this->mailHeader .= $this->headerLine(
     1175                                        return substr($address, 0, $pos) . $punycode;
     1176                                }
     1177                        }
     1178                }
     1179                return $address;
     1180        }
     1181
     1182        /**
     1183         * Create a message and send it.
     1184         * Uses the sending method specified by $Mailer.
     1185         * @throws phpmailerException
     1186         * @return boolean false on error - See the ErrorInfo property for details of the error.
     1187         */
     1188        public function send() {
     1189                try {
     1190                        if (!$this->preSend()) {
     1191                                return false;
     1192                        }
     1193                        return $this->postSend();
     1194                } catch (phpmailerException $exc) {
     1195                        $this->mailHeader = '';
     1196                        $this->setError($exc->getMessage());
     1197                        if ($this->exceptions) {
     1198                                throw $exc;
     1199                        }
     1200                        return false;
     1201                }
     1202        }
     1203
     1204        /**
     1205         * Prepare a message for sending.
     1206         * @throws phpmailerException
     1207         * @return boolean
     1208         */
     1209        public function preSend() {
     1210                try {
     1211                        $this->error_count = 0; // Reset errors
     1212                        $this->mailHeader  = '';
     1213
     1214                        // Dequeue recipient and Reply-To addresses with IDN
     1215                        foreach (array_merge($this->RecipientsQueue, $this->ReplyToQueue) as $params) {
     1216                                $params[1] = $this->punyencodeAddress($params[1]);
     1217                                call_user_func_array(array($this, 'addAnAddress'), $params);
     1218                        }
     1219                        if ((count($this->to) + count($this->cc) + count($this->bcc)) < 1) {
     1220                                throw new phpmailerException($this->lang('provide_address'), self::STOP_CRITICAL);
     1221                        }
     1222
     1223                        // Validate From, Sender, and ConfirmReadingTo addresses
     1224                        foreach (array('From', 'Sender', 'ConfirmReadingTo') as $address_kind) {
     1225                                $this->$address_kind = trim($this->$address_kind);
     1226                                if (empty($this->$address_kind)) {
     1227                                        continue;
     1228                                }
     1229                                $this->$address_kind = $this->punyencodeAddress($this->$address_kind);
     1230                                if (!$this->validateAddress($this->$address_kind)) {
     1231                                        $error_message = $this->lang('invalid_address') . ' (punyEncode) ' . $this->$address_kind;
     1232                                        $this->setError($error_message);
     1233                                        $this->edebug($error_message);
     1234                                        if ($this->exceptions) {
     1235                                                throw new phpmailerException($error_message);
     1236                                        }
     1237                                        return false;
     1238                                }
     1239                        }
     1240
     1241                        // Set whether the message is multipart/alternative
     1242                        if ($this->alternativeExists()) {
     1243                                $this->ContentType = 'multipart/alternative';
     1244                        }
     1245
     1246                        $this->setMessageType();
     1247                        // Refuse to send an empty message unless we are specifically allowing it
     1248                        if (!$this->AllowEmpty and empty($this->Body)) {
     1249                                throw new phpmailerException($this->lang('empty_message'), self::STOP_CRITICAL);
     1250                        }
     1251
     1252                        // Create body before headers in case body makes changes to headers (e.g. altering transfer encoding)
     1253                        $this->MIMEHeader = '';
     1254                        $this->MIMEBody   = $this->createBody();
     1255                        // createBody may have added some headers, so retain them
     1256                        $tempheaders      = $this->MIMEHeader;
     1257                        $this->MIMEHeader = $this->createHeader();
     1258                        $this->MIMEHeader .= $tempheaders;
     1259
     1260                        // To capture the complete message when using mail(), create
     1261                        // an extra header list which createHeader() doesn't fold in
     1262                        if ($this->Mailer == 'mail') {
     1263                                if (count($this->to) > 0) {
     1264                                        $this->mailHeader .= $this->addrAppend('To', $this->to);
     1265                                } else {
     1266                                        $this->mailHeader .= $this->headerLine('To', 'undisclosed-recipients:;');
     1267                                }
     1268                                $this->mailHeader .= $this->headerLine(
    12921269                    'Subject',
    12931270                    $this->encodeHeader($this->secureHeader(trim($this->Subject)))
    12941271                );
    1295             }
     1272                        }
    12961273
    1297             // Sign with DKIM if enabled
    1298             if (!empty($this->DKIM_domain)
     1274                        // Sign with DKIM if enabled
     1275                        if (!empty($this->DKIM_domain)
    12991276                and !empty($this->DKIM_selector)
    13001277                and (!empty($this->DKIM_private_string)
    13011278                    or (!empty($this->DKIM_private)
     
    13041281                    )
    13051282                )
    13061283            ) {
    1307                 $header_dkim = $this->DKIM_Add(
     1284                                $header_dkim = $this->DKIM_Add(
    13081285                    $this->MIMEHeader . $this->mailHeader,
    13091286                    $this->encodeHeader($this->secureHeader($this->Subject)),
    13101287                    $this->MIMEBody
    13111288                );
    1312                 $this->MIMEHeader = rtrim($this->MIMEHeader, "\r\n ") . self::CRLF .
     1289                                $this->MIMEHeader = rtrim($this->MIMEHeader, "\r\n ") . self::CRLF .
    13131290                    str_replace("\r\n", "\n", $header_dkim) . self::CRLF;
    1314             }
    1315             return true;
    1316         } catch (phpmailerException $exc) {
    1317             $this->setError($exc->getMessage());
    1318             if ($this->exceptions) {
    1319                 throw $exc;
    1320             }
    1321             return false;
    1322         }
    1323     }
    1324 
    1325     /**
    1326      * Actually send a message.
    1327      * Send the email via the selected mechanism
    1328      * @throws phpmailerException
    1329      * @return boolean
    1330      */
    1331     public function postSend()
    1332     {
    1333         try {
    1334             // Choose the mailer and send through it
    1335             switch ($this->Mailer) {
     1291                        }
     1292                        return true;
     1293                } catch (phpmailerException $exc) {
     1294                        $this->setError($exc->getMessage());
     1295                        if ($this->exceptions) {
     1296                                throw $exc;
     1297                        }
     1298                        return false;
     1299                }
     1300        }
     1301
     1302        /**
     1303         * Actually send a message.
     1304         * Send the email via the selected mechanism
     1305         * @throws phpmailerException
     1306         * @return boolean
     1307         */
     1308        public function postSend() {
     1309                try {
     1310                        // Choose the mailer and send through it
     1311                        switch ($this->Mailer) {
    13361312                case 'sendmail':
    13371313                case 'qmail':
    13381314                    return $this->sendmailSend($this->MIMEHeader, $this->MIMEBody);
     
    13411317                case 'mail':
    13421318                    return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
    13431319                default:
    1344                     $sendMethod = $this->Mailer.'Send';
     1320                    $sendMethod = $this->Mailer . 'Send';
    13451321                    if (method_exists($this, $sendMethod)) {
    1346                         return $this->$sendMethod($this->MIMEHeader, $this->MIMEBody);
     1322                        return $this->$sendMethod($this->MIMEHeader, $this->MIMEBody);
    13471323                    }
    13481324
    13491325                    return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
    13501326            }
    1351         } catch (phpmailerException $exc) {
    1352             $this->setError($exc->getMessage());
    1353             $this->edebug($exc->getMessage());
    1354             if ($this->exceptions) {
    1355                 throw $exc;
    1356             }
    1357         }
    1358         return false;
    1359     }
    1360 
    1361     /**
    1362      * Send mail using the $Sendmail program.
    1363      * @param string $header The message headers
    1364      * @param string $body The message body
    1365      * @see PHPMailer::$Sendmail
    1366      * @throws phpmailerException
    1367      * @access protected
    1368      * @return boolean
    1369      */
    1370     protected function sendmailSend($header, $body)
    1371     {
    1372         // CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
    1373         if (!empty($this->Sender) and self::isShellSafe($this->Sender)) {
    1374             if ($this->Mailer == 'qmail') {
    1375                 $sendmailFmt = '%s -f%s';
    1376             } else {
    1377                 $sendmailFmt = '%s -oi -f%s -t';
    1378             }
    1379         } else {
    1380             if ($this->Mailer == 'qmail') {
    1381                 $sendmailFmt = '%s';
    1382             } else {
    1383                 $sendmailFmt = '%s -oi -t';
    1384             }
    1385         }
    1386 
    1387         // TODO: If possible, this should be changed to escapeshellarg.  Needs thorough testing.
    1388         $sendmail = sprintf($sendmailFmt, escapeshellcmd($this->Sendmail), $this->Sender);
    1389 
    1390         if ($this->SingleTo) {
    1391             foreach ($this->SingleToArray as $toAddr) {
    1392                 if (!@$mail = popen($sendmail, 'w')) {
    1393                     throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
    1394                 }
    1395                 fputs($mail, 'To: ' . $toAddr . "\n");
    1396                 fputs($mail, $header);
    1397                 fputs($mail, $body);
    1398                 $result = pclose($mail);
    1399                 $this->doCallback(
     1327                } catch (phpmailerException $exc) {
     1328                        $this->setError($exc->getMessage());
     1329                        $this->edebug($exc->getMessage());
     1330                        if ($this->exceptions) {
     1331                                throw $exc;
     1332                        }
     1333                }
     1334                return false;
     1335        }
     1336
     1337        /**
     1338         * Send mail using the $Sendmail program.
     1339         * @param string $header The message headers
     1340         * @param string $body The message body
     1341         * @see PHPMailer::$Sendmail
     1342         * @throws phpmailerException
     1343         * @access protected
     1344         * @return boolean
     1345         */
     1346        protected function sendmailSend($header, $body) {
     1347                // CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
     1348                if (!empty($this->Sender) and self::isShellSafe($this->Sender)) {
     1349                        if ($this->Mailer == 'qmail') {
     1350                                $sendmailFmt = '%s -f%s';
     1351                        } else {
     1352                                $sendmailFmt = '%s -oi -f%s -t';
     1353                        }
     1354                } else {
     1355                        if ($this->Mailer == 'qmail') {
     1356                                $sendmailFmt = '%s';
     1357                        } else {
     1358                                $sendmailFmt = '%s -oi -t';
     1359                        }
     1360                }
     1361
     1362                // TODO: If possible, this should be changed to escapeshellarg.  Needs thorough testing.
     1363                $sendmail = sprintf($sendmailFmt, escapeshellcmd($this->Sendmail), $this->Sender);
     1364
     1365                if ($this->SingleTo) {
     1366                        foreach ($this->SingleToArray as $toAddr) {
     1367                                if (!@$mail = popen($sendmail, 'w')) {
     1368                                        throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
     1369                                }
     1370                                fputs($mail, 'To: ' . $toAddr . "\n");
     1371                                fputs($mail, $header);
     1372                                fputs($mail, $body);
     1373                                $result = pclose($mail);
     1374                                $this->doCallback(
    14001375                    ($result == 0),
    14011376                    array($toAddr),
    14021377                    $this->cc,
     
    14051380                    $body,
    14061381                    $this->From
    14071382                );
    1408                 if ($result != 0) {
    1409                     throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
    1410                 }
    1411             }
    1412         } else {
    1413             if (!@$mail = popen($sendmail, 'w')) {
    1414                 throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
    1415             }
    1416             fputs($mail, $header);
    1417             fputs($mail, $body);
    1418             $result = pclose($mail);
    1419             $this->doCallback(
     1383                                if ($result != 0) {
     1384                                        throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
     1385                                }
     1386                        }
     1387                } else {
     1388                        if (!@$mail = popen($sendmail, 'w')) {
     1389                                throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
     1390                        }
     1391                        fputs($mail, $header);
     1392                        fputs($mail, $body);
     1393                        $result = pclose($mail);
     1394                        $this->doCallback(
    14201395                ($result == 0),
    14211396                $this->to,
    14221397                $this->cc,
     
    14251400                $body,
    14261401                $this->From
    14271402            );
    1428             if ($result != 0) {
    1429                 throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
    1430             }
    1431         }
    1432         return true;
    1433     }
    1434 
    1435     /**
    1436      * Fix CVE-2016-10033 and CVE-2016-10045 by disallowing potentially unsafe shell characters.
    1437      *
    1438      * Note that escapeshellarg and escapeshellcmd are inadequate for our purposes, especially on Windows.
    1439      * @param string $string The string to be validated
    1440      * @see https://github.com/PHPMailer/PHPMailer/issues/924 CVE-2016-10045 bug report
    1441      * @access protected
    1442      * @return boolean
    1443      */
    1444     protected static function isShellSafe($string)
    1445     {
    1446         // Future-proof
    1447         if (escapeshellcmd($string) !== $string
     1403                        if ($result != 0) {
     1404                                throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
     1405                        }
     1406                }
     1407                return true;
     1408        }
     1409
     1410        /**
     1411         * Fix CVE-2016-10033 and CVE-2016-10045 by disallowing potentially unsafe shell characters.
     1412         *
     1413         * Note that escapeshellarg and escapeshellcmd are inadequate for our purposes, especially on Windows.
     1414         * @param string $string The string to be validated
     1415         * @see https://github.com/PHPMailer/PHPMailer/issues/924 CVE-2016-10045 bug report
     1416         * @access protected
     1417         * @return boolean
     1418         */
     1419        protected static function isShellSafe($string) {
     1420                // Future-proof
     1421                if (escapeshellcmd($string) !== $string
    14481422            or !in_array(escapeshellarg($string), array("'$string'", "\"$string\""))
    14491423        ) {
    1450             return false;
    1451         }
    1452 
    1453         $length = strlen($string);
    1454 
    1455         for ($i = 0; $i < $length; $i++) {
    1456             $c = $string[$i];
    1457 
    1458             // All other characters have a special meaning in at least one common shell, including = and +.
    1459             // Full stop (.) has a special meaning in cmd.exe, but its impact should be negligible here.
    1460             // Note that this does permit non-Latin alphanumeric characters based on the current locale.
    1461             if (!ctype_alnum($c) && strpos('@_-.', $c) === false) {
    1462                 return false;
    1463             }
    1464         }
     1424                        return false;
     1425                }
    14651426
    1466         return true;
    1467     }
    1468 
    1469     /**
    1470      * Check whether a file path is of a permitted type.
    1471      * Used to reject URLs and phar files from functions that access local file paths,
    1472      * such as addAttachment.
    1473      * @param string $path A relative or absolute path to a file.
    1474      * @return bool
    1475      */
    1476     protected static function isPermittedPath($path)
    1477     {
    1478         return !preg_match('#^[a-z]+://#i', $path);
    1479     }
    1480 
    1481     /**
    1482      * Send mail using the PHP mail() function.
    1483      * @param string $header The message headers
    1484      * @param string $body The message body
    1485      * @link http://www.php.net/manual/en/book.mail.php
    1486      * @throws phpmailerException
    1487      * @access protected
    1488      * @return boolean
    1489      */
    1490     protected function mailSend($header, $body)
    1491     {
    1492         $toArr = array();
    1493         foreach ($this->to as $toaddr) {
    1494             $toArr[] = $this->addrFormat($toaddr);
    1495         }
    1496         $to = implode(', ', $toArr);
    1497 
    1498         $params = null;
    1499         //This sets the SMTP envelope sender which gets turned into a return-path header by the receiver
    1500         if (!empty($this->Sender) and $this->validateAddress($this->Sender)) {
    1501             // CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
    1502             if (self::isShellSafe($this->Sender)) {
    1503                 $params = sprintf('-f%s', $this->Sender);
    1504             }
    1505         }
    1506         if (!empty($this->Sender) and !ini_get('safe_mode') and $this->validateAddress($this->Sender)) {
    1507             $old_from = ini_get('sendmail_from');
    1508             ini_set('sendmail_from', $this->Sender);
    1509         }
    1510         $result = false;
    1511         if ($this->SingleTo and count($toArr) > 1) {
    1512             foreach ($toArr as $toAddr) {
    1513                 $result = $this->mailPassthru($toAddr, $this->Subject, $body, $header, $params);
    1514                 $this->doCallback($result, array($toAddr), $this->cc, $this->bcc, $this->Subject, $body, $this->From);
    1515             }
    1516         } else {
    1517             $result = $this->mailPassthru($to, $this->Subject, $body, $header, $params);
    1518             $this->doCallback($result, $this->to, $this->cc, $this->bcc, $this->Subject, $body, $this->From);
    1519         }
    1520         if (isset($old_from)) {
    1521             ini_set('sendmail_from', $old_from);
    1522         }
    1523         if (!$result) {
    1524             throw new phpmailerException($this->lang('instantiate'), self::STOP_CRITICAL);
    1525         }
    1526         return true;
    1527     }
    1528 
    1529     /**
    1530      * Get an instance to use for SMTP operations.
    1531      * Override this function to load your own SMTP implementation
    1532      * @return SMTP
    1533      */
    1534     public function getSMTPInstance()
    1535     {
    1536         if (!is_object($this->smtp)) {
    1537                         require_once( 'class-smtp.php' );
    1538             $this->smtp = new SMTP;
    1539         }
    1540         return $this->smtp;
    1541     }
    1542 
    1543     /**
    1544      * Send mail via SMTP.
    1545      * Returns false if there is a bad MAIL FROM, RCPT, or DATA input.
    1546      * Uses the PHPMailerSMTP class by default.
    1547      * @see PHPMailer::getSMTPInstance() to use a different class.
    1548      * @param string $header The message headers
    1549      * @param string $body The message body
    1550      * @throws phpmailerException
    1551      * @uses SMTP
    1552      * @access protected
    1553      * @return boolean
    1554      */
    1555     protected function smtpSend($header, $body)
    1556     {
    1557         $bad_rcpt = array();
    1558         if (!$this->smtpConnect($this->SMTPOptions)) {
    1559             throw new phpmailerException($this->lang('smtp_connect_failed'), self::STOP_CRITICAL);
    1560         }
    1561         if (!empty($this->Sender) and $this->validateAddress($this->Sender)) {
    1562             $smtp_from = $this->Sender;
    1563         } else {
    1564             $smtp_from = $this->From;
    1565         }
    1566         if (!$this->smtp->mail($smtp_from)) {
    1567             $this->setError($this->lang('from_failed') . $smtp_from . ' : ' . implode(',', $this->smtp->getError()));
    1568             throw new phpmailerException($this->ErrorInfo, self::STOP_CRITICAL);
    1569         }
     1427                $length = strlen($string);
    15701428
    1571         // Attempt to send to all recipients
    1572         foreach (array($this->to, $this->cc, $this->bcc) as $togroup) {
    1573             foreach ($togroup as $to) {
    1574                 if (!$this->smtp->recipient($to[0])) {
    1575                     $error = $this->smtp->getError();
    1576                     $bad_rcpt[] = array('to' => $to[0], 'error' => $error['detail']);
    1577                     $isSent = false;
    1578                 } else {
    1579                     $isSent = true;
    1580                 }
    1581                 $this->doCallback($isSent, array($to[0]), array(), array(), $this->Subject, $body, $this->From);
    1582             }
    1583         }
     1429                for ($i = 0; $i < $length; $i++) {
     1430                        $c = $string[$i];
    15841431
    1585         // Only send the DATA command if we have viable recipients
    1586         if ((count($this->all_recipients) > count($bad_rcpt)) and !$this->smtp->data($header . $body)) {
    1587             throw new phpmailerException($this->lang('data_not_accepted'), self::STOP_CRITICAL);
    1588         }
    1589         if ($this->SMTPKeepAlive) {
    1590             $this->smtp->reset();
    1591         } else {
    1592             $this->smtp->quit();
    1593             $this->smtp->close();
    1594         }
    1595         //Create error message for any bad addresses
    1596         if (count($bad_rcpt) > 0) {
    1597             $errstr = '';
    1598             foreach ($bad_rcpt as $bad) {
    1599                 $errstr .= $bad['to'] . ': ' . $bad['error'];
    1600             }
    1601             throw new phpmailerException(
     1432                        // All other characters have a special meaning in at least one common shell, including = and +.
     1433                        // Full stop (.) has a special meaning in cmd.exe, but its impact should be negligible here.
     1434                        // Note that this does permit non-Latin alphanumeric characters based on the current locale.
     1435                        if (!ctype_alnum($c) && strpos('@_-.', $c) === false) {
     1436                                return false;
     1437                        }
     1438                }
     1439
     1440                return true;
     1441        }
     1442
     1443        /**
     1444         * Check whether a file path is of a permitted type.
     1445         * Used to reject URLs and phar files from functions that access local file paths,
     1446         * such as addAttachment.
     1447         * @param string $path A relative or absolute path to a file.
     1448         * @return bool
     1449         */
     1450        protected static function isPermittedPath($path) {
     1451                return !preg_match('#^[a-z]+://#i', $path);
     1452        }
     1453
     1454        /**
     1455         * Send mail using the PHP mail() function.
     1456         * @param string $header The message headers
     1457         * @param string $body The message body
     1458         * @link http://www.php.net/manual/en/book.mail.php
     1459         * @throws phpmailerException
     1460         * @access protected
     1461         * @return boolean
     1462         */
     1463        protected function mailSend($header, $body) {
     1464                $toArr = array();
     1465                foreach ($this->to as $toaddr) {
     1466                        $toArr[] = $this->addrFormat($toaddr);
     1467                }
     1468                $to = implode(', ', $toArr);
     1469
     1470                $params = null;
     1471                //This sets the SMTP envelope sender which gets turned into a return-path header by the receiver
     1472                if (!empty($this->Sender) and $this->validateAddress($this->Sender)) {
     1473                        // CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
     1474                        if (self::isShellSafe($this->Sender)) {
     1475                                $params = sprintf('-f%s', $this->Sender);
     1476                        }
     1477                }
     1478                if (!empty($this->Sender) and !ini_get('safe_mode') and $this->validateAddress($this->Sender)) {
     1479                        $old_from = ini_get('sendmail_from');
     1480                        ini_set('sendmail_from', $this->Sender);
     1481                }
     1482                $result = false;
     1483                if ($this->SingleTo and count($toArr) > 1) {
     1484                        foreach ($toArr as $toAddr) {
     1485                                $result = $this->mailPassthru($toAddr, $this->Subject, $body, $header, $params);
     1486                                $this->doCallback($result, array($toAddr), $this->cc, $this->bcc, $this->Subject, $body, $this->From);
     1487                        }
     1488                } else {
     1489                        $result = $this->mailPassthru($to, $this->Subject, $body, $header, $params);
     1490                        $this->doCallback($result, $this->to, $this->cc, $this->bcc, $this->Subject, $body, $this->From);
     1491                }
     1492                if (isset($old_from)) {
     1493                        ini_set('sendmail_from', $old_from);
     1494                }
     1495                if (!$result) {
     1496                        throw new phpmailerException($this->lang('instantiate'), self::STOP_CRITICAL);
     1497                }
     1498                return true;
     1499        }
     1500
     1501        /**
     1502         * Get an instance to use for SMTP operations.
     1503         * Override this function to load your own SMTP implementation
     1504         * @return SMTP
     1505         */
     1506        public function getSMTPInstance() {
     1507                if (!is_object($this->smtp)) {
     1508                        require_once 'class-smtp.php';
     1509                        $this->smtp = new SMTP;
     1510                }
     1511                return $this->smtp;
     1512        }
     1513
     1514        /**
     1515         * Send mail via SMTP.
     1516         * Returns false if there is a bad MAIL FROM, RCPT, or DATA input.
     1517         * Uses the PHPMailerSMTP class by default.
     1518         * @see PHPMailer::getSMTPInstance() to use a different class.
     1519         * @param string $header The message headers
     1520         * @param string $body The message body
     1521         * @throws phpmailerException
     1522         * @uses SMTP
     1523         * @access protected
     1524         * @return boolean
     1525         */
     1526        protected function smtpSend($header, $body) {
     1527                $bad_rcpt = array();
     1528                if (!$this->smtpConnect($this->SMTPOptions)) {
     1529                        throw new phpmailerException($this->lang('smtp_connect_failed'), self::STOP_CRITICAL);
     1530                }
     1531                if (!empty($this->Sender) and $this->validateAddress($this->Sender)) {
     1532                        $smtp_from = $this->Sender;
     1533                } else {
     1534                        $smtp_from = $this->From;
     1535                }
     1536                if (!$this->smtp->mail($smtp_from)) {
     1537                        $this->setError($this->lang('from_failed') . $smtp_from . ' : ' . implode(',', $this->smtp->getError()));
     1538                        throw new phpmailerException($this->ErrorInfo, self::STOP_CRITICAL);
     1539                }
     1540
     1541                // Attempt to send to all recipients
     1542                foreach (array($this->to, $this->cc, $this->bcc) as $togroup) {
     1543                        foreach ($togroup as $to) {
     1544                                if (!$this->smtp->recipient($to[0])) {
     1545                                        $error      = $this->smtp->getError();
     1546                                        $bad_rcpt[] = array('to' => $to[0], 'error' => $error['detail']);
     1547                                        $isSent     = false;
     1548                                } else {
     1549                                        $isSent = true;
     1550                                }
     1551                                $this->doCallback($isSent, array($to[0]), array(), array(), $this->Subject, $body, $this->From);
     1552                        }
     1553                }
     1554
     1555                // Only send the DATA command if we have viable recipients
     1556                if ((count($this->all_recipients) > count($bad_rcpt)) and !$this->smtp->data($header . $body)) {
     1557                        throw new phpmailerException($this->lang('data_not_accepted'), self::STOP_CRITICAL);
     1558                }
     1559                if ($this->SMTPKeepAlive) {
     1560                        $this->smtp->reset();
     1561                } else {
     1562                        $this->smtp->quit();
     1563                        $this->smtp->close();
     1564                }
     1565                //Create error message for any bad addresses
     1566                if (count($bad_rcpt) > 0) {
     1567                        $errstr = '';
     1568                        foreach ($bad_rcpt as $bad) {
     1569                                $errstr .= $bad['to'] . ': ' . $bad['error'];
     1570                        }
     1571                        throw new phpmailerException(
    16021572                $this->lang('recipients_failed') . $errstr,
    16031573                self::STOP_CONTINUE
    16041574            );
    1605         }
    1606         return true;
    1607     }
    1608 
    1609     /**
    1610      * Initiate a connection to an SMTP server.
    1611      * Returns false if the operation failed.
    1612      * @param array $options An array of options compatible with stream_context_create()
    1613      * @uses SMTP
    1614      * @access public
    1615      * @throws phpmailerException
    1616      * @return boolean
    1617      */
    1618     public function smtpConnect($options = null)
    1619     {
    1620         if (is_null($this->smtp)) {
    1621             $this->smtp = $this->getSMTPInstance();
    1622         }
    1623 
    1624         //If no options are provided, use whatever is set in the instance
    1625         if (is_null($options)) {
    1626             $options = $this->SMTPOptions;
    1627         }
    1628 
    1629         // Already connected?
    1630         if ($this->smtp->connected()) {
    1631             return true;
    1632         }
    1633 
    1634         $this->smtp->setTimeout($this->Timeout);
    1635         $this->smtp->setDebugLevel($this->SMTPDebug);
    1636         $this->smtp->setDebugOutput($this->Debugoutput);
    1637         $this->smtp->setVerp($this->do_verp);
    1638         $hosts = explode(';', $this->Host);
    1639         $lastexception = null;
    1640 
    1641         foreach ($hosts as $hostentry) {
    1642             $hostinfo = array();
    1643             if (!preg_match(
     1575                }
     1576                return true;
     1577        }
     1578
     1579        /**
     1580         * Initiate a connection to an SMTP server.
     1581         * Returns false if the operation failed.
     1582         * @param array $options An array of options compatible with stream_context_create()
     1583         * @uses SMTP
     1584         * @access public
     1585         * @throws phpmailerException
     1586         * @return boolean
     1587         */
     1588        public function smtpConnect($options = null) {
     1589                if (is_null($this->smtp)) {
     1590                        $this->smtp = $this->getSMTPInstance();
     1591                }
     1592
     1593                //If no options are provided, use whatever is set in the instance
     1594                if (is_null($options)) {
     1595                        $options = $this->SMTPOptions;
     1596                }
     1597
     1598                // Already connected?
     1599                if ($this->smtp->connected()) {
     1600                        return true;
     1601                }
     1602
     1603                $this->smtp->setTimeout($this->Timeout);
     1604                $this->smtp->setDebugLevel($this->SMTPDebug);
     1605                $this->smtp->setDebugOutput($this->Debugoutput);
     1606                $this->smtp->setVerp($this->do_verp);
     1607                $hosts         = explode(';', $this->Host);
     1608                $lastexception = null;
     1609
     1610                foreach ($hosts as $hostentry) {
     1611                        $hostinfo = array();
     1612                        if (!preg_match(
    16441613                '/^((ssl|tls):\/\/)*([a-zA-Z0-9\.-]*|\[[a-fA-F0-9:]+\]):?([0-9]*)$/',
    16451614                trim($hostentry),
    16461615                $hostinfo
    16471616            )) {
    1648                 // Not a valid host entry
    1649                 $this->edebug('Ignoring invalid host: ' . $hostentry);
    1650                 continue;
    1651             }
    1652             // $hostinfo[2]: optional ssl or tls prefix
    1653             // $hostinfo[3]: the hostname
    1654             // $hostinfo[4]: optional port number
    1655             // The host string prefix can temporarily override the current setting for SMTPSecure
    1656             // If it's not specified, the default value is used
    1657             $prefix = '';
    1658             $secure = $this->SMTPSecure;
    1659             $tls = ($this->SMTPSecure == 'tls');
    1660             if ('ssl' == $hostinfo[2] or ('' == $hostinfo[2] and 'ssl' == $this->SMTPSecure)) {
    1661                 $prefix = 'ssl://';
    1662                 $tls = false; // Can't have SSL and TLS at the same time
    1663                 $secure = 'ssl';
    1664             } elseif ($hostinfo[2] == 'tls') {
    1665                 $tls = true;
    1666                 // tls doesn't use a prefix
    1667                 $secure = 'tls';
    1668             }
    1669             //Do we need the OpenSSL extension?
    1670             $sslext = defined('OPENSSL_ALGO_SHA1');
    1671             if ('tls' === $secure or 'ssl' === $secure) {
    1672                 //Check for an OpenSSL constant rather than using extension_loaded, which is sometimes disabled
    1673                 if (!$sslext) {
    1674                     throw new phpmailerException($this->lang('extension_missing').'openssl', self::STOP_CRITICAL);
    1675                 }
    1676             }
    1677             $host = $hostinfo[3];
    1678             $port = $this->Port;
    1679             $tport = (integer)$hostinfo[4];
    1680             if ($tport > 0 and $tport < 65536) {
    1681                 $port = $tport;
    1682             }
    1683             if ($this->smtp->connect($prefix . $host, $port, $this->Timeout, $options)) {
    1684                 try {
    1685                     if ($this->Helo) {
    1686                         $hello = $this->Helo;
    1687                     } else {
    1688                         $hello = $this->serverHostname();
    1689                     }
    1690                     $this->smtp->hello($hello);
    1691                     //Automatically enable TLS encryption if:
    1692                     // * it's not disabled
    1693                     // * we have openssl extension
    1694                     // * we are not already using SSL
    1695                     // * the server offers STARTTLS
    1696                     if ($this->SMTPAutoTLS and $sslext and $secure != 'ssl' and $this->smtp->getServerExt('STARTTLS')) {
    1697                         $tls = true;
    1698                     }
    1699                     if ($tls) {
    1700                         if (!$this->smtp->startTLS()) {
    1701                             throw new phpmailerException($this->lang('connect_host'));
    1702                         }
    1703                         // We must resend EHLO after TLS negotiation
    1704                         $this->smtp->hello($hello);
    1705                     }
    1706                     if ($this->SMTPAuth) {
    1707                         if (!$this->smtp->authenticate(
     1617                                // Not a valid host entry
     1618                                $this->edebug('Ignoring invalid host: ' . $hostentry);
     1619                                continue;
     1620                        }
     1621                        // $hostinfo[2]: optional ssl or tls prefix
     1622                        // $hostinfo[3]: the hostname
     1623                        // $hostinfo[4]: optional port number
     1624                        // The host string prefix can temporarily override the current setting for SMTPSecure
     1625                        // If it's not specified, the default value is used
     1626                        $prefix = '';
     1627                        $secure = $this->SMTPSecure;
     1628                        $tls    = ($this->SMTPSecure == 'tls');
     1629                        if ('ssl' == $hostinfo[2] or ('' == $hostinfo[2] and 'ssl' == $this->SMTPSecure)) {
     1630                                $prefix = 'ssl://';
     1631                                $tls    = false; // Can't have SSL and TLS at the same time
     1632                                $secure = 'ssl';
     1633                        } elseif ($hostinfo[2] == 'tls') {
     1634                                $tls = true;
     1635                                // tls doesn't use a prefix
     1636                                $secure = 'tls';
     1637                        }
     1638                        //Do we need the OpenSSL extension?
     1639                        $sslext = defined('OPENSSL_ALGO_SHA1');
     1640                        if ('tls' === $secure or 'ssl' === $secure) {
     1641                                //Check for an OpenSSL constant rather than using extension_loaded, which is sometimes disabled
     1642                                if (!$sslext) {
     1643                                        throw new phpmailerException($this->lang('extension_missing') . 'openssl', self::STOP_CRITICAL);
     1644                                }
     1645                        }
     1646                        $host = $hostinfo[3];
     1647                        $port = $this->Port;
     1648                        $tport = (integer) $hostinfo[4];
     1649                        if ($tport > 0 and $tport < 65536) {
     1650                                $port = $tport;
     1651                        }
     1652                        if ($this->smtp->connect($prefix . $host, $port, $this->Timeout, $options)) {
     1653                                try {
     1654                                        if ($this->Helo) {
     1655                                                $hello = $this->Helo;
     1656                                        } else {
     1657                                                $hello = $this->serverHostname();
     1658                                        }
     1659                                        $this->smtp->hello($hello);
     1660                                        //Automatically enable TLS encryption if:
     1661                                        // * it's not disabled
     1662                                        // * we have openssl extension
     1663                                        // * we are not already using SSL
     1664                                        // * the server offers STARTTLS
     1665                                        if ($this->SMTPAutoTLS and $sslext and $secure != 'ssl' and $this->smtp->getServerExt('STARTTLS')) {
     1666                                                $tls = true;
     1667                                        }
     1668                                        if ($tls) {
     1669                                                if (!$this->smtp->startTLS()) {
     1670                                                        throw new phpmailerException($this->lang('connect_host'));
     1671                                                }
     1672                                                // We must resend EHLO after TLS negotiation
     1673                                                $this->smtp->hello($hello);
     1674                                        }
     1675                                        if ($this->SMTPAuth) {
     1676                                                if (!$this->smtp->authenticate(
    17081677                            $this->Username,
    17091678                            $this->Password,
    17101679                            $this->AuthType,
     
    17121681                            $this->Workstation
    17131682                        )
    17141683                        ) {
    1715                             throw new phpmailerException($this->lang('authenticate'));
    1716                         }
    1717                     }
    1718                     return true;
    1719                 } catch (phpmailerException $exc) {
    1720                     $lastexception = $exc;
    1721                     $this->edebug($exc->getMessage());
    1722                     // We must have connected, but then failed TLS or Auth, so close connection nicely
    1723                     $this->smtp->quit();
    1724                 }
    1725             }
    1726         }
    1727         // If we get here, all connection attempts have failed, so close connection hard
    1728         $this->smtp->close();
    1729         // As we've caught all exceptions, just report whatever the last one was
    1730         if ($this->exceptions and !is_null($lastexception)) {
    1731             throw $lastexception;
    1732         }
    1733         return false;
    1734     }
    1735 
    1736     /**
    1737      * Close the active SMTP session if one exists.
    1738      * @return void
    1739      */
    1740     public function smtpClose()
    1741     {
    1742         if (is_a($this->smtp, 'SMTP')) {
    1743             if ($this->smtp->connected()) {
    1744                 $this->smtp->quit();
    1745                 $this->smtp->close();
    1746             }
    1747         }
    1748     }
    1749 
    1750     /**
    1751      * Set the language for error messages.
    1752      * Returns false if it cannot load the language file.
    1753      * The default language is English.
    1754      * @param string $langcode ISO 639-1 2-character language code (e.g. French is "fr")
    1755      * @param string $lang_path Path to the language file directory, with trailing separator (slash)
    1756      * @return boolean
    1757      * @access public
    1758      */
    1759     public function setLanguage($langcode = 'en', $lang_path = '')
    1760     {
    1761         // Backwards compatibility for renamed language codes
    1762         $renamed_langcodes = array(
    1763             'br' => 'pt_br',
    1764             'cz' => 'cs',
    1765             'dk' => 'da',
    1766             'no' => 'nb',
    1767             'se' => 'sv',
    1768             'sr' => 'rs'
    1769         );
    1770 
    1771         if (isset($renamed_langcodes[$langcode])) {
    1772             $langcode = $renamed_langcodes[$langcode];
    1773         }
    1774 
    1775         // Define full set of translatable strings in English
    1776         $PHPMAILER_LANG = array(
    1777             'authenticate' => 'SMTP Error: Could not authenticate.',
    1778             'connect_host' => 'SMTP Error: Could not connect to SMTP host.',
    1779             'data_not_accepted' => 'SMTP Error: data not accepted.',
    1780             'empty_message' => 'Message body empty',
    1781             'encoding' => 'Unknown encoding: ',
    1782             'execute' => 'Could not execute: ',
    1783             'file_access' => 'Could not access file: ',
    1784             'file_open' => 'File Error: Could not open file: ',
    1785             'from_failed' => 'The following From address failed: ',
    1786             'instantiate' => 'Could not instantiate mail function.',
    1787             'invalid_address' => 'Invalid address: ',
    1788             'mailer_not_supported' => ' mailer is not supported.',
    1789             'provide_address' => 'You must provide at least one recipient email address.',
    1790             'recipients_failed' => 'SMTP Error: The following recipients failed: ',
    1791             'signing' => 'Signing Error: ',
    1792             'smtp_connect_failed' => 'SMTP connect() failed.',
    1793             'smtp_error' => 'SMTP server error: ',
    1794             'variable_set' => 'Cannot set or reset variable: ',
    1795             'extension_missing' => 'Extension missing: '
    1796         );
    1797         if (empty($lang_path)) {
    1798             // Calculate an absolute path so it can work if CWD is not here
    1799             $lang_path = dirname(__FILE__). DIRECTORY_SEPARATOR . 'language'. DIRECTORY_SEPARATOR;
    1800         }
    1801         //Validate $langcode
    1802         if (!preg_match('/^[a-z]{2}(?:_[a-zA-Z]{2})?$/', $langcode)) {
    1803             $langcode = 'en';
    1804         }
    1805         $foundlang = true;
    1806         $lang_file = $lang_path . 'phpmailer.lang-' . $langcode . '.php';
    1807         // There is no English translation file
    1808         if ($langcode != 'en') {
    1809             // Make sure language file path is readable
    1810             if (!self::isPermittedPath($lang_file) or !is_readable($lang_file)) {
    1811                 $foundlang = false;
    1812             } else {
    1813                 // Overwrite language-specific strings.
    1814                 // This way we'll never have missing translation keys.
    1815                 $foundlang = include $lang_file;
    1816             }
    1817         }
    1818         $this->language = $PHPMAILER_LANG;
    1819         return (boolean)$foundlang; // Returns false if language not found
    1820     }
    1821 
    1822     /**
    1823      * Get the array of strings for the current language.
    1824      * @return array
    1825      */
    1826     public function getTranslations()
    1827     {
    1828         return $this->language;
    1829     }
    1830 
    1831     /**
    1832      * Create recipient headers.
    1833      * @access public
    1834      * @param string $type
    1835      * @param array $addr An array of recipient,
    1836      * where each recipient is a 2-element indexed array with element 0 containing an address
    1837      * and element 1 containing a name, like:
    1838      * array(array('joe@example.com', 'Joe User'), array('zoe@example.com', 'Zoe User'))
    1839      * @return string
    1840      */
    1841     public function addrAppend($type, $addr)
    1842     {
    1843         $addresses = array();
    1844         foreach ($addr as $address) {
    1845             $addresses[] = $this->addrFormat($address);
    1846         }
    1847         return $type . ': ' . implode(', ', $addresses) . $this->LE;
    1848     }
    1849 
    1850     /**
    1851      * Format an address for use in a message header.
    1852      * @access public
    1853      * @param array $addr A 2-element indexed array, element 0 containing an address, element 1 containing a name
    1854      *      like array('joe@example.com', 'Joe User')
    1855      * @return string
    1856      */
    1857     public function addrFormat($addr)
    1858     {
    1859         if (empty($addr[1])) { // No name provided
    1860             return $this->secureHeader($addr[0]);
    1861         } else {
    1862             return $this->encodeHeader($this->secureHeader($addr[1]), 'phrase') . ' <' . $this->secureHeader(
     1684                                                        throw new phpmailerException($this->lang('authenticate'));
     1685                                                }
     1686                                        }
     1687                                        return true;
     1688                                } catch (phpmailerException $exc) {
     1689                                        $lastexception = $exc;
     1690                                        $this->edebug($exc->getMessage());
     1691                                        // We must have connected, but then failed TLS or Auth, so close connection nicely
     1692                                        $this->smtp->quit();
     1693                                }
     1694                        }
     1695                }
     1696                // If we get here, all connection attempts have failed, so close connection hard
     1697                $this->smtp->close();
     1698                // As we've caught all exceptions, just report whatever the last one was
     1699                if ($this->exceptions and !is_null($lastexception)) {
     1700                        throw $lastexception;
     1701                }
     1702                return false;
     1703        }
     1704
     1705        /**
     1706         * Close the active SMTP session if one exists.
     1707         * @return void
     1708         */
     1709        public function smtpClose() {
     1710                if (is_a($this->smtp, 'SMTP')) {
     1711                        if ($this->smtp->connected()) {
     1712                                $this->smtp->quit();
     1713                                $this->smtp->close();
     1714                        }
     1715                }
     1716        }
     1717
     1718        /**
     1719         * Set the language for error messages.
     1720         * Returns false if it cannot load the language file.
     1721         * The default language is English.
     1722         * @param string $langcode ISO 639-1 2-character language code (e.g. French is "fr")
     1723         * @param string $lang_path Path to the language file directory, with trailing separator (slash)
     1724         * @return boolean
     1725         * @access public
     1726         */
     1727        public function setLanguage($langcode = 'en', $lang_path = '') {
     1728                // Backwards compatibility for renamed language codes
     1729                $renamed_langcodes = array(
     1730                        'br' => 'pt_br',
     1731                        'cz' => 'cs',
     1732                        'dk' => 'da',
     1733                        'no' => 'nb',
     1734                        'se' => 'sv',
     1735                        'sr' => 'rs',
     1736                );
     1737
     1738                if (isset($renamed_langcodes[$langcode])) {
     1739                        $langcode = $renamed_langcodes[$langcode];
     1740                }
     1741
     1742                // Define full set of translatable strings in English
     1743                $PHPMAILER_LANG = array(
     1744                        'authenticate'         => 'SMTP Error: Could not authenticate.',
     1745                        'connect_host'         => 'SMTP Error: Could not connect to SMTP host.',
     1746                        'data_not_accepted'    => 'SMTP Error: data not accepted.',
     1747                        'empty_message'        => 'Message body empty',
     1748                        'encoding'             => 'Unknown encoding: ',
     1749                        'execute'              => 'Could not execute: ',
     1750                        'file_access'          => 'Could not access file: ',
     1751                        'file_open'            => 'File Error: Could not open file: ',
     1752                        'from_failed'          => 'The following From address failed: ',
     1753                        'instantiate'          => 'Could not instantiate mail function.',
     1754                        'invalid_address'      => 'Invalid address: ',
     1755                        'mailer_not_supported' => ' mailer is not supported.',
     1756                        'provide_address'      => 'You must provide at least one recipient email address.',
     1757                        'recipients_failed'    => 'SMTP Error: The following recipients failed: ',
     1758                        'signing'              => 'Signing Error: ',
     1759                        'smtp_connect_failed'  => 'SMTP connect() failed.',
     1760                        'smtp_error'           => 'SMTP server error: ',
     1761                        'variable_set'         => 'Cannot set or reset variable: ',
     1762                        'extension_missing'    => 'Extension missing: ',
     1763                );
     1764                if (empty($lang_path)) {
     1765                        // Calculate an absolute path so it can work if CWD is not here
     1766                        $lang_path = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'language' . DIRECTORY_SEPARATOR;
     1767                }
     1768                //Validate $langcode
     1769                if (!preg_match('/^[a-z]{2}(?:_[a-zA-Z]{2})?$/', $langcode)) {
     1770                        $langcode = 'en';
     1771                }
     1772                $foundlang = true;
     1773                $lang_file = $lang_path . 'phpmailer.lang-' . $langcode . '.php';
     1774                // There is no English translation file
     1775                if ($langcode != 'en') {
     1776                        // Make sure language file path is readable
     1777                        if (!self::isPermittedPath($lang_file) or !is_readable($lang_file)) {
     1778                                $foundlang = false;
     1779                        } else {
     1780                                // Overwrite language-specific strings.
     1781                                // This way we'll never have missing translation keys.
     1782                                $foundlang = include $lang_file;
     1783                        }
     1784                }
     1785                $this->language = $PHPMAILER_LANG;
     1786                return (boolean) $foundlang; // Returns false if language not found
     1787        }
     1788
     1789        /**
     1790         * Get the array of strings for the current language.
     1791         * @return array
     1792         */
     1793        public function getTranslations() {
     1794                return $this->language;
     1795        }
     1796
     1797        /**
     1798         * Create recipient headers.
     1799         * @access public
     1800         * @param string $type
     1801         * @param array $addr An array of recipient,
     1802         * where each recipient is a 2-element indexed array with element 0 containing an address
     1803         * and element 1 containing a name, like:
     1804         * array(array('joe@example.com', 'Joe User'), array('zoe@example.com', 'Zoe User'))
     1805         * @return string
     1806         */
     1807        public function addrAppend($type, $addr) {
     1808                $addresses = array();
     1809                foreach ($addr as $address) {
     1810                        $addresses[] = $this->addrFormat($address);
     1811                }
     1812                return $type . ': ' . implode(', ', $addresses) . $this->LE;
     1813        }
     1814
     1815        /**
     1816         * Format an address for use in a message header.
     1817         * @access public
     1818         * @param array $addr A 2-element indexed array, element 0 containing an address, element 1 containing a name
     1819         *      like array('joe@example.com', 'Joe User')
     1820         * @return string
     1821         */
     1822        public function addrFormat($addr) {
     1823                if (empty($addr[1])) { // No name provided
     1824                        return $this->secureHeader($addr[0]);
     1825                } else {
     1826                        return $this->encodeHeader($this->secureHeader($addr[1]), 'phrase') . ' <' . $this->secureHeader(
    18631827                $addr[0]
    18641828            ) . '>';
    1865         }
    1866     }
    1867 
    1868     /**
    1869      * Word-wrap message.
    1870      * For use with mailers that do not automatically perform wrapping
    1871      * and for quoted-printable encoded messages.
    1872      * Original written by philippe.
    1873      * @param string $message The message to wrap
    1874      * @param integer $length The line length to wrap to
    1875      * @param boolean $qp_mode Whether to run in Quoted-Printable mode
    1876      * @access public
    1877      * @return string
    1878      */
    1879     public function wrapText($message, $length, $qp_mode = false)
    1880     {
    1881         if ($qp_mode) {
    1882             $soft_break = sprintf(' =%s', $this->LE);
    1883         } else {
    1884             $soft_break = $this->LE;
    1885         }
    1886         // If utf-8 encoding is used, we will need to make sure we don't
    1887         // split multibyte characters when we wrap
    1888         $is_utf8 = (strtolower($this->CharSet) == 'utf-8');
    1889         $lelen = strlen($this->LE);
    1890         $crlflen = strlen(self::CRLF);
    1891 
    1892         $message = $this->fixEOL($message);
    1893         //Remove a trailing line break
    1894         if (substr($message, -$lelen) == $this->LE) {
    1895             $message = substr($message, 0, -$lelen);
    1896         }
    1897 
    1898         //Split message into lines
    1899         $lines = explode($this->LE, $message);
    1900         //Message will be rebuilt in here
    1901         $message = '';
    1902         foreach ($lines as $line) {
    1903             $words = explode(' ', $line);
    1904             $buf = '';
    1905             $firstword = true;
    1906             foreach ($words as $word) {
    1907                 if ($qp_mode and (strlen($word) > $length)) {
    1908                     $space_left = $length - strlen($buf) - $crlflen;
    1909                     if (!$firstword) {
    1910                         if ($space_left > 20) {
    1911                             $len = $space_left;
    1912                             if ($is_utf8) {
    1913                                 $len = $this->utf8CharBoundary($word, $len);
    1914                             } elseif (substr($word, $len - 1, 1) == '=') {
    1915                                 $len--;
    1916                             } elseif (substr($word, $len - 2, 1) == '=') {
    1917                                 $len -= 2;
    1918                             }
    1919                             $part = substr($word, 0, $len);
    1920                             $word = substr($word, $len);
    1921                             $buf .= ' ' . $part;
    1922                             $message .= $buf . sprintf('=%s', self::CRLF);
    1923                         } else {
    1924                             $message .= $buf . $soft_break;
    1925                         }
    1926                         $buf = '';
    1927                     }
    1928                     while (strlen($word) > 0) {
    1929                         if ($length <= 0) {
    1930                             break;
    1931                         }
    1932                         $len = $length;
    1933                         if ($is_utf8) {
    1934                             $len = $this->utf8CharBoundary($word, $len);
    1935                         } elseif (substr($word, $len - 1, 1) == '=') {
    1936                             $len--;
    1937                         } elseif (substr($word, $len - 2, 1) == '=') {
    1938                             $len -= 2;
    1939                         }
    1940                         $part = substr($word, 0, $len);
    1941                         $word = substr($word, $len);
    1942 
    1943                         if (strlen($word) > 0) {
    1944                             $message .= $part . sprintf('=%s', self::CRLF);
    1945                         } else {
    1946                             $buf = $part;
    1947                         }
    1948                     }
    1949                 } else {
    1950                     $buf_o = $buf;
    1951                     if (!$firstword) {
    1952                         $buf .= ' ';
    1953                     }
    1954                     $buf .= $word;
     1829                }
     1830        }
    19551831
    1956                     if (strlen($buf) > $length and $buf_o != '') {
    1957                         $message .= $buf_o . $soft_break;
    1958                         $buf = $word;
    1959                     }
    1960                 }
    1961                 $firstword = false;
    1962             }
    1963             $message .= $buf . self::CRLF;
    1964         }
    1965 
    1966         return $message;
    1967     }
    1968 
    1969     /**
    1970      * Find the last character boundary prior to $maxLength in a utf-8
    1971      * quoted-printable encoded string.
    1972      * Original written by Colin Brown.
    1973      * @access public
    1974      * @param string $encodedText utf-8 QP text
    1975      * @param integer $maxLength Find the last character boundary prior to this length
    1976      * @return integer
    1977      */
    1978     public function utf8CharBoundary($encodedText, $maxLength)
    1979     {
    1980         $foundSplitPos = false;
    1981         $lookBack = 3;
    1982         while (!$foundSplitPos) {
    1983             $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack);
    1984             $encodedCharPos = strpos($lastChunk, '=');
    1985             if (false !== $encodedCharPos) {
    1986                 // Found start of encoded character byte within $lookBack block.
    1987                 // Check the encoded byte value (the 2 chars after the '=')
    1988                 $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2);
    1989                 $dec = hexdec($hex);
    1990                 if ($dec < 128) {
    1991                     // Single byte character.
    1992                     // If the encoded char was found at pos 0, it will fit
    1993                     // otherwise reduce maxLength to start of the encoded char
    1994                     if ($encodedCharPos > 0) {
    1995                         $maxLength = $maxLength - ($lookBack - $encodedCharPos);
    1996                     }
    1997                     $foundSplitPos = true;
    1998                 } elseif ($dec >= 192) {
    1999                     // First byte of a multi byte character
    2000                     // Reduce maxLength to split at start of character
    2001                     $maxLength = $maxLength - ($lookBack - $encodedCharPos);
    2002                     $foundSplitPos = true;
    2003                 } elseif ($dec < 192) {
    2004                     // Middle byte of a multi byte character, look further back
    2005                     $lookBack += 3;
    2006                 }
    2007             } else {
    2008                 // No encoded character found
    2009                 $foundSplitPos = true;
    2010             }
    2011         }
    2012         return $maxLength;
    2013     }
     1832        /**
     1833         * Word-wrap message.
     1834         * For use with mailers that do not automatically perform wrapping
     1835         * and for quoted-printable encoded messages.
     1836         * Original written by philippe.
     1837         * @param string $message The message to wrap
     1838         * @param integer $length The line length to wrap to
     1839         * @param boolean $qp_mode Whether to run in Quoted-Printable mode
     1840         * @access public
     1841         * @return string
     1842         */
     1843        public function wrapText($message, $length, $qp_mode = false) {
     1844                if ($qp_mode) {
     1845                        $soft_break = sprintf(' =%s', $this->LE);
     1846                } else {
     1847                        $soft_break = $this->LE;
     1848                }
     1849                // If utf-8 encoding is used, we will need to make sure we don't
     1850                // split multibyte characters when we wrap
     1851                $is_utf8 = (strtolower($this->CharSet) == 'utf-8');
     1852                $lelen   = strlen($this->LE);
     1853                $crlflen = strlen(self::CRLF);
     1854
     1855                $message = $this->fixEOL($message);
     1856                //Remove a trailing line break
     1857                if (substr($message, -$lelen) == $this->LE) {
     1858                        $message = substr($message, 0, -$lelen);
     1859                }
     1860
     1861                //Split message into lines
     1862                $lines = explode($this->LE, $message);
     1863                //Message will be rebuilt in here
     1864                $message = '';
     1865                foreach ($lines as $line) {
     1866                        $words     = explode(' ', $line);
     1867                        $buf       = '';
     1868                        $firstword = true;
     1869                        foreach ($words as $word) {
     1870                                if ($qp_mode and (strlen($word) > $length)) {
     1871                                        $space_left = $length - strlen($buf) - $crlflen;
     1872                                        if (!$firstword) {
     1873                                                if ($space_left > 20) {
     1874                                                        $len = $space_left;
     1875                                                        if ($is_utf8) {
     1876                                                                $len = $this->utf8CharBoundary($word, $len);
     1877                                                        } elseif (substr($word, $len - 1, 1) == '=') {
     1878                                                                $len--;
     1879                                                        } elseif (substr($word, $len - 2, 1) == '=') {
     1880                                                                $len -= 2;
     1881                                                        }
     1882                                                        $part = substr($word, 0, $len);
     1883                                                        $word = substr($word, $len);
     1884                                                        $buf .= ' ' . $part;
     1885                                                        $message .= $buf . sprintf('=%s', self::CRLF);
     1886                                                } else {
     1887                                                        $message .= $buf . $soft_break;
     1888                                                }
     1889                                                $buf = '';
     1890                                        }
     1891                                        while (strlen($word) > 0) {
     1892                                                if ($length <= 0) {
     1893                                                        break;
     1894                                                }
     1895                                                $len = $length;
     1896                                                if ($is_utf8) {
     1897                                                        $len = $this->utf8CharBoundary($word, $len);
     1898                                                } elseif (substr($word, $len - 1, 1) == '=') {
     1899                                                        $len--;
     1900                                                } elseif (substr($word, $len - 2, 1) == '=') {
     1901                                                        $len -= 2;
     1902                                                }
     1903                                                $part = substr($word, 0, $len);
     1904                                                $word = substr($word, $len);
     1905
     1906                                                if (strlen($word) > 0) {
     1907                                                        $message .= $part . sprintf('=%s', self::CRLF);
     1908                                                } else {
     1909                                                        $buf = $part;
     1910                                                }
     1911                                        }
     1912                                } else {
     1913                                        $buf_o = $buf;
     1914                                        if (!$firstword) {
     1915                                                $buf .= ' ';
     1916                                        }
     1917                                        $buf .= $word;
     1918
     1919                                        if (strlen($buf) > $length and $buf_o != '') {
     1920                                                $message .= $buf_o . $soft_break;
     1921                                                $buf = $word;
     1922                                        }
     1923                                }
     1924                                $firstword = false;
     1925                        }
     1926                        $message .= $buf . self::CRLF;
     1927                }
     1928
     1929                return $message;
     1930        }
     1931
     1932        /**
     1933         * Find the last character boundary prior to $maxLength in a utf-8
     1934         * quoted-printable encoded string.
     1935         * Original written by Colin Brown.
     1936         * @access public
     1937         * @param string $encodedText utf-8 QP text
     1938         * @param integer $maxLength Find the last character boundary prior to this length
     1939         * @return integer
     1940         */
     1941        public function utf8CharBoundary($encodedText, $maxLength) {
     1942                $foundSplitPos = false;
     1943                $lookBack      = 3;
     1944                while (!$foundSplitPos) {
     1945                        $lastChunk      = substr($encodedText, $maxLength - $lookBack, $lookBack);
     1946                        $encodedCharPos = strpos($lastChunk, '=');
     1947                        if (false !== $encodedCharPos) {
     1948                                // Found start of encoded character byte within $lookBack block.
     1949                                // Check the encoded byte value (the 2 chars after the '=')
     1950                                $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2);
     1951                                $dec = hexdec($hex);
     1952                                if ($dec < 128) {
     1953                                        // Single byte character.
     1954                                        // If the encoded char was found at pos 0, it will fit
     1955                                        // otherwise reduce maxLength to start of the encoded char
     1956                                        if ($encodedCharPos > 0) {
     1957                                                $maxLength = $maxLength - ($lookBack - $encodedCharPos);
     1958                                        }
     1959                                        $foundSplitPos = true;
     1960                                } elseif ($dec >= 192) {
     1961                                        // First byte of a multi byte character
     1962                                        // Reduce maxLength to split at start of character
     1963                                        $maxLength     = $maxLength - ($lookBack - $encodedCharPos);
     1964                                        $foundSplitPos = true;
     1965                                } elseif ($dec < 192) {
     1966                                        // Middle byte of a multi byte character, look further back
     1967                                        $lookBack += 3;
     1968                                }
     1969                        } else {
     1970                                // No encoded character found
     1971                                $foundSplitPos = true;
     1972                        }
     1973                }
     1974                return $maxLength;
     1975        }
     1976
     1977        /**
     1978         * Apply word wrapping to the message body.
     1979         * Wraps the message body to the number of chars set in the WordWrap property.
     1980         * You should only do this to plain-text bodies as wrapping HTML tags may break them.
     1981         * This is called automatically by createBody(), so you don't need to call it yourself.
     1982         * @access public
     1983         * @return void
     1984         */
     1985        public function setWordWrap() {
     1986                if ($this->WordWrap < 1) {
     1987                        return;
     1988                }
    20141989
    2015     /**
    2016      * Apply word wrapping to the message body.
    2017      * Wraps the message body to the number of chars set in the WordWrap property.
    2018      * You should only do this to plain-text bodies as wrapping HTML tags may break them.
    2019      * This is called automatically by createBody(), so you don't need to call it yourself.
    2020      * @access public
    2021      * @return void
    2022      */
    2023     public function setWordWrap()
    2024     {
    2025         if ($this->WordWrap < 1) {
    2026             return;
    2027         }
    2028 
    2029         switch ($this->message_type) {
     1990                switch ($this->message_type) {
    20301991            case 'alt':
    20311992            case 'alt_inline':
    20321993            case 'alt_attach':
     
    20371998                $this->Body = $this->wrapText($this->Body, $this->WordWrap);
    20381999                break;
    20392000        }
    2040     }
    2041 
    2042     /**
    2043      * Assemble message headers.
    2044      * @access public
    2045      * @return string The assembled headers
    2046      */
    2047     public function createHeader()
    2048     {
    2049         $result = '';
    2050 
    2051         $result .= $this->headerLine('Date', $this->MessageDate == '' ? self::rfcDate() : $this->MessageDate);
    2052 
    2053         // To be created automatically by mail()
    2054         if ($this->SingleTo) {
    2055             if ($this->Mailer != 'mail') {
    2056                 foreach ($this->to as $toaddr) {
    2057                     $this->SingleToArray[] = $this->addrFormat($toaddr);
    2058                 }
    2059             }
    2060         } else {
    2061             if (count($this->to) > 0) {
    2062                 if ($this->Mailer != 'mail') {
    2063                     $result .= $this->addrAppend('To', $this->to);
    2064                 }
    2065             } elseif (count($this->cc) == 0) {
    2066                 $result .= $this->headerLine('To', 'undisclosed-recipients:;');
    2067             }
    2068         }
     2001        }
    20692002
    2070         $result .= $this->addrAppend('From', array(array(trim($this->From), $this->FromName)));
     2003        /**
     2004         * Assemble message headers.
     2005         * @access public
     2006         * @return string The assembled headers
     2007         */
     2008        public function createHeader() {
     2009                $result = '';
     2010
     2011                $result .= $this->headerLine('Date', $this->MessageDate == '' ? self::rfcDate() : $this->MessageDate);
     2012
     2013                // To be created automatically by mail()
     2014                if ($this->SingleTo) {
     2015                        if ($this->Mailer != 'mail') {
     2016                                foreach ($this->to as $toaddr) {
     2017                                        $this->SingleToArray[] = $this->addrFormat($toaddr);
     2018                                }
     2019                        }
     2020                } else {
     2021                        if (count($this->to) > 0) {
     2022                                if ($this->Mailer != 'mail') {
     2023                                        $result .= $this->addrAppend('To', $this->to);
     2024                                }
     2025                        } elseif (count($this->cc) == 0) {
     2026                                $result .= $this->headerLine('To', 'undisclosed-recipients:;');
     2027                        }
     2028                }
     2029
     2030                $result .= $this->addrAppend('From', array(array(trim($this->From), $this->FromName)));
     2031
     2032                // sendmail and mail() extract Cc from the header before sending
     2033                if (count($this->cc) > 0) {
     2034                        $result .= $this->addrAppend('Cc', $this->cc);
     2035                }
    20712036
    2072         // sendmail and mail() extract Cc from the header before sending
    2073         if (count($this->cc) > 0) {
    2074             $result .= $this->addrAppend('Cc', $this->cc);
    2075         }
    2076 
    2077         // sendmail and mail() extract Bcc from the header before sending
    2078         if ((
     2037                // sendmail and mail() extract Bcc from the header before sending
     2038                if ((
    20792039                $this->Mailer == 'sendmail' or $this->Mailer == 'qmail' or $this->Mailer == 'mail'
    20802040            )
    20812041            and count($this->bcc) > 0
    20822042        ) {
    2083             $result .= $this->addrAppend('Bcc', $this->bcc);
    2084         }
     2043                        $result .= $this->addrAppend('Bcc', $this->bcc);
     2044                }
    20852045
    2086         if (count($this->ReplyTo) > 0) {
    2087             $result .= $this->addrAppend('Reply-To', $this->ReplyTo);
    2088         }
    2089 
    2090         // mail() sets the subject itself
    2091         if ($this->Mailer != 'mail') {
    2092             $result .= $this->headerLine('Subject', $this->encodeHeader($this->secureHeader($this->Subject)));
    2093         }
    2094 
    2095         // Only allow a custom message ID if it conforms to RFC 5322 section 3.6.4
    2096         // https://tools.ietf.org/html/rfc5322#section-3.6.4
    2097         if ('' != $this->MessageID and preg_match('/^<.*@.*>$/', $this->MessageID)) {
    2098             $this->lastMessageID = $this->MessageID;
    2099         } else {
    2100             $this->lastMessageID = sprintf('<%s@%s>', $this->uniqueid, $this->serverHostname());
    2101         }
    2102         $result .= $this->headerLine('Message-ID', $this->lastMessageID);
    2103         if (!is_null($this->Priority)) {
    2104             $result .= $this->headerLine('X-Priority', $this->Priority);
    2105         }
    2106         if ($this->XMailer == '') {
    2107             $result .= $this->headerLine(
     2046                if (count($this->ReplyTo) > 0) {
     2047                        $result .= $this->addrAppend('Reply-To', $this->ReplyTo);
     2048                }
     2049
     2050                // mail() sets the subject itself
     2051                if ($this->Mailer != 'mail') {
     2052                        $result .= $this->headerLine('Subject', $this->encodeHeader($this->secureHeader($this->Subject)));
     2053                }
     2054
     2055                // Only allow a custom message ID if it conforms to RFC 5322 section 3.6.4
     2056                // https://tools.ietf.org/html/rfc5322#section-3.6.4
     2057                if ('' != $this->MessageID and preg_match('/^<.*@.*>$/', $this->MessageID)) {
     2058                        $this->lastMessageID = $this->MessageID;
     2059                } else {
     2060                        $this->lastMessageID = sprintf('<%s@%s>', $this->uniqueid, $this->serverHostname());
     2061                }
     2062                $result .= $this->headerLine('Message-ID', $this->lastMessageID);
     2063                if (!is_null($this->Priority)) {
     2064                        $result .= $this->headerLine('X-Priority', $this->Priority);
     2065                }
     2066                if ($this->XMailer == '') {
     2067                        $result .= $this->headerLine(
    21082068                'X-Mailer',
    21092069                'PHPMailer ' . $this->Version . ' (https://github.com/PHPMailer/PHPMailer)'
    21102070            );
    2111         } else {
    2112             $myXmailer = trim($this->XMailer);
    2113             if ($myXmailer) {
    2114                 $result .= $this->headerLine('X-Mailer', $myXmailer);
    2115             }
    2116         }
    2117 
    2118         if ($this->ConfirmReadingTo != '') {
    2119             $result .= $this->headerLine('Disposition-Notification-To', '<' . $this->ConfirmReadingTo . '>');
    2120         }
    2121 
    2122         // Add custom headers
    2123         foreach ($this->CustomHeader as $header) {
    2124             $result .= $this->headerLine(
     2071                } else {
     2072                        $myXmailer = trim($this->XMailer);
     2073                        if ($myXmailer) {
     2074                                $result .= $this->headerLine('X-Mailer', $myXmailer);
     2075                        }
     2076                }
     2077
     2078                if ($this->ConfirmReadingTo != '') {
     2079                        $result .= $this->headerLine('Disposition-Notification-To', '<' . $this->ConfirmReadingTo . '>');
     2080                }
     2081
     2082                // Add custom headers
     2083                foreach ($this->CustomHeader as $header) {
     2084                        $result .= $this->headerLine(
    21252085                trim($header[0]),
    21262086                $this->encodeHeader(trim($header[1]))
    21272087            );
    2128         }
    2129         if (!$this->sign_key_file) {
    2130             $result .= $this->headerLine('MIME-Version', '1.0');
    2131             $result .= $this->getMailMIME();
    2132         }
    2133 
    2134         return $result;
    2135     }
    2136 
    2137     /**
    2138      * Get the message MIME type headers.
    2139      * @access public
    2140      * @return string
    2141      */
    2142     public function getMailMIME()
    2143     {
    2144         $result = '';
    2145         $ismultipart = true;
    2146         switch ($this->message_type) {
     2088                }
     2089                if (!$this->sign_key_file) {
     2090                        $result .= $this->headerLine('MIME-Version', '1.0');
     2091                        $result .= $this->getMailMIME();
     2092                }
     2093
     2094                return $result;
     2095        }
     2096
     2097        /**
     2098         * Get the message MIME type headers.
     2099         * @access public
     2100         * @return string
     2101         */
     2102        public function getMailMIME() {
     2103                $result      = '';
     2104                $ismultipart = true;
     2105                switch ($this->message_type) {
    21472106            case 'inline':
    21482107                $result .= $this->headerLine('Content-Type', 'multipart/related;');
    21492108                $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
     
    21662125                $ismultipart = false;
    21672126                break;
    21682127        }
    2169         // RFC1341 part 5 says 7bit is assumed if not specified
    2170         if ($this->Encoding != '7bit') {
    2171             // RFC 2045 section 6.4 says multipart MIME parts may only use 7bit, 8bit or binary CTE
    2172             if ($ismultipart) {
    2173                 if ($this->Encoding == '8bit') {
    2174                     $result .= $this->headerLine('Content-Transfer-Encoding', '8bit');
    2175                 }
    2176                 // The only remaining alternatives are quoted-printable and base64, which are both 7bit compatible
    2177             } else {
    2178                 $result .= $this->headerLine('Content-Transfer-Encoding', $this->Encoding);
    2179             }
    2180         }
    2181 
    2182         if ($this->Mailer != 'mail') {
    2183             $result .= $this->LE;
    2184         }
    2185 
    2186         return $result;
    2187     }
    2188 
    2189     /**
    2190      * Returns the whole MIME message.
    2191      * Includes complete headers and body.
    2192      * Only valid post preSend().
    2193      * @see PHPMailer::preSend()
    2194      * @access public
    2195      * @return string
    2196      */
    2197     public function getSentMIMEMessage()
    2198     {
    2199         return rtrim($this->MIMEHeader . $this->mailHeader, "\n\r") . self::CRLF . self::CRLF . $this->MIMEBody;
    2200     }
    2201 
    2202     /**
    2203      * Create unique ID
    2204      * @return string
    2205      */
    2206     protected function generateId() {
    2207         return md5(uniqid(time()));
    2208     }
    2209 
    2210     /**
    2211      * Assemble the message body.
    2212      * Returns an empty string on failure.
    2213      * @access public
    2214      * @throws phpmailerException
    2215      * @return string The assembled message body
    2216      */
    2217     public function createBody()
    2218     {
    2219         $body = '';
    2220         //Create unique IDs and preset boundaries
    2221         $this->uniqueid = $this->generateId();
    2222         $this->boundary[1] = 'b1_' . $this->uniqueid;
    2223         $this->boundary[2] = 'b2_' . $this->uniqueid;
    2224         $this->boundary[3] = 'b3_' . $this->uniqueid;
    2225 
    2226         if ($this->sign_key_file) {
    2227             $body .= $this->getMailMIME() . $this->LE;
    2228         }
    2229 
    2230         $this->setWordWrap();
    2231 
    2232         $bodyEncoding = $this->Encoding;
    2233         $bodyCharSet = $this->CharSet;
    2234         //Can we do a 7-bit downgrade?
    2235         if ($bodyEncoding == '8bit' and !$this->has8bitChars($this->Body)) {
    2236             $bodyEncoding = '7bit';
    2237             //All ISO 8859, Windows codepage and UTF-8 charsets are ascii compatible up to 7-bit
    2238             $bodyCharSet = 'us-ascii';
    2239         }
    2240         //If lines are too long, and we're not already using an encoding that will shorten them,
    2241         //change to quoted-printable transfer encoding for the body part only
    2242         if ('base64' != $this->Encoding and self::hasLineLongerThanMax($this->Body)) {
    2243             $bodyEncoding = 'quoted-printable';
    2244         }
    2245 
    2246         $altBodyEncoding = $this->Encoding;
    2247         $altBodyCharSet = $this->CharSet;
    2248         //Can we do a 7-bit downgrade?
    2249         if ($altBodyEncoding == '8bit' and !$this->has8bitChars($this->AltBody)) {
    2250             $altBodyEncoding = '7bit';
    2251             //All ISO 8859, Windows codepage and UTF-8 charsets are ascii compatible up to 7-bit
    2252             $altBodyCharSet = 'us-ascii';
    2253         }
    2254         //If lines are too long, and we're not already using an encoding that will shorten them,
    2255         //change to quoted-printable transfer encoding for the alt body part only
    2256         if ('base64' != $altBodyEncoding and self::hasLineLongerThanMax($this->AltBody)) {
    2257             $altBodyEncoding = 'quoted-printable';
    2258         }
    2259         //Use this as a preamble in all multipart message types
    2260         $mimepre = "This is a multi-part message in MIME format." . $this->LE . $this->LE;
    2261         switch ($this->message_type) {
     2128                // RFC1341 part 5 says 7bit is assumed if not specified
     2129                if ($this->Encoding != '7bit') {
     2130                        // RFC 2045 section 6.4 says multipart MIME parts may only use 7bit, 8bit or binary CTE
     2131                        if ($ismultipart) {
     2132                                if ($this->Encoding == '8bit') {
     2133                                        $result .= $this->headerLine('Content-Transfer-Encoding', '8bit');
     2134                                }
     2135                                // The only remaining alternatives are quoted-printable and base64, which are both 7bit compatible
     2136                        } else {
     2137                                $result .= $this->headerLine('Content-Transfer-Encoding', $this->Encoding);
     2138                        }
     2139                }
     2140
     2141                if ($this->Mailer != 'mail') {
     2142                        $result .= $this->LE;
     2143                }
     2144
     2145                return $result;
     2146        }
     2147
     2148        /**
     2149         * Returns the whole MIME message.
     2150         * Includes complete headers and body.
     2151         * Only valid post preSend().
     2152         * @see PHPMailer::preSend()
     2153         * @access public
     2154         * @return string
     2155         */
     2156        public function getSentMIMEMessage() {
     2157                return rtrim($this->MIMEHeader . $this->mailHeader, "\n\r") . self::CRLF . self::CRLF . $this->MIMEBody;
     2158        }
     2159
     2160        /**
     2161         * Create unique ID
     2162         * @return string
     2163         */
     2164        protected function generateId() {
     2165                return md5(uniqid(time()));
     2166        }
     2167
     2168        /**
     2169         * Assemble the message body.
     2170         * Returns an empty string on failure.
     2171         * @access public
     2172         * @throws phpmailerException
     2173         * @return string The assembled message body
     2174         */
     2175        public function createBody() {
     2176                $body = '';
     2177                //Create unique IDs and preset boundaries
     2178                $this->uniqueid    = $this->generateId();
     2179                $this->boundary[1] = 'b1_' . $this->uniqueid;
     2180                $this->boundary[2] = 'b2_' . $this->uniqueid;
     2181                $this->boundary[3] = 'b3_' . $this->uniqueid;
     2182
     2183                if ($this->sign_key_file) {
     2184                        $body .= $this->getMailMIME() . $this->LE;
     2185                }
     2186
     2187                $this->setWordWrap();
     2188
     2189                $bodyEncoding = $this->Encoding;
     2190                $bodyCharSet  = $this->CharSet;
     2191                //Can we do a 7-bit downgrade?
     2192                if ($bodyEncoding == '8bit' and !$this->has8bitChars($this->Body)) {
     2193                        $bodyEncoding = '7bit';
     2194                        //All ISO 8859, Windows codepage and UTF-8 charsets are ascii compatible up to 7-bit
     2195                        $bodyCharSet = 'us-ascii';
     2196                }
     2197                //If lines are too long, and we're not already using an encoding that will shorten them,
     2198                //change to quoted-printable transfer encoding for the body part only
     2199                if ('base64' != $this->Encoding and self::hasLineLongerThanMax($this->Body)) {
     2200                        $bodyEncoding = 'quoted-printable';
     2201                }
     2202
     2203                $altBodyEncoding = $this->Encoding;
     2204                $altBodyCharSet  = $this->CharSet;
     2205                //Can we do a 7-bit downgrade?
     2206                if ($altBodyEncoding == '8bit' and !$this->has8bitChars($this->AltBody)) {
     2207                        $altBodyEncoding = '7bit';
     2208                        //All ISO 8859, Windows codepage and UTF-8 charsets are ascii compatible up to 7-bit
     2209                        $altBodyCharSet = 'us-ascii';
     2210                }
     2211                //If lines are too long, and we're not already using an encoding that will shorten them,
     2212                //change to quoted-printable transfer encoding for the alt body part only
     2213                if ('base64' != $altBodyEncoding and self::hasLineLongerThanMax($this->AltBody)) {
     2214                        $altBodyEncoding = 'quoted-printable';
     2215                }
     2216                //Use this as a preamble in all multipart message types
     2217                $mimepre = 'This is a multi-part message in MIME format.' . $this->LE . $this->LE;
     2218                switch ($this->message_type) {
    22622219            case 'inline':
    22632220                $body .= $mimepre;
    22642221                $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding);
     
    22952252                $body .= $this->encodeString($this->Body, $bodyEncoding);
    22962253                $body .= $this->LE . $this->LE;
    22972254                if (!empty($this->Ical)) {
    2298                     $body .= $this->getBoundary($this->boundary[1], '', 'text/calendar; method=REQUEST', '');
    2299                     $body .= $this->encodeString($this->Ical, $this->Encoding);
    2300                     $body .= $this->LE . $this->LE;
     2255                        $body .= $this->getBoundary($this->boundary[1], '', 'text/calendar; method=REQUEST', '');
     2256                        $body .= $this->encodeString($this->Ical, $this->Encoding);
     2257                        $body .= $this->LE . $this->LE;
    23012258                }
    23022259                $body .= $this->endBoundary($this->boundary[1]);
    23032260                break;
     
    23632320                break;
    23642321        }
    23652322
    2366         if ($this->isError()) {
    2367             $body = '';
    2368         } elseif ($this->sign_key_file) {
    2369             try {
    2370                 if (!defined('PKCS7_TEXT')) {
    2371                     throw new phpmailerException($this->lang('extension_missing') . 'openssl');
    2372                 }
    2373                 // @TODO would be nice to use php://temp streams here, but need to wrap for PHP < 5.1
    2374                 $file = tempnam(sys_get_temp_dir(), 'mail');
    2375                 if (false === file_put_contents($file, $body)) {
    2376                     throw new phpmailerException($this->lang('signing') . ' Could not write temp file');
    2377                 }
    2378                 $signed = tempnam(sys_get_temp_dir(), 'signed');
    2379                 //Workaround for PHP bug https://bugs.php.net/bug.php?id=69197
    2380                 if (empty($this->sign_extracerts_file)) {
    2381                     $sign = @openssl_pkcs7_sign(
     2323                if ($this->isError()) {
     2324                        $body = '';
     2325                } elseif ($this->sign_key_file) {
     2326                        try {
     2327                                if (!defined('PKCS7_TEXT')) {
     2328                                        throw new phpmailerException($this->lang('extension_missing') . 'openssl');
     2329                                }
     2330                                // @TODO would be nice to use php://temp streams here, but need to wrap for PHP < 5.1
     2331                                $file = tempnam(sys_get_temp_dir(), 'mail');
     2332                                if (false === file_put_contents($file, $body)) {
     2333                                        throw new phpmailerException($this->lang('signing') . ' Could not write temp file');
     2334                                }
     2335                                $signed = tempnam(sys_get_temp_dir(), 'signed');
     2336                                //Workaround for PHP bug https://bugs.php.net/bug.php?id=69197
     2337                                if (empty($this->sign_extracerts_file)) {
     2338                                        $sign = @openssl_pkcs7_sign(
    23822339                        $file,
    23832340                        $signed,
    23842341                        'file://' . realpath($this->sign_cert_file),
    23852342                        array('file://' . realpath($this->sign_key_file), $this->sign_key_pass),
    23862343                        null
    23872344                    );
    2388                 } else {
    2389                     $sign = @openssl_pkcs7_sign(
     2345                                } else {
     2346                                        $sign = @openssl_pkcs7_sign(
    23902347                        $file,
    23912348                        $signed,
    23922349                        'file://' . realpath($this->sign_cert_file),
     
    23952352                        PKCS7_DETACHED,
    23962353                        $this->sign_extracerts_file
    23972354                    );
    2398                 }
    2399                 if ($sign) {
    2400                     @unlink($file);
    2401                     $body = file_get_contents($signed);
    2402                     @unlink($signed);
    2403                     //The message returned by openssl contains both headers and body, so need to split them up
    2404                     $parts = explode("\n\n", $body, 2);
    2405                     $this->MIMEHeader .= $parts[0] . $this->LE . $this->LE;
    2406                     $body = $parts[1];
    2407                 } else {
    2408                     @unlink($file);
    2409                     @unlink($signed);
    2410                     throw new phpmailerException($this->lang('signing') . openssl_error_string());
    2411                 }
    2412             } catch (phpmailerException $exc) {
    2413                 $body = '';
    2414                 if ($this->exceptions) {
    2415                     throw $exc;
    2416                 }
    2417             }
    2418         }
    2419         return $body;
    2420     }
    2421 
    2422     /**
    2423      * Return the start of a message boundary.
    2424      * @access protected
    2425      * @param string $boundary
    2426      * @param string $charSet
    2427      * @param string $contentType
    2428      * @param string $encoding
    2429      * @return string
    2430      */
    2431     protected function getBoundary($boundary, $charSet, $contentType, $encoding)
    2432     {
    2433         $result = '';
    2434         if ($charSet == '') {
    2435             $charSet = $this->CharSet;
    2436         }
    2437         if ($contentType == '') {
    2438             $contentType = $this->ContentType;
    2439         }
    2440         if ($encoding == '') {
    2441             $encoding = $this->Encoding;
    2442         }
    2443         $result .= $this->textLine('--' . $boundary);
    2444         $result .= sprintf('Content-Type: %s; charset=%s', $contentType, $charSet);
    2445         $result .= $this->LE;
    2446         // RFC1341 part 5 says 7bit is assumed if not specified
    2447         if ($encoding != '7bit') {
    2448             $result .= $this->headerLine('Content-Transfer-Encoding', $encoding);
    2449         }
    2450         $result .= $this->LE;
    2451 
    2452         return $result;
    2453     }
    2454 
    2455     /**
    2456      * Return the end of a message boundary.
    2457      * @access protected
    2458      * @param string $boundary
    2459      * @return string
    2460      */
    2461     protected function endBoundary($boundary)
    2462     {
    2463         return $this->LE . '--' . $boundary . '--' . $this->LE;
    2464     }
    2465 
    2466     /**
    2467      * Set the message type.
    2468      * PHPMailer only supports some preset message types, not arbitrary MIME structures.
    2469      * @access protected
    2470      * @return void
    2471      */
    2472     protected function setMessageType()
    2473     {
    2474         $type = array();
    2475         if ($this->alternativeExists()) {
    2476             $type[] = 'alt';
    2477         }
    2478         if ($this->inlineImageExists()) {
    2479             $type[] = 'inline';
    2480         }
    2481         if ($this->attachmentExists()) {
    2482             $type[] = 'attach';
    2483         }
    2484         $this->message_type = implode('_', $type);
    2485         if ($this->message_type == '') {
    2486             //The 'plain' message_type refers to the message having a single body element, not that it is plain-text
    2487             $this->message_type = 'plain';
    2488         }
    2489     }
    2490 
    2491     /**
    2492      * Format a header line.
    2493      * @access public
    2494      * @param string $name
    2495      * @param string $value
    2496      * @return string
    2497      */
    2498     public function headerLine($name, $value)
    2499     {
    2500         return $name . ': ' . $value . $this->LE;
    2501     }
    2502 
    2503     /**
    2504      * Return a formatted mail line.
    2505      * @access public
    2506      * @param string $value
    2507      * @return string
    2508      */
    2509     public function textLine($value)
    2510     {
    2511         return $value . $this->LE;
    2512     }
    2513 
    2514     /**
    2515      * Add an attachment from a path on the filesystem.
    2516      * Never use a user-supplied path to a file!
    2517      * Returns false if the file could not be found or read.
    2518      * Explicitly *does not* support passing URLs; PHPMailer is not an HTTP client.
    2519      * If you need to do that, fetch the resource yourself and pass it in via a local file or string.
    2520      * @param string $path Path to the attachment.
    2521      * @param string $name Overrides the attachment name.
    2522      * @param string $encoding File encoding (see $Encoding).
    2523      * @param string $type File extension (MIME) type.
    2524      * @param string $disposition Disposition to use
    2525      * @throws phpmailerException
    2526      * @return boolean
    2527      */
    2528     public function addAttachment($path, $name = '', $encoding = 'base64', $type = '', $disposition = 'attachment')
    2529     {
    2530         try {
    2531             if (!self::isPermittedPath($path) or !@is_file($path)) {
    2532                 throw new phpmailerException($this->lang('file_access') . $path, self::STOP_CONTINUE);
    2533             }
    2534 
    2535             // If a MIME type is not specified, try to work it out from the file name
    2536             if ($type == '') {
    2537                 $type = self::filenameToType($path);
    2538             }
    2539 
    2540             $filename = basename($path);
    2541             if ($name == '') {
    2542                 $name = $filename;
    2543             }
    2544 
    2545             $this->attachment[] = array(
    2546                 0 => $path,
    2547                 1 => $filename,
    2548                 2 => $name,
    2549                 3 => $encoding,
    2550                 4 => $type,
    2551                 5 => false, // isStringAttachment
    2552                 6 => $disposition,
    2553                 7 => 0
    2554             );
    2555 
    2556         } catch (phpmailerException $exc) {
    2557             $this->setError($exc->getMessage());
    2558             $this->edebug($exc->getMessage());
    2559             if ($this->exceptions) {
    2560                 throw $exc;
    2561             }
    2562             return false;
    2563         }
    2564         return true;
    2565     }
    2566 
    2567     /**
    2568      * Return the array of attachments.
    2569      * @return array
    2570      */
    2571     public function getAttachments()
    2572     {
    2573         return $this->attachment;
    2574     }
    2575 
    2576     /**
    2577      * Attach all file, string, and binary attachments to the message.
    2578      * Returns an empty string on failure.
    2579      * @access protected
    2580      * @param string $disposition_type
    2581      * @param string $boundary
    2582      * @return string
    2583      */
    2584     protected function attachAll($disposition_type, $boundary)
    2585     {
    2586         // Return text of body
    2587         $mime = array();
    2588         $cidUniq = array();
    2589         $incl = array();
    2590 
    2591         // Add all attachments
    2592         foreach ($this->attachment as $attachment) {
    2593             // Check if it is a valid disposition_filter
    2594             if ($attachment[6] == $disposition_type) {
    2595                 // Check for string attachment
    2596                 $string = '';
    2597                 $path = '';
    2598                 $bString = $attachment[5];
    2599                 if ($bString) {
    2600                     $string = $attachment[0];
    2601                 } else {
    2602                     $path = $attachment[0];
    2603                 }
    2604 
    2605                 $inclhash = md5(serialize($attachment));
    2606                 if (in_array($inclhash, $incl)) {
    2607                     continue;
    2608                 }
    2609                 $incl[] = $inclhash;
    2610                 $name = $attachment[2];
    2611                 $encoding = $attachment[3];
    2612                 $type = $attachment[4];
    2613                 $disposition = $attachment[6];
    2614                 $cid = $attachment[7];
    2615                 if ($disposition == 'inline' && array_key_exists($cid, $cidUniq)) {
    2616                     continue;
    2617                 }
    2618                 $cidUniq[$cid] = true;
    2619 
    2620                 $mime[] = sprintf('--%s%s', $boundary, $this->LE);
    2621                 //Only include a filename property if we have one
    2622                 if (!empty($name)) {
    2623                     $mime[] = sprintf(
     2355                                }
     2356                                if ($sign) {
     2357                                        @unlink($file);
     2358                                        $body = file_get_contents($signed);
     2359                                        @unlink($signed);
     2360                                        //The message returned by openssl contains both headers and body, so need to split them up
     2361                                        $parts = explode("\n\n", $body, 2);
     2362                                        $this->MIMEHeader .= $parts[0] . $this->LE . $this->LE;
     2363                                        $body = $parts[1];
     2364                                } else {
     2365                                        @unlink($file);
     2366                                        @unlink($signed);
     2367                                        throw new phpmailerException($this->lang('signing') . openssl_error_string());
     2368                                }
     2369                        } catch (phpmailerException $exc) {
     2370                                $body = '';
     2371                                if ($this->exceptions) {
     2372                                        throw $exc;
     2373                                }
     2374                        }
     2375                }
     2376                return $body;
     2377        }
     2378
     2379        /**
     2380         * Return the start of a message boundary.
     2381         * @access protected
     2382         * @param string $boundary
     2383         * @param string $charSet
     2384         * @param string $contentType
     2385         * @param string $encoding
     2386         * @return string
     2387         */
     2388        protected function getBoundary($boundary, $charSet, $contentType, $encoding) {
     2389                $result = '';
     2390                if ($charSet == '') {
     2391                        $charSet = $this->CharSet;
     2392                }
     2393                if ($contentType == '') {
     2394                        $contentType = $this->ContentType;
     2395                }
     2396                if ($encoding == '') {
     2397                        $encoding = $this->Encoding;
     2398                }
     2399                $result .= $this->textLine('--' . $boundary);
     2400                $result .= sprintf('Content-Type: %s; charset=%s', $contentType, $charSet);
     2401                $result .= $this->LE;
     2402                // RFC1341 part 5 says 7bit is assumed if not specified
     2403                if ($encoding != '7bit') {
     2404                        $result .= $this->headerLine('Content-Transfer-Encoding', $encoding);
     2405                }
     2406                $result .= $this->LE;
     2407
     2408                return $result;
     2409        }
     2410
     2411        /**
     2412         * Return the end of a message boundary.
     2413         * @access protected
     2414         * @param string $boundary
     2415         * @return string
     2416         */
     2417        protected function endBoundary($boundary) {
     2418                return $this->LE . '--' . $boundary . '--' . $this->LE;
     2419        }
     2420
     2421        /**
     2422         * Set the message type.
     2423         * PHPMailer only supports some preset message types, not arbitrary MIME structures.
     2424         * @access protected
     2425         * @return void
     2426         */
     2427        protected function setMessageType() {
     2428                $type = array();
     2429                if ($this->alternativeExists()) {
     2430                        $type[] = 'alt';
     2431                }
     2432                if ($this->inlineImageExists()) {
     2433                        $type[] = 'inline';
     2434                }
     2435                if ($this->attachmentExists()) {
     2436                        $type[] = 'attach';
     2437                }
     2438                $this->message_type = implode('_', $type);
     2439                if ($this->message_type == '') {
     2440                        //The 'plain' message_type refers to the message having a single body element, not that it is plain-text
     2441                        $this->message_type = 'plain';
     2442                }
     2443        }
     2444
     2445        /**
     2446         * Format a header line.
     2447         * @access public
     2448         * @param string $name
     2449         * @param string $value
     2450         * @return string
     2451         */
     2452        public function headerLine($name, $value) {
     2453                return $name . ': ' . $value . $this->LE;
     2454        }
     2455
     2456        /**
     2457         * Return a formatted mail line.
     2458         * @access public
     2459         * @param string $value
     2460         * @return string
     2461         */
     2462        public function textLine($value) {
     2463                return $value . $this->LE;
     2464        }
     2465
     2466        /**
     2467         * Add an attachment from a path on the filesystem.
     2468         * Never use a user-supplied path to a file!
     2469         * Returns false if the file could not be found or read.
     2470         * Explicitly *does not* support passing URLs; PHPMailer is not an HTTP client.
     2471         * If you need to do that, fetch the resource yourself and pass it in via a local file or string.
     2472         * @param string $path Path to the attachment.
     2473         * @param string $name Overrides the attachment name.
     2474         * @param string $encoding File encoding (see $Encoding).
     2475         * @param string $type File extension (MIME) type.
     2476         * @param string $disposition Disposition to use
     2477         * @throws phpmailerException
     2478         * @return boolean
     2479         */
     2480        public function addAttachment($path, $name = '', $encoding = 'base64', $type = '', $disposition = 'attachment') {
     2481                try {
     2482                        if (!self::isPermittedPath($path) or !@is_file($path)) {
     2483                                throw new phpmailerException($this->lang('file_access') . $path, self::STOP_CONTINUE);
     2484                        }
     2485
     2486                        // If a MIME type is not specified, try to work it out from the file name
     2487                        if ($type == '') {
     2488                                $type = self::filenameToType($path);
     2489                        }
     2490
     2491                        $filename = basename($path);
     2492                        if ($name == '') {
     2493                                $name = $filename;
     2494                        }
     2495
     2496                        $this->attachment[] = array(
     2497                                0 => $path,
     2498                                1 => $filename,
     2499                                2 => $name,
     2500                                3 => $encoding,
     2501                                4 => $type,
     2502                                5 => false, // isStringAttachment
     2503                                6 => $disposition,
     2504                                7 => 0,
     2505                        );
     2506                } catch (phpmailerException $exc) {
     2507                        $this->setError($exc->getMessage());
     2508                        $this->edebug($exc->getMessage());
     2509                        if ($this->exceptions) {
     2510                                throw $exc;
     2511                        }
     2512                        return false;
     2513                }
     2514                return true;
     2515        }
     2516
     2517        /**
     2518         * Return the array of attachments.
     2519         * @return array
     2520         */
     2521        public function getAttachments() {
     2522                return $this->attachment;
     2523        }
     2524
     2525        /**
     2526         * Attach all file, string, and binary attachments to the message.
     2527         * Returns an empty string on failure.
     2528         * @access protected
     2529         * @param string $disposition_type
     2530         * @param string $boundary
     2531         * @return string
     2532         */
     2533        protected function attachAll($disposition_type, $boundary) {
     2534                // Return text of body
     2535                $mime    = array();
     2536                $cidUniq = array();
     2537                $incl    = array();
     2538
     2539                // Add all attachments
     2540                foreach ($this->attachment as $attachment) {
     2541                        // Check if it is a valid disposition_filter
     2542                        if ($attachment[6] == $disposition_type) {
     2543                                // Check for string attachment
     2544                                $string  = '';
     2545                                $path    = '';
     2546                                $bString = $attachment[5];
     2547                                if ($bString) {
     2548                                        $string = $attachment[0];
     2549                                } else {
     2550                                        $path = $attachment[0];
     2551                                }
     2552
     2553                                $inclhash = md5(serialize($attachment));
     2554                                if (in_array($inclhash, $incl)) {
     2555                                        continue;
     2556                                }
     2557                                $incl[]      = $inclhash;
     2558                                $name        = $attachment[2];
     2559                                $encoding    = $attachment[3];
     2560                                $type        = $attachment[4];
     2561                                $disposition = $attachment[6];
     2562                                $cid         = $attachment[7];
     2563                                if ($disposition == 'inline' && array_key_exists($cid, $cidUniq)) {
     2564                                        continue;
     2565                                }
     2566                                $cidUniq[$cid] = true;
     2567
     2568                                $mime[] = sprintf('--%s%s', $boundary, $this->LE);
     2569                                //Only include a filename property if we have one
     2570                                if (!empty($name)) {
     2571                                        $mime[] = sprintf(
    26242572                        'Content-Type: %s; name="%s"%s',
    26252573                        $type,
    26262574                        $this->encodeHeader($this->secureHeader($name)),
    26272575                        $this->LE
    26282576                    );
    2629                 } else {
    2630                     $mime[] = sprintf(
     2577                                } else {
     2578                                        $mime[] = sprintf(
    26312579                        'Content-Type: %s%s',
    26322580                        $type,
    26332581                        $this->LE
    26342582                    );
    2635                 }
    2636                 // RFC1341 part 5 says 7bit is assumed if not specified
    2637                 if ($encoding != '7bit') {
    2638                     $mime[] = sprintf('Content-Transfer-Encoding: %s%s', $encoding, $this->LE);
    2639                 }
    2640 
    2641                 if ($disposition == 'inline') {
    2642                     $mime[] = sprintf('Content-ID: <%s>%s', $cid, $this->LE);
    2643                 }
    2644 
    2645                 // If a filename contains any of these chars, it should be quoted,
    2646                 // but not otherwise: RFC2183 & RFC2045 5.1
    2647                 // Fixes a warning in IETF's msglint MIME checker
    2648                 // Allow for bypassing the Content-Disposition header totally
    2649                 if (!(empty($disposition))) {
    2650                     $encoded_name = $this->encodeHeader($this->secureHeader($name));
    2651                     if (preg_match('/[ \(\)<>@,;:\\"\/\[\]\?=]/', $encoded_name)) {
    2652                         $mime[] = sprintf(
     2583                                }
     2584                                // RFC1341 part 5 says 7bit is assumed if not specified
     2585                                if ($encoding != '7bit') {
     2586                                        $mime[] = sprintf('Content-Transfer-Encoding: %s%s', $encoding, $this->LE);
     2587                                }
     2588
     2589                                if ($disposition == 'inline') {
     2590                                        $mime[] = sprintf('Content-ID: <%s>%s', $cid, $this->LE);
     2591                                }
     2592
     2593                                // If a filename contains any of these chars, it should be quoted,
     2594                                // but not otherwise: RFC2183 & RFC2045 5.1
     2595                                // Fixes a warning in IETF's msglint MIME checker
     2596                                // Allow for bypassing the Content-Disposition header totally
     2597                                if (!(empty($disposition))) {
     2598                                        $encoded_name = $this->encodeHeader($this->secureHeader($name));
     2599                                        if (preg_match('/[ \(\)<>@,;:\\"\/\[\]\?=]/', $encoded_name)) {
     2600                                                $mime[] = sprintf(
    26532601                            'Content-Disposition: %s; filename="%s"%s',
    26542602                            $disposition,
    26552603                            $encoded_name,
    26562604                            $this->LE . $this->LE
    26572605                        );
    2658                     } else {
    2659                         if (!empty($encoded_name)) {
    2660                             $mime[] = sprintf(
     2606                                        } else {
     2607                                                if (!empty($encoded_name)) {
     2608                                                        $mime[] = sprintf(
    26612609                                'Content-Disposition: %s; filename=%s%s',
    26622610                                $disposition,
    26632611                                $encoded_name,
    26642612                                $this->LE . $this->LE
    26652613                            );
    2666                         } else {
    2667                             $mime[] = sprintf(
     2614                                                } else {
     2615                                                        $mime[] = sprintf(
    26682616                                'Content-Disposition: %s%s',
    26692617                                $disposition,
    26702618                                $this->LE . $this->LE
    26712619                            );
    2672                         }
    2673                     }
    2674                 } else {
    2675                     $mime[] = $this->LE;
    2676                 }
    2677 
    2678                 // Encode as string attachment
    2679                 if ($bString) {
    2680                     $mime[] = $this->encodeString($string, $encoding);
    2681                     if ($this->isError()) {
    2682                         return '';
    2683                     }
    2684                     $mime[] = $this->LE . $this->LE;
    2685                 } else {
    2686                     $mime[] = $this->encodeFile($path, $encoding);
    2687                     if ($this->isError()) {
    2688                         return '';
    2689                     }
    2690                     $mime[] = $this->LE . $this->LE;
    2691                 }
    2692             }
    2693         }
    2694 
    2695         $mime[] = sprintf('--%s--%s', $boundary, $this->LE);
    2696 
    2697         return implode('', $mime);
    2698     }
    2699 
    2700     /**
    2701      * Encode a file attachment in requested format.
    2702      * Returns an empty string on failure.
    2703      * @param string $path The full path to the file
    2704      * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
    2705      * @throws phpmailerException
    2706      * @access protected
    2707      * @return string
    2708      */
    2709     protected function encodeFile($path, $encoding = 'base64')
    2710     {
    2711         try {
    2712             if (!self::isPermittedPath($path) or !file_exists($path)) {
    2713                 throw new phpmailerException($this->lang('file_open') . $path, self::STOP_CONTINUE);
    2714             }
    2715             $magic_quotes = ( PHP_VERSION_ID < 70400 && get_magic_quotes_runtime() ); // WP: Patched for PHP 7.4.
    2716             if ($magic_quotes) {
    2717                 if (version_compare(PHP_VERSION, '5.3.0', '<')) {
    2718                     set_magic_quotes_runtime(false);
    2719                 } else {
    2720                     //Doesn't exist in PHP 5.4, but we don't need to check because
    2721                     //get_magic_quotes_runtime always returns false in 5.4+
    2722                     //so it will never get here
    2723                     ini_set('magic_quotes_runtime', false);
    2724                 }
    2725             }
    2726             $file_buffer = file_get_contents($path);
    2727             $file_buffer = $this->encodeString($file_buffer, $encoding);
    2728             if ($magic_quotes) {
    2729                 if (version_compare(PHP_VERSION, '5.3.0', '<')) {
    2730                     set_magic_quotes_runtime($magic_quotes);
    2731                 } else {
    2732                     ini_set('magic_quotes_runtime', $magic_quotes);
    2733                 }
    2734             }
    2735             return $file_buffer;
    2736         } catch (Exception $exc) {
    2737             $this->setError($exc->getMessage());
    2738             return '';
    2739         }
    2740     }
    2741 
    2742     /**
    2743      * Encode a string in requested format.
    2744      * Returns an empty string on failure.
    2745      * @param string $str The text to encode
    2746      * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
    2747      * @access public
    2748      * @return string
    2749      */
    2750     public function encodeString($str, $encoding = 'base64')
    2751     {
    2752         $encoded = '';
    2753         switch (strtolower($encoding)) {
     2620                                                }
     2621                                        }
     2622                                } else {
     2623                                        $mime[] = $this->LE;
     2624                                }
     2625
     2626                                // Encode as string attachment
     2627                                if ($bString) {
     2628                                        $mime[] = $this->encodeString($string, $encoding);
     2629                                        if ($this->isError()) {
     2630                                                return '';
     2631                                        }
     2632                                        $mime[] = $this->LE . $this->LE;
     2633                                } else {
     2634                                        $mime[] = $this->encodeFile($path, $encoding);
     2635                                        if ($this->isError()) {
     2636                                                return '';
     2637                                        }
     2638                                        $mime[] = $this->LE . $this->LE;
     2639                                }
     2640                        }
     2641                }
     2642
     2643                $mime[] = sprintf('--%s--%s', $boundary, $this->LE);
     2644
     2645                return implode('', $mime);
     2646        }
     2647
     2648        /**
     2649         * Encode a file attachment in requested format.
     2650         * Returns an empty string on failure.
     2651         * @param string $path The full path to the file
     2652         * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
     2653         * @throws phpmailerException
     2654         * @access protected
     2655         * @return string
     2656         */
     2657        protected function encodeFile($path, $encoding = 'base64') {
     2658                try {
     2659                        if (!self::isPermittedPath($path) or !file_exists($path)) {
     2660                                throw new phpmailerException($this->lang('file_open') . $path, self::STOP_CONTINUE);
     2661                        }
     2662                        $magic_quotes = ( PHP_VERSION_ID < 70400 && get_magic_quotes_runtime() ); // WP: Patched for PHP 7.4.
     2663                        if ($magic_quotes) {
     2664                                if (version_compare(PHP_VERSION, '5.3.0', '<')) {
     2665                                        set_magic_quotes_runtime(false);
     2666                                } else {
     2667                                        //Doesn't exist in PHP 5.4, but we don't need to check because
     2668                                        //get_magic_quotes_runtime always returns false in 5.4+
     2669                                        //so it will never get here
     2670                                        ini_set('magic_quotes_runtime', false);
     2671                                }
     2672                        }
     2673                        $file_buffer = file_get_contents($path);
     2674                        $file_buffer = $this->encodeString($file_buffer, $encoding);
     2675                        if ($magic_quotes) {
     2676                                if (version_compare(PHP_VERSION, '5.3.0', '<')) {
     2677                                        set_magic_quotes_runtime($magic_quotes);
     2678                                } else {
     2679                                        ini_set('magic_quotes_runtime', $magic_quotes);
     2680                                }
     2681                        }
     2682                        return $file_buffer;
     2683                } catch (Exception $exc) {
     2684                        $this->setError($exc->getMessage());
     2685                        return '';
     2686                }
     2687        }
     2688
     2689        /**
     2690         * Encode a string in requested format.
     2691         * Returns an empty string on failure.
     2692         * @param string $str The text to encode
     2693         * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
     2694         * @access public
     2695         * @return string
     2696         */
     2697        public function encodeString($str, $encoding = 'base64') {
     2698                $encoded = '';
     2699                switch (strtolower($encoding)) {
    27542700            case 'base64':
    27552701                $encoded = chunk_split(base64_encode($str), 76, $this->LE);
    27562702                break;
     
    27592705                $encoded = $this->fixEOL($str);
    27602706                // Make sure it ends with a line break
    27612707                if (substr($encoded, -(strlen($this->LE))) != $this->LE) {
    2762                     $encoded .= $this->LE;
     2708                        $encoded .= $this->LE;
    27632709                }
    27642710                break;
    27652711            case 'binary':
     
    27722718                $this->setError($this->lang('encoding') . $encoding);
    27732719                break;
    27742720        }
    2775         return $encoded;
    2776     }
     2721                return $encoded;
     2722        }
    27772723
    2778     /**
    2779      * Encode a header string optimally.
    2780      * Picks shortest of Q, B, quoted-printable or none.
    2781      * @access public
    2782      * @param string $str
    2783      * @param string $position
    2784      * @return string
    2785      */
    2786     public function encodeHeader($str, $position = 'text')
    2787     {
    2788         $matchcount = 0;
    2789         switch (strtolower($position)) {
     2724        /**
     2725         * Encode a header string optimally.
     2726         * Picks shortest of Q, B, quoted-printable or none.
     2727         * @access public
     2728         * @param string $str
     2729         * @param string $position
     2730         * @return string
     2731         */
     2732        public function encodeHeader($str, $position = 'text') {
     2733                $matchcount = 0;
     2734                switch (strtolower($position)) {
    27902735            case 'phrase':
    27912736                if (!preg_match('/[\200-\377]/', $str)) {
    2792                     // Can't use addslashes as we don't know the value of magic_quotes_sybase
    2793                     $encoded = addcslashes($str, "\0..\37\177\\\"");
    2794                     if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) {
    2795                         return ($encoded);
    2796                     } else {
    2797                         return ("\"$encoded\"");
    2798                     }
     2737                        // Can't use addslashes as we don't know the value of magic_quotes_sybase
     2738                        $encoded = addcslashes($str, "\0..\37\177\\\"");
     2739                        if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) {
     2740                                return ($encoded);
     2741                        } else {
     2742                                return ("\"$encoded\"");
     2743                        }
    27992744                }
    28002745                $matchcount = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches);
    28012746                break;
     
    28092754                break;
    28102755        }
    28112756
    2812         //There are no chars that need encoding
    2813         if ($matchcount == 0) {
    2814             return ($str);
    2815         }
    2816 
    2817         $maxlen = 75 - 7 - strlen($this->CharSet);
    2818         // Try to select the encoding which should produce the shortest output
    2819         if ($matchcount > strlen($str) / 3) {
    2820             // More than a third of the content will need encoding, so B encoding will be most efficient
    2821             $encoding = 'B';
    2822             if (function_exists('mb_strlen') && $this->hasMultiBytes($str)) {
    2823                 // Use a custom function which correctly encodes and wraps long
    2824                 // multibyte strings without breaking lines within a character
    2825                 $encoded = $this->base64EncodeWrapMB($str, "\n");
    2826             } else {
    2827                 $encoded = base64_encode($str);
    2828                 $maxlen -= $maxlen % 4;
    2829                 $encoded = trim(chunk_split($encoded, $maxlen, "\n"));
    2830             }
    2831         } else {
    2832             $encoding = 'Q';
    2833             $encoded = $this->encodeQ($str, $position);
    2834             $encoded = $this->wrapText($encoded, $maxlen, true);
    2835             $encoded = str_replace('=' . self::CRLF, "\n", trim($encoded));
    2836         }
    2837 
    2838         $encoded = preg_replace('/^(.*)$/m', ' =?' . $this->CharSet . "?$encoding?\\1?=", $encoded);
    2839         $encoded = trim(str_replace("\n", $this->LE, $encoded));
    2840 
    2841         return $encoded;
    2842     }
    2843 
    2844     /**
    2845      * Check if a string contains multi-byte characters.
    2846      * @access public
    2847      * @param string $str multi-byte text to wrap encode
    2848      * @return boolean
    2849      */
    2850     public function hasMultiBytes($str)
    2851     {
    2852         if (function_exists('mb_strlen')) {
    2853             return (strlen($str) > mb_strlen($str, $this->CharSet));
    2854         } else { // Assume no multibytes (we can't handle without mbstring functions anyway)
    2855             return false;
    2856         }
    2857     }
    2858 
    2859     /**
    2860      * Does a string contain any 8-bit chars (in any charset)?
    2861      * @param string $text
    2862      * @return boolean
    2863      */
    2864     public function has8bitChars($text)
    2865     {
    2866         return (boolean)preg_match('/[\x80-\xFF]/', $text);
    2867     }
    2868 
    2869     /**
    2870      * Encode and wrap long multibyte strings for mail headers
    2871      * without breaking lines within a character.
    2872      * Adapted from a function by paravoid
    2873      * @link http://www.php.net/manual/en/function.mb-encode-mimeheader.php#60283
    2874      * @access public
    2875      * @param string $str multi-byte text to wrap encode
    2876      * @param string $linebreak string to use as linefeed/end-of-line
    2877      * @return string
    2878      */
    2879     public function base64EncodeWrapMB($str, $linebreak = null)
    2880     {
    2881         $start = '=?' . $this->CharSet . '?B?';
    2882         $end = '?=';
    2883         $encoded = '';
    2884         if ($linebreak === null) {
    2885             $linebreak = $this->LE;
    2886         }
    2887 
    2888         $mb_length = mb_strlen($str, $this->CharSet);
    2889         // Each line must have length <= 75, including $start and $end
    2890         $length = 75 - strlen($start) - strlen($end);
    2891         // Average multi-byte ratio
    2892         $ratio = $mb_length / strlen($str);
    2893         // Base64 has a 4:3 ratio
    2894         $avgLength = floor($length * $ratio * .75);
    2895 
    2896         for ($i = 0; $i < $mb_length; $i += $offset) {
    2897             $lookBack = 0;
    2898             do {
    2899                 $offset = $avgLength - $lookBack;
    2900                 $chunk = mb_substr($str, $i, $offset, $this->CharSet);
    2901                 $chunk = base64_encode($chunk);
    2902                 $lookBack++;
    2903             } while (strlen($chunk) > $length);
    2904             $encoded .= $chunk . $linebreak;
    2905         }
    2906 
    2907         // Chomp the last linefeed
    2908         $encoded = substr($encoded, 0, -strlen($linebreak));
    2909         return $encoded;
    2910     }
    2911 
    2912     /**
    2913      * Encode a string in quoted-printable format.
    2914      * According to RFC2045 section 6.7.
    2915      * @access public
    2916      * @param string $string The text to encode
    2917      * @param integer $line_max Number of chars allowed on a line before wrapping
    2918      * @return string
    2919      * @link http://www.php.net/manual/en/function.quoted-printable-decode.php#89417 Adapted from this comment
    2920      */
    2921     public function encodeQP($string, $line_max = 76)
    2922     {
    2923         // Use native function if it's available (>= PHP5.3)
    2924         if (function_exists('quoted_printable_encode')) {
    2925             return quoted_printable_encode($string);
    2926         }
    2927         // Fall back to a pure PHP implementation
    2928         $string = str_replace(
     2757                //There are no chars that need encoding
     2758                if ($matchcount == 0) {
     2759                        return ($str);
     2760                }
     2761
     2762                $maxlen = 75 - 7 - strlen($this->CharSet);
     2763                // Try to select the encoding which should produce the shortest output
     2764                if ($matchcount > strlen($str) / 3) {
     2765                        // More than a third of the content will need encoding, so B encoding will be most efficient
     2766                        $encoding = 'B';
     2767                        if (function_exists('mb_strlen') && $this->hasMultiBytes($str)) {
     2768                                // Use a custom function which correctly encodes and wraps long
     2769                                // multibyte strings without breaking lines within a character
     2770                                $encoded = $this->base64EncodeWrapMB($str, "\n");
     2771                        } else {
     2772                                $encoded = base64_encode($str);
     2773                                $maxlen -= $maxlen % 4;
     2774                                $encoded = trim(chunk_split($encoded, $maxlen, "\n"));
     2775                        }
     2776                } else {
     2777                        $encoding = 'Q';
     2778                        $encoded  = $this->encodeQ($str, $position);
     2779                        $encoded  = $this->wrapText($encoded, $maxlen, true);
     2780                        $encoded  = str_replace('=' . self::CRLF, "\n", trim($encoded));
     2781                }
     2782
     2783                $encoded = preg_replace('/^(.*)$/m', ' =?' . $this->CharSet . "?$encoding?\\1?=", $encoded);
     2784                $encoded = trim(str_replace("\n", $this->LE, $encoded));
     2785
     2786                return $encoded;
     2787        }
     2788
     2789        /**
     2790         * Check if a string contains multi-byte characters.
     2791         * @access public
     2792         * @param string $str multi-byte text to wrap encode
     2793         * @return boolean
     2794         */
     2795        public function hasMultiBytes($str) {
     2796                if (function_exists('mb_strlen')) {
     2797                        return (strlen($str) > mb_strlen($str, $this->CharSet));
     2798                } else { // Assume no multibytes (we can't handle without mbstring functions anyway)
     2799                        return false;
     2800                }
     2801        }
     2802
     2803        /**
     2804         * Does a string contain any 8-bit chars (in any charset)?
     2805         * @param string $text
     2806         * @return boolean
     2807         */
     2808        public function has8bitChars($text) {
     2809                return (boolean) preg_match('/[\x80-\xFF]/', $text);
     2810        }
     2811
     2812        /**
     2813         * Encode and wrap long multibyte strings for mail headers
     2814         * without breaking lines within a character.
     2815         * Adapted from a function by paravoid
     2816         * @link http://www.php.net/manual/en/function.mb-encode-mimeheader.php#60283
     2817         * @access public
     2818         * @param string $str multi-byte text to wrap encode
     2819         * @param string $linebreak string to use as linefeed/end-of-line
     2820         * @return string
     2821         */
     2822        public function base64EncodeWrapMB($str, $linebreak = null) {
     2823                $start   = '=?' . $this->CharSet . '?B?';
     2824                $end     = '?=';
     2825                $encoded = '';
     2826                if ($linebreak === null) {
     2827                        $linebreak = $this->LE;
     2828                }
     2829
     2830                $mb_length = mb_strlen($str, $this->CharSet);
     2831                // Each line must have length <= 75, including $start and $end
     2832                $length = 75 - strlen($start) - strlen($end);
     2833                // Average multi-byte ratio
     2834                $ratio = $mb_length / strlen($str);
     2835                // Base64 has a 4:3 ratio
     2836                $avgLength = floor($length * $ratio * .75);
     2837
     2838                for ($i = 0; $i < $mb_length; $i += $offset) {
     2839                        $lookBack = 0;
     2840                        do {
     2841                                $offset = $avgLength - $lookBack;
     2842                                $chunk  = mb_substr($str, $i, $offset, $this->CharSet);
     2843                                $chunk  = base64_encode($chunk);
     2844                                $lookBack++;
     2845                        } while (strlen($chunk) > $length);
     2846                        $encoded .= $chunk . $linebreak;
     2847                }
     2848
     2849                // Chomp the last linefeed
     2850                $encoded = substr($encoded, 0, -strlen($linebreak));
     2851                return $encoded;
     2852        }
     2853
     2854        /**
     2855         * Encode a string in quoted-printable format.
     2856         * According to RFC2045 section 6.7.
     2857         * @access public
     2858         * @param string $string The text to encode
     2859         * @param integer $line_max Number of chars allowed on a line before wrapping
     2860         * @return string
     2861         * @link http://www.php.net/manual/en/function.quoted-printable-decode.php#89417 Adapted from this comment
     2862         */
     2863        public function encodeQP($string, $line_max = 76) {
     2864                // Use native function if it's available (>= PHP5.3)
     2865                if (function_exists('quoted_printable_encode')) {
     2866                        return quoted_printable_encode($string);
     2867                }
     2868                // Fall back to a pure PHP implementation
     2869                $string = str_replace(
    29292870            array('%20', '%0D%0A.', '%0D%0A', '%'),
    29302871            array(' ', "\r\n=2E", "\r\n", '='),
    29312872            rawurlencode($string)
    29322873        );
    2933         return preg_replace('/[^\r\n]{' . ($line_max - 3) . '}[^=\r\n]{2}/', "$0=\r\n", $string);
    2934     }