WordPress.org

Make WordPress Core

Changeset 39725 for branches/4.3/src


Ignore:
Timestamp:
01/06/2017 05:42:02 AM (3 years ago)
Author:
dd32
Message:

Mail: Upgrade PHPMailer to 5.2.21.

Merges [39645], [36083] to the 4.3 branch.
See #37210.

Location:
branches/4.3
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • branches/4.3

  • branches/4.3/src/wp-includes/class-phpmailer.php

    r33142 r39725  
    3030    /**
    3131     * The PHPMailer Version number.
    32      * @type string
    33      */
    34     public $Version = '5.2.10';
     32     * @var string
     33     */
     34    public $Version = '5.2.21';
    3535
    3636    /**
    3737     * Email priority.
    38      * Options: 1 = High, 3 = Normal, 5 = low.
    39      * @type integer
    40      */
    41     public $Priority = 3;
     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;
    4243
    4344    /**
    4445     * The character set of the message.
    45      * @type string
     46     * @var string
    4647     */
    4748    public $CharSet = 'iso-8859-1';
     
    4950    /**
    5051     * The MIME Content-type of the message.
    51      * @type string
     52     * @var string
    5253     */
    5354    public $ContentType = 'text/plain';
     
    5657     * The message encoding.
    5758     * Options: "8bit", "7bit", "binary", "base64", and "quoted-printable".
    58      * @type string
     59     * @var string
    5960     */
    6061    public $Encoding = '8bit';
     
    6263    /**
    6364     * Holds the most recent mailer error message.
    64      * @type string
     65     * @var string
    6566     */
    6667    public $ErrorInfo = '';
     
    6869    /**
    6970     * The From email address for the message.
    70      * @type string
     71     * @var string
    7172     */
    7273    public $From = 'root@localhost';
     
    7475    /**
    7576     * The From name of the message.
    76      * @type string
     77     * @var string
    7778     */
    7879    public $FromName = 'Root User';
     
    8182     * The Sender email (Return-Path) of the message.
    8283     * If not empty, will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode.
    83      * @type string
     84     * @var string
    8485     */
    8586    public $Sender = '';
     
    8889     * The Return-Path of the message.
    8990     * If empty, it will be set to either From or Sender.
    90      * @type string
     91     * @var string
    9192     * @deprecated Email senders should never set a return-path header;
    9293     * it's the receiver's job (RFC5321 section 4.4), so this no longer does anything.
     
    9798    /**
    9899     * The Subject of the message.
    99      * @type string
     100     * @var string
    100101     */
    101102    public $Subject = '';
     
    104105     * An HTML or plain text message body.
    105106     * If HTML then call isHTML(true).
    106      * @type string
     107     * @var string
    107108     */
    108109    public $Body = '';
     
    113114     * capability such as mutt & Eudora.
    114115     * Clients that can read HTML will view the normal Body.
    115      * @type string
     116     * @var string
    116117     */
    117118    public $AltBody = '';
     
    123124     * @link http://sprain.ch/blog/downloads/php-class-easypeasyics-create-ical-files-with-php/
    124125     * @link http://kigkonsult.se/iCalcreator/
    125      * @type string
     126     * @var string
    126127     */
    127128    public $Ical = '';
     
    130131     * The complete compiled MIME message body.
    131132     * @access protected
    132      * @type string
     133     * @var string
    133134     */
    134135    protected $MIMEBody = '';
     
    136137    /**
    137138     * The complete compiled MIME message headers.
    138      * @type string
     139     * @var string
    139140     * @access protected
    140141     */
     
    143144    /**
    144145     * Extra headers that createHeader() doesn't fold in.
    145      * @type string
     146     * @var string
    146147     * @access protected
    147148     */
     
    151152     * Word-wrap the message body to this number of chars.
    152153     * Set to 0 to not wrap. A useful value here is 78, for RFC2822 section 2.1.1 compliance.
    153      * @type integer
     154     * @var integer
    154155     */
    155156    public $WordWrap = 0;
     
    158159     * Which method to use to send mail.
    159160     * Options: "mail", "sendmail", or "smtp".
    160      * @type string
     161     * @var string
    161162     */
    162163    public $Mailer = 'mail';
     
    164165    /**
    165166     * The path to the sendmail program.
    166      * @type string
     167     * @var string
    167168     */
    168169    public $Sendmail = '/usr/sbin/sendmail';
     
    171172     * Whether mail() uses a fully sendmail-compatible MTA.
    172173     * One which supports sendmail's "-oi -f" options.
    173      * @type boolean
     174     * @var boolean
    174175     */
    175176    public $UseSendmailOptions = true;
     
    178179     * Path to PHPMailer plugins.
    179180     * Useful if the SMTP class is not in the PHP include path.
    180      * @type string
     181     * @var string
    181182     * @deprecated Should not be needed now there is an autoloader.
    182183     */
     
    184185
    185186    /**
    186      * The email address that a reading confirmation should be sent to.
    187      * @type string
     187     * The email address that a reading confirmation should be sent to, also known as read receipt.
     188     * @var string
    188189     */
    189190    public $ConfirmReadingTo = '';
    190191
    191192    /**
    192      * The hostname to use in Message-Id and Received headers
    193      * and as default HELO string.
    194      * If empty, the value returned
    195      * by SERVER_NAME is used or 'localhost.localdomain'.
    196      * @type string
     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
    197198     */
    198199    public $Hostname = '';
    199200
    200201    /**
    201      * An ID to be used in the Message-Id header.
     202     * An ID to be used in the Message-ID header.
    202203     * If empty, a unique id will be generated.
    203      * @type string
     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
    204208     */
    205209    public $MessageID = '';
     
    208212     * The message Date to be used in the Date header.
    209213     * If empty, the current date will be added.
    210      * @type string
     214     * @var string
    211215     */
    212216    public $MessageDate = '';
     
    221225     * (e.g. "tls://smtp1.example.com:587;ssl://smtp2.example.com:465").
    222226     * Hosts will be tried in order.
    223      * @type string
     227     * @var string
    224228     */
    225229    public $Host = 'localhost';
     
    227231    /**
    228232     * The default SMTP server port.
    229      * @type integer
     233     * @var integer
    230234     * @TODO Why is this needed when the SMTP class takes care of it?
    231235     */
     
    234238    /**
    235239     * The SMTP HELO of the message.
    236      * Default is $Hostname.
    237      * @type string
     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
    238243     * @see PHPMailer::$Hostname
    239244     */
     
    243248     * What kind of encryption to use on the SMTP connection.
    244249     * Options: '', 'ssl' or 'tls'
    245      * @type string
     250     * @var string
    246251     */
    247252    public $SMTPSecure = '';
     
    251256     * even if `SMTPSecure` is not set to 'tls'.
    252257     * Be aware that in PHP >= 5.6 this requires that the server's certificates are valid.
    253      * @type boolean
     258     * @var boolean
    254259     */
    255260    public $SMTPAutoTLS = true;
     
    258263     * Whether to use SMTP authentication.
    259264     * Uses the Username and Password properties.
    260      * @type boolean
     265     * @var boolean
    261266     * @see PHPMailer::$Username
    262267     * @see PHPMailer::$Password
     
    266271    /**
    267272     * Options array passed to stream_context_create when connecting via SMTP.
    268      * @type array
     273     * @var array
    269274     */
    270275    public $SMTPOptions = array();
     
    272277    /**
    273278     * SMTP username.
    274      * @type string
     279     * @var string
    275280     */
    276281    public $Username = '';
     
    278283    /**
    279284     * SMTP password.
    280      * @type string
     285     * @var string
    281286     */
    282287    public $Password = '';
     
    284289    /**
    285290     * SMTP auth type.
    286      * Options are LOGIN (default), PLAIN, NTLM, CRAM-MD5
    287      * @type string
     291     * Options are CRAM-MD5, LOGIN, PLAIN, attempted in that order if not specified
     292     * @var string
    288293     */
    289294    public $AuthType = '';
     
    292297     * SMTP realm.
    293298     * Used for NTLM auth
    294      * @type string
     299     * @var string
    295300     */
    296301    public $Realm = '';
     
    299304     * SMTP workstation.
    300305     * Used for NTLM auth
    301      * @type string
     306     * @var string
    302307     */
    303308    public $Workstation = '';
     
    306311     * The SMTP server timeout in seconds.
    307312     * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2
    308      * @type integer
     313     * @var integer
    309314     */
    310315    public $Timeout = 300;
     
    319324     * * `3` As 2 plus connection status
    320325     * * `4` Low-level data output
    321      * @type integer
     326     * @var integer
    322327     * @see SMTP::$do_debug
    323328     */
     
    335340     * $mail->Debugoutput = function($str, $level) {echo "debug level $level; message: $str";};
    336341     * </code>
    337      * @type string|callable
     342     * @var string|callable
    338343     * @see SMTP::$Debugoutput
    339344     */
     
    344349     * If this is set to true then to close the connection
    345350     * requires an explicit call to smtpClose().
    346      * @type boolean
     351     * @var boolean
    347352     */
    348353    public $SMTPKeepAlive = false;
     
    351356     * Whether to split multiple to addresses into multiple messages
    352357     * or send them all in one message.
    353      * @type boolean
     358     * Only supported in `mail` and `sendmail` transports, not in SMTP.
     359     * @var boolean
    354360     */
    355361    public $SingleTo = false;
     
    357363    /**
    358364     * Storage for addresses when SingleTo is enabled.
    359      * @type array
     365     * @var array
    360366     * @TODO This should really not be public
    361367     */
     
    365371     * Whether to generate VERP addresses on send.
    366372     * Only applicable when sending via SMTP.
    367      * @link http://en.wikipedia.org/wiki/Variable_envelope_return_path
     373     * @link https://en.wikipedia.org/wiki/Variable_envelope_return_path
    368374     * @link http://www.postfix.org/VERP_README.html Postfix VERP info
    369      * @type boolean
     375     * @var boolean
    370376     */
    371377    public $do_verp = false;
     
    373379    /**
    374380     * Whether to allow sending messages with an empty body.
    375      * @type boolean
     381     * @var boolean
    376382     */
    377383    public $AllowEmpty = false;
     
    381387     * @note The default remains "\n". We force CRLF where we know
    382388     *        it must be used via self::CRLF.
    383      * @type string
     389     * @var string
    384390     */
    385391    public $LE = "\n";
     
    387393    /**
    388394     * DKIM selector.
    389      * @type string
     395     * @var string
    390396     */
    391397    public $DKIM_selector = '';
     
    393399    /**
    394400     * DKIM Identity.
    395      * Usually the email address used as the source of the email
    396      * @type string
     401     * Usually the email address used as the source of the email.
     402     * @var string
    397403     */
    398404    public $DKIM_identity = '';
     
    401407     * DKIM passphrase.
    402408     * Used if your key is encrypted.
    403      * @type string
     409     * @var string
    404410     */
    405411    public $DKIM_passphrase = '';
     
    408414     * DKIM signing domain name.
    409415     * @example 'example.com'
    410      * @type string
     416     * @var string
    411417     */
    412418    public $DKIM_domain = '';
     
    414420    /**
    415421     * DKIM private key file path.
    416      * @type string
     422     * @var string
    417423     */
    418424    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 = '';
    419432
    420433    /**
     
    434447     *   string  $body          the email body
    435448     *   string  $from          email address of sender
    436      * @type string
     449     * @var string
    437450     */
    438451    public $action_function = '';
     
    441454     * What to put in the X-Mailer header.
    442455     * Options: An empty string for PHPMailer default, whitespace for none, or a string to use
    443      * @type string
     456     * @var string
    444457     */
    445458    public $XMailer = '';
    446459
    447460    /**
     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    /**
    448470     * An instance of the SMTP sender class.
    449      * @type SMTP
     471     * @var SMTP
    450472     * @access protected
    451473     */
     
    453475
    454476    /**
    455      * The array of 'to' addresses.
    456      * @type array
     477     * The array of 'to' names and addresses.
     478     * @var array
    457479     * @access protected
    458480     */
     
    460482
    461483    /**
    462      * The array of 'cc' addresses.
    463      * @type array
     484     * The array of 'cc' names and addresses.
     485     * @var array
    464486     * @access protected
    465487     */
     
    467489
    468490    /**
    469      * The array of 'bcc' addresses.
    470      * @type array
     491     * The array of 'bcc' names and addresses.
     492     * @var array
    471493     * @access protected
    472494     */
     
    475497    /**
    476498     * The array of reply-to names and addresses.
    477      * @type array
     499     * @var array
    478500     * @access protected
    479501     */
     
    483505     * An array of all kinds of addresses.
    484506     * Includes all of $to, $cc, $bcc
    485      * @type array
     507     * @var array
    486508     * @access protected
     509     * @see PHPMailer::$to @see PHPMailer::$cc @see PHPMailer::$bcc
    487510     */
    488511    protected $all_recipients = array();
    489512
    490513    /**
     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    /**
    491536     * The array of attachments.
    492      * @type array
     537     * @var array
    493538     * @access protected
    494539     */
     
    497542    /**
    498543     * The array of custom headers.
    499      * @type array
     544     * @var array
    500545     * @access protected
    501546     */
     
    504549    /**
    505550     * The most recent Message-ID (including angular brackets).
    506      * @type string
     551     * @var string
    507552     * @access protected
    508553     */
     
    511556    /**
    512557     * The message's MIME type.
    513      * @type string
     558     * @var string
    514559     * @access protected
    515560     */
     
    518563    /**
    519564     * The array of MIME boundary strings.
    520      * @type array
     565     * @var array
    521566     * @access protected
    522567     */
     
    525570    /**
    526571     * The array of available languages.
    527      * @type array
     572     * @var array
    528573     * @access protected
    529574     */
     
    532577    /**
    533578     * The number of errors encountered.
    534      * @type integer
     579     * @var integer
    535580     * @access protected
    536581     */
     
    539584    /**
    540585     * The S/MIME certificate file path.
    541      * @type string
     586     * @var string
    542587     * @access protected
    543588     */
     
    546591    /**
    547592     * The S/MIME key file path.
    548      * @type string
     593     * @var string
    549594     * @access protected
    550595     */
     
    553598    /**
    554599     * The optional S/MIME extra certificates ("CA Chain") file path.
    555      * @type string
     600     * @var string
    556601     * @access protected
    557602     */
     
    561606     * The S/MIME password for the key.
    562607     * Used only if the key is encrypted.
    563      * @type string
     608     * @var string
    564609     * @access protected
    565610     */
     
    568613    /**
    569614     * Whether to throw exceptions for errors.
    570      * @type boolean
     615     * @var boolean
    571616     * @access protected
    572617     */
     
    575620    /**
    576621     * Unique ID used for message ID and boundaries.
    577      * @type string
     622     * @var string
    578623     * @access protected
    579624     */
     
    602647    /**
    603648     * The maximum line length allowed by RFC 2822 section 2.1.1
    604      * @type integer
     649     * @var integer
    605650     */
    606651    const MAX_LINE_LENGTH = 998;
     
    610655     * @param boolean $exceptions Should we throw external exceptions?
    611656     */
    612     public function __construct($exceptions = false)
    613     {
    614         $this->exceptions = (boolean)$exceptions;
     657    public function __construct($exceptions = null)
     658    {
     659        if ($exceptions !== null) {
     660            $this->exceptions = (boolean)$exceptions;
     661        }
    615662    }
    616663
     
    621668    {
    622669        //Close any open SMTP connection nicely
    623         if ($this->Mailer == 'smtp') {
    624             $this->smtpClose();
    625         }
     670        $this->smtpClose();
    626671    }
    627672
     
    647692            $subject = $this->encodeHeader($this->secureHeader($subject));
    648693        }
    649         if (ini_get('safe_mode') || !($this->UseSendmailOptions)) {
     694
     695        //Can't use additional_parameters in safe_mode, calling mail() with null params breaks
     696        //@link http://php.net/manual/en/function.mail.php
     697        if (ini_get('safe_mode') or !$this->UseSendmailOptions or is_null($params)) {
    650698            $result = @mail($to, $subject, $body, $header);
    651699        } else {
     
    654702        return $result;
    655703    }
    656 
    657704    /**
    658705     * Output debugging info via user-defined method.
     
    689736            default:
    690737                //Normalize line breaks
    691                 $str = preg_replace('/(\r\n|\r|\n)/ms', "\n", $str);
     738                $str = preg_replace('/\r\n?/ms', "\n", $str);
    692739                echo gmdate('Y-m-d H:i:s') . "\t" . str_replace(
    693740                    "\n",
     
    764811    /**
    765812     * Add a "To" address.
    766      * @param string $address
     813     * @param string $address The email address to send to
    767814     * @param string $name
    768      * @return boolean true on success, false if address already used
     815     * @return boolean true on success, false if address already used or invalid in some way
    769816     */
    770817    public function addAddress($address, $name = '')
    771818    {
    772         return $this->addAnAddress('to', $address, $name);
     819        return $this->addOrEnqueueAnAddress('to', $address, $name);
    773820    }
    774821
     
    776823     * Add a "CC" address.
    777824     * @note: This function works with the SMTP mailer on win32, not with the "mail" mailer.
    778      * @param string $address
     825     * @param string $address The email address to send to
    779826     * @param string $name
    780      * @return boolean true on success, false if address already used
     827     * @return boolean true on success, false if address already used or invalid in some way
    781828     */
    782829    public function addCC($address, $name = '')
    783830    {
    784         return $this->addAnAddress('cc', $address, $name);
     831        return $this->addOrEnqueueAnAddress('cc', $address, $name);
    785832    }
    786833
     
    788835     * Add a "BCC" address.
    789836     * @note: This function works with the SMTP mailer on win32, not with the "mail" mailer.
    790      * @param string $address
     837     * @param string $address The email address to send to
    791838     * @param string $name
    792      * @return boolean true on success, false if address already used
     839     * @return boolean true on success, false if address already used or invalid in some way
    793840     */
    794841    public function addBCC($address, $name = '')
    795842    {
    796         return $this->addAnAddress('bcc', $address, $name);
    797     }
    798 
    799     /**
    800      * Add a "Reply-to" address.
    801      * @param string $address
     843        return $this->addOrEnqueueAnAddress('bcc', $address, $name);
     844    }
     845
     846    /**
     847     * Add a "Reply-To" address.
     848     * @param string $address The email address to reply to
    802849     * @param string $name
    803      * @return boolean
     850     * @return boolean true on success, false if address already used or invalid in some way
    804851     */
    805852    public function addReplyTo($address, $name = '')
    806853    {
    807         return $this->addAnAddress('Reply-To', $address, $name);
    808     }
    809 
    810     /**
    811      * Add an address to one of the recipient arrays.
    812      * Addresses that have been added already return false, but do not throw exceptions
    813      * @param string $kind One of 'to', 'cc', 'bcc', 'ReplyTo'
    814      * @param string $address The email address to send to
     854        return $this->addOrEnqueueAnAddress('Reply-To', $address, $name);
     855    }
     856
     857    /**
     858     * Add an address to one of the recipient arrays or to the ReplyTo array. Because PHPMailer
     859     * can't validate addresses with an IDN without knowing the PHPMailer::$CharSet (that can still
     860     * be modified after calling this function), addition of such addresses is delayed until send().
     861     * Addresses that have been added already return false, but do not throw exceptions.
     862     * @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo'
     863     * @param string $address The email address to send, resp. to reply to
    815864     * @param string $name
    816865     * @throws phpmailerException
     
    818867     * @access protected
    819868     */
    820     protected function addAnAddress($kind, $address, $name = '')
    821     {
    822         if (!preg_match('/^(to|cc|bcc|Reply-To)$/', $kind)) {
    823             $this->setError($this->lang('Invalid recipient array') . ': ' . $kind);
    824             $this->edebug($this->lang('Invalid recipient array') . ': ' . $kind);
    825             if ($this->exceptions) {
    826                 throw new phpmailerException('Invalid recipient array: ' . $kind);
    827             }
    828             return false;
    829         }
     869    protected function addOrEnqueueAnAddress($kind, $address, $name)
     870    {
    830871        $address = trim($address);
    831872        $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
     873        if (($pos = strrpos($address, '@')) === false) {
     874            // At-sign is misssing.
     875            $error_message = $this->lang('invalid_address') . " (addAnAddress $kind): $address";
     876            $this->setError($error_message);
     877            $this->edebug($error_message);
     878            if ($this->exceptions) {
     879                throw new phpmailerException($error_message);
     880            }
     881            return false;
     882        }
     883        $params = array($kind, $address, $name);
     884        // Enqueue addresses with IDN until we know the PHPMailer::$CharSet.
     885        if ($this->has8bitChars(substr($address, ++$pos)) and $this->idnSupported()) {
     886            if ($kind != 'Reply-To') {
     887                if (!array_key_exists($address, $this->RecipientsQueue)) {
     888                    $this->RecipientsQueue[$address] = $params;
     889                    return true;
     890                }
     891            } else {
     892                if (!array_key_exists($address, $this->ReplyToQueue)) {
     893                    $this->ReplyToQueue[$address] = $params;
     894                    return true;
     895                }
     896            }
     897            return false;
     898        }
     899        // Immediately add standard addresses without IDN.
     900        return call_user_func_array(array($this, 'addAnAddress'), $params);
     901    }
     902
     903    /**
     904     * Add an address to one of the recipient arrays or to the ReplyTo array.
     905     * Addresses that have been added already return false, but do not throw exceptions.
     906     * @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo'
     907     * @param string $address The email address to send, resp. to reply to
     908     * @param string $name
     909     * @throws phpmailerException
     910     * @return boolean true on success, false if address already used or invalid in some way
     911     * @access protected
     912     */
     913    protected function addAnAddress($kind, $address, $name = '')
     914    {
     915        if (!in_array($kind, array('to', 'cc', 'bcc', 'Reply-To'))) {
     916            $error_message = $this->lang('Invalid recipient kind: ') . $kind;
     917            $this->setError($error_message);
     918            $this->edebug($error_message);
     919            if ($this->exceptions) {
     920                throw new phpmailerException($error_message);
     921            }
     922            return false;
     923        }
    832924        if (!$this->validateAddress($address)) {
    833             $this->setError($this->lang('invalid_address') . ': ' . $address);
    834             $this->edebug($this->lang('invalid_address') . ': ' . $address);
     925            $error_message = $this->lang('invalid_address') . " (addAnAddress $kind): $address";
     926            $this->setError($error_message);
     927            $this->edebug($error_message);
    835928            if ($this->exceptions) {
    836                 throw new phpmailerException($this->lang('invalid_address') . ': ' . $address);
     929                throw new phpmailerException($error_message);
    837930            }
    838931            return false;
    839932        }
    840933        if ($kind != 'Reply-To') {
    841             if (!isset($this->all_recipients[strtolower($address)])) {
     934            if (!array_key_exists(strtolower($address), $this->all_recipients)) {
    842935                array_push($this->$kind, array($address, $name));
    843936                $this->all_recipients[strtolower($address)] = true;
     
    851944        }
    852945        return false;
     946    }
     947
     948    /**
     949     * Parse and validate a string containing one or more RFC822-style comma-separated email addresses
     950     * of the form "display name <address>" into an array of name/address pairs.
     951     * Uses the imap_rfc822_parse_adrlist function if the IMAP extension is available.
     952     * Note that quotes in the name part are removed.
     953     * @param string $addrstr The address list string
     954     * @param bool $useimap Whether to use the IMAP extension to parse the list
     955     * @return array
     956     * @link http://www.andrew.cmu.edu/user/agreen1/testing/mrbs/web/Mail/RFC822.php A more careful implementation
     957     */
     958    public function parseAddresses($addrstr, $useimap = true)
     959    {
     960        $addresses = array();
     961        if ($useimap and function_exists('imap_rfc822_parse_adrlist')) {
     962            //Use this built-in parser if it's available
     963            $list = imap_rfc822_parse_adrlist($addrstr, '');
     964            foreach ($list as $address) {
     965                if ($address->host != '.SYNTAX-ERROR.') {
     966                    if ($this->validateAddress($address->mailbox . '@' . $address->host)) {
     967                        $addresses[] = array(
     968                            'name' => (property_exists($address, 'personal') ? $address->personal : ''),
     969                            'address' => $address->mailbox . '@' . $address->host
     970                        );
     971                    }
     972                }
     973            }
     974        } else {
     975            //Use this simpler parser
     976            $list = explode(',', $addrstr);
     977            foreach ($list as $address) {
     978                $address = trim($address);
     979                //Is there a separate name part?
     980                if (strpos($address, '<') === false) {
     981                    //No separate name, just use the whole thing
     982                    if ($this->validateAddress($address)) {
     983                        $addresses[] = array(
     984                            'name' => '',
     985                            'address' => $address
     986                        );
     987                    }
     988                } else {
     989                    list($name, $email) = explode('<', $address);
     990                    $email = trim(str_replace('>', '', $email));
     991                    if ($this->validateAddress($email)) {
     992                        $addresses[] = array(
     993                            'name' => trim(str_replace(array('"', "'"), '', $name)),
     994                            'address' => $email
     995                        );
     996                    }
     997                }
     998            }
     999        }
     1000        return $addresses;
    8531001    }
    8541002
     
    8651013        $address = trim($address);
    8661014        $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
    867         if (!$this->validateAddress($address)) {
    868             $this->setError($this->lang('invalid_address') . ': ' . $address);
    869             $this->edebug($this->lang('invalid_address') . ': ' . $address);
     1015        // Don't validate now addresses with IDN. Will be done in send().
     1016        if (($pos = strrpos($address, '@')) === false or
     1017            (!$this->has8bitChars(substr($address, ++$pos)) or !$this->idnSupported()) and
     1018            !$this->validateAddress($address)) {
     1019            $error_message = $this->lang('invalid_address') . " (setFrom) $address";
     1020            $this->setError($error_message);
     1021            $this->edebug($error_message);
    8701022            if ($this->exceptions) {
    871                 throw new phpmailerException($this->lang('invalid_address') . ': ' . $address);
     1023                throw new phpmailerException($error_message);
    8721024            }
    8731025            return false;
     
    8981050     * Check that a string looks like an email address.
    8991051     * @param string $address The email address to check
    900      * @param string $patternselect A selector for the validation pattern to use :
    901      * * `auto` Pick strictest one automatically;
     1052     * @param string|callable $patternselect A selector for the validation pattern to use :
     1053     * * `auto` Pick best pattern automatically;
    9021054     * * `pcre8` Use the squiloople.com pattern, requires PCRE > 8.0, PHP >= 5.3.2, 5.2.14;
    9031055     * * `pcre` Use old PCRE implementation;
    904      * * `php` Use PHP built-in FILTER_VALIDATE_EMAIL; same as pcre8 but does not allow 'dotless' domains;
     1056     * * `php` Use PHP built-in FILTER_VALIDATE_EMAIL;
    9051057     * * `html5` Use the pattern given by the HTML5 spec for 'email' type form input elements.
    9061058     * * `noregex` Don't use a regex: super fast, really dumb.
     1059     * Alternatively you may pass in a callable to inject your own validator, for example:
     1060     * PHPMailer::validateAddress('user@example.com', function($address) {
     1061     *     return (strpos($address, '@') !== false);
     1062     * });
     1063     * You can also set the PHPMailer::$validator static to a callable, allowing built-in methods to use your validator.
    9071064     * @return boolean
    9081065     * @static
    9091066     * @access public
    9101067     */
    911     public static function validateAddress($address, $patternselect = 'auto')
    912     {
     1068    public static function validateAddress($address, $patternselect = null)
     1069    {
     1070        if (is_null($patternselect)) {
     1071            $patternselect = self::$validator;
     1072        }
     1073        if (is_callable($patternselect)) {
     1074            return call_user_func($patternselect, $address);
     1075        }
     1076        //Reject line breaks in addresses; it's valid RFC5322, but not RFC5321
     1077        if (strpos($address, "\n") !== false or strpos($address, "\r") !== false) {
     1078            return false;
     1079        }
    9131080        if (!$patternselect or $patternselect == 'auto') {
    9141081            //Check this constant first so it works when extension_loaded() is disabled by safe mode
     
    9911158
    9921159    /**
     1160     * Tells whether IDNs (Internationalized Domain Names) are supported or not. This requires the
     1161     * "intl" and "mbstring" PHP extensions.
     1162     * @return bool "true" if required functions for IDN support are present
     1163     */
     1164    public function idnSupported()
     1165    {
     1166        // @TODO: Write our own "idn_to_ascii" function for PHP <= 5.2.
     1167        return function_exists('idn_to_ascii') and function_exists('mb_convert_encoding');
     1168    }
     1169
     1170    /**
     1171     * Converts IDN in given email address to its ASCII form, also known as punycode, if possible.
     1172     * Important: Address must be passed in same encoding as currently set in PHPMailer::$CharSet.
     1173     * This function silently returns unmodified address if:
     1174     * - No conversion is necessary (i.e. domain name is not an IDN, or is already in ASCII form)
     1175     * - Conversion to punycode is impossible (e.g. required PHP functions are not available)
     1176     *   or fails for any reason (e.g. domain has characters not allowed in an IDN)
     1177     * @see PHPMailer::$CharSet
     1178     * @param string $address The email address to convert
     1179     * @return string The encoded address in ASCII form
     1180     */
     1181    public function punyencodeAddress($address)
     1182    {
     1183        // Verify we have required functions, CharSet, and at-sign.
     1184        if ($this->idnSupported() and
     1185            !empty($this->CharSet) and
     1186            ($pos = strrpos($address, '@')) !== false) {
     1187            $domain = substr($address, ++$pos);
     1188            // Verify CharSet string is a valid one, and domain properly encoded in this CharSet.
     1189            if ($this->has8bitChars($domain) and @mb_check_encoding($domain, $this->CharSet)) {
     1190                $domain = mb_convert_encoding($domain, 'UTF-8', $this->CharSet);
     1191                if (($punycode = defined('INTL_IDNA_VARIANT_UTS46') ?
     1192                    idn_to_ascii($domain, 0, INTL_IDNA_VARIANT_UTS46) :
     1193                    idn_to_ascii($domain)) !== false) {
     1194                    return substr($address, 0, $pos) . $punycode;
     1195                }
     1196            }
     1197        }
     1198        return $address;
     1199    }
     1200
     1201    /**
    9931202     * Create a message and send it.
    9941203     * Uses the sending method specified by $Mailer.
     
    10211230    {
    10221231        try {
     1232            $this->error_count = 0; // Reset errors
    10231233            $this->mailHeader = '';
     1234
     1235            // Dequeue recipient and Reply-To addresses with IDN
     1236            foreach (array_merge($this->RecipientsQueue, $this->ReplyToQueue) as $params) {
     1237                $params[1] = $this->punyencodeAddress($params[1]);
     1238                call_user_func_array(array($this, 'addAnAddress'), $params);
     1239            }
    10241240            if ((count($this->to) + count($this->cc) + count($this->bcc)) < 1) {
    10251241                throw new phpmailerException($this->lang('provide_address'), self::STOP_CRITICAL);
    10261242            }
    10271243
     1244            // Validate From, Sender, and ConfirmReadingTo addresses
     1245            foreach (array('From', 'Sender', 'ConfirmReadingTo') as $address_kind) {
     1246                $this->$address_kind = trim($this->$address_kind);
     1247                if (empty($this->$address_kind)) {
     1248                    continue;
     1249                }
     1250                $this->$address_kind = $this->punyencodeAddress($this->$address_kind);
     1251                if (!$this->validateAddress($this->$address_kind)) {
     1252                    $error_message = $this->lang('invalid_address') . ' (punyEncode) ' . $this->$address_kind;
     1253                    $this->setError($error_message);
     1254                    $this->edebug($error_message);
     1255                    if ($this->exceptions) {
     1256                        throw new phpmailerException($error_message);
     1257                    }
     1258                    return false;
     1259                }
     1260            }
     1261
    10281262            // Set whether the message is multipart/alternative
    1029             if (!empty($this->AltBody)) {
     1263            if ($this->alternativeExists()) {
    10301264                $this->ContentType = 'multipart/alternative';
    10311265            }
    10321266
    1033             $this->error_count = 0; // Reset errors
    10341267            $this->setMessageType();
    10351268            // Refuse to send an empty message unless we are specifically allowing it
     
    10621295            // Sign with DKIM if enabled
    10631296            if (!empty($this->DKIM_domain)
    1064                 && !empty($this->DKIM_private)
    10651297                && !empty($this->DKIM_selector)
    1066                 && file_exists($this->DKIM_private)) {
     1298                && (!empty($this->DKIM_private_string)
     1299                   || (!empty($this->DKIM_private) && file_exists($this->DKIM_private))
     1300                )
     1301            ) {
    10671302                $header_dkim = $this->DKIM_Add(
    10681303                    $this->MIMEHeader . $this->mailHeader,
     
    11301365    protected function sendmailSend($header, $body)
    11311366    {
    1132         if ($this->Sender != '') {
     1367        // CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
     1368        if (!empty($this->Sender) and self::isShellSafe($this->Sender)) {
    11331369            if ($this->Mailer == 'qmail') {
    1134                 $sendmail = sprintf('%s -f%s', escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
     1370                $sendmailFmt = '%s -f%s';
    11351371            } else {
    1136                 $sendmail = sprintf('%s -oi -f%s -t', escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
     1372                $sendmailFmt = '%s -oi -f%s -t';
    11371373            }
    11381374        } else {
    11391375            if ($this->Mailer == 'qmail') {
    1140                 $sendmail = sprintf('%s', escapeshellcmd($this->Sendmail));
     1376                $sendmailFmt = '%s';
    11411377            } else {
    1142                 $sendmail = sprintf('%s -oi -t', escapeshellcmd($this->Sendmail));
    1143             }
    1144         }
     1378                $sendmailFmt = '%s -oi -t';
     1379            }
     1380        }
     1381
     1382        // TODO: If possible, this should be changed to escapeshellarg.  Needs thorough testing.
     1383        $sendmail = sprintf($sendmailFmt, escapeshellcmd($this->Sendmail), $this->Sender);
     1384
    11451385        if ($this->SingleTo) {
    11461386            foreach ($this->SingleToArray as $toAddr) {
     
    11721412            fputs($mail, $body);
    11731413            $result = pclose($mail);
    1174             $this->doCallback(($result == 0), $this->to, $this->cc, $this->bcc, $this->Subject, $body, $this->From);
     1414            $this->doCallback(
     1415                ($result == 0),
     1416                $this->to,
     1417                $this->cc,
     1418                $this->bcc,
     1419                $this->Subject,
     1420                $body,
     1421                $this->From
     1422            );
    11751423            if ($result != 0) {
    11761424                throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
    11771425            }
    11781426        }
     1427        return true;
     1428    }
     1429
     1430    /**
     1431     * Fix CVE-2016-10033 and CVE-2016-10045 by disallowing potentially unsafe shell characters.
     1432     *
     1433     * Note that escapeshellarg and escapeshellcmd are inadequate for our purposes, especially on Windows.
     1434     * @param string $string The string to be validated
     1435     * @see https://github.com/PHPMailer/PHPMailer/issues/924 CVE-2016-10045 bug report
     1436     * @access protected
     1437     * @return boolean
     1438     */
     1439    protected static function isShellSafe($string)
     1440    {
     1441        // Future-proof
     1442        if (escapeshellcmd($string) !== $string
     1443            or !in_array(escapeshellarg($string), array("'$string'", "\"$string\""))
     1444        ) {
     1445            return false;
     1446        }
     1447
     1448        $length = strlen($string);
     1449
     1450        for ($i = 0; $i < $length; $i++) {
     1451            $c = $string[$i];
     1452
     1453            // All other characters have a special meaning in at least one common shell, including = and +.
     1454            // Full stop (.) has a special meaning in cmd.exe, but its impact should be negligible here.
     1455            // Note that this does permit non-Latin alphanumeric characters based on the current locale.
     1456            if (!ctype_alnum($c) && strpos('@_-.', $c) === false) {
     1457                return false;
     1458            }
     1459        }
     1460
    11791461        return true;
    11801462    }
     
    11971479        $to = implode(', ', $toArr);
    11981480
    1199         if (empty($this->Sender)) {
    1200             $params = ' ';
    1201         } else {
    1202             $params = sprintf('-f%s', $this->Sender);
    1203         }
    1204         if ($this->Sender != '' and !ini_get('safe_mode')) {
     1481        $params = null;
     1482        //This sets the SMTP envelope sender which gets turned into a return-path header by the receiver
     1483        if (!empty($this->Sender) and $this->validateAddress($this->Sender)) {
     1484            // CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
     1485            if (self::isShellSafe($this->Sender)) {
     1486                $params = sprintf('-f%s', $this->Sender);
     1487            }
     1488        }
     1489        if (!empty($this->Sender) and !ini_get('safe_mode') and $this->validateAddress($this->Sender)) {
    12051490            $old_from = ini_get('sendmail_from');
    12061491            ini_set('sendmail_from', $this->Sender);
    12071492        }
    12081493        $result = false;
    1209         if ($this->SingleTo && count($toArr) > 1) {
     1494        if ($this->SingleTo and count($toArr) > 1) {
    12101495            foreach ($toArr as $toAddr) {
    12111496                $result = $this->mailPassthru($toAddr, $this->Subject, $body, $header, $params);
     
    12571542            throw new phpmailerException($this->lang('smtp_connect_failed'), self::STOP_CRITICAL);
    12581543        }
    1259         if ('' == $this->Sender) {
     1544        if (!empty($this->Sender) and $this->validateAddress($this->Sender)) {
     1545            $smtp_from = $this->Sender;
     1546        } else {
    12601547            $smtp_from = $this->From;
    1261         } else {
    1262             $smtp_from = $this->Sender;
    12631548        }
    12641549        if (!$this->smtp->mail($smtp_from)) {
     
    13141599     * @return boolean
    13151600     */
    1316     public function smtpConnect($options = array())
     1601    public function smtpConnect($options = null)
    13171602    {
    13181603        if (is_null($this->smtp)) {
    13191604            $this->smtp = $this->getSMTPInstance();
     1605        }
     1606
     1607        //If no options are provided, use whatever is set in the instance
     1608        if (is_null($options)) {
     1609            $options = $this->SMTPOptions;
    13201610        }
    13211611
     
    13891679                            throw new phpmailerException($this->lang('connect_host'));
    13901680                        }
    1391                         // We must resend HELO after tls negotiation
     1681                        // We must resend EHLO after TLS negotiation
    13921682                        $this->smtp->hello($hello);
    13931683                    }
     
    14281718    public function smtpClose()
    14291719    {
    1430         if ($this->smtp !== null) {
     1720        if (is_a($this->smtp, 'SMTP')) {
    14311721            if ($this->smtp->connected()) {
    14321722                $this->smtp->quit();
     
    14471737    public function setLanguage($langcode = 'en', $lang_path = '')
    14481738    {
     1739        // Backwards compatibility for renamed language codes
     1740        $renamed_langcodes = array(
     1741            'br' => 'pt_br',
     1742            'cz' => 'cs',
     1743            'dk' => 'da',
     1744            'no' => 'nb',
     1745            'se' => 'sv',
     1746        );
     1747
     1748        if (isset($renamed_langcodes[$langcode])) {
     1749            $langcode = $renamed_langcodes[$langcode];
     1750        }
     1751
    14491752        // Define full set of translatable strings in English
    14501753        $PHPMAILER_LANG = array(
     
    14591762            'from_failed' => 'The following From address failed: ',
    14601763            'instantiate' => 'Could not instantiate mail function.',
    1461             'invalid_address' => 'Invalid address',
     1764            'invalid_address' => 'Invalid address: ',
    14621765            'mailer_not_supported' => ' mailer is not supported.',
    14631766            'provide_address' => 'You must provide at least one recipient email address.',
     
    14721775            // Calculate an absolute path so it can work if CWD is not here
    14731776            $lang_path = dirname(__FILE__). DIRECTORY_SEPARATOR . 'language'. DIRECTORY_SEPARATOR;
     1777        }
     1778        //Validate $langcode
     1779        if (!preg_match('/^[a-z]{2}(?:_[a-zA-Z]{2})?$/', $langcode)) {
     1780            $langcode = 'en';
    14741781        }
    14751782        $foundlang = true;
     
    17242031        $result .= $this->headerLine('Date', $this->MessageDate);
    17252032
    1726 
    17272033        // To be created automatically by mail()
    17282034        if ($this->SingleTo) {
     
    17672073        }
    17682074
    1769         if ($this->MessageID != '') {
     2075        // Only allow a custom message ID if it conforms to RFC 5322 section 3.6.4
     2076        // https://tools.ietf.org/html/rfc5322#section-3.6.4
     2077        if ('' != $this->MessageID and preg_match('/^<.*@.*>$/', $this->MessageID)) {
    17702078            $this->lastMessageID = $this->MessageID;
    17712079        } else {
    1772             $this->lastMessageID = sprintf('<%s@%s>', $this->uniqueid, $this->ServerHostname());
     2080            $this->lastMessageID = sprintf('<%s@%s>', $this->uniqueid, $this->serverHostname());
    17732081        }
    17742082        $result .= $this->headerLine('Message-ID', $this->lastMessageID);
    1775         $result .= $this->headerLine('X-Priority', $this->Priority);
     2083        if (!is_null($this->Priority)) {
     2084            $result .= $this->headerLine('X-Priority', $this->Priority);
     2085        }
    17762086        if ($this->XMailer == '') {
    17772087            $result .= $this->headerLine(
    17782088                'X-Mailer',
    1779                 'PHPMailer ' . $this->Version . ' (https://github.com/PHPMailer/PHPMailer/)'
     2089                'PHPMailer ' . $this->Version . ' (https://github.com/PHPMailer/PHPMailer)'
    17802090            );
    17812091        } else {
     
    17872097
    17882098        if ($this->ConfirmReadingTo != '') {
    1789             $result .= $this->headerLine('Disposition-Notification-To', '<' . trim($this->ConfirmReadingTo) . '>');
     2099            $result .= $this->headerLine('Disposition-Notification-To', '<' . $this->ConfirmReadingTo . '>');
    17902100        }
    17912101
     
    18672177    public function getSentMIMEMessage()
    18682178    {
    1869         return $this->MIMEHeader . $this->mailHeader . self::CRLF . $this->MIMEBody;
     2179        return rtrim($this->MIMEHeader . $this->mailHeader, "\n\r") . self::CRLF . self::CRLF . $this->MIMEBody;
     2180    }
     2181
     2182    /**
     2183     * Create unique ID
     2184     * @return string
     2185     */
     2186    protected function generateId() {
     2187        return md5(uniqid(time()));
    18702188    }
    18712189
     
    18812199        $body = '';
    18822200        //Create unique IDs and preset boundaries
    1883         $this->uniqueid = md5(uniqid(time()));
     2201        $this->uniqueid = $this->generateId();
    18842202        $this->boundary[1] = 'b1_' . $this->uniqueid;
    18852203        $this->boundary[2] = 'b2_' . $this->uniqueid;
     
    18972215        if ($bodyEncoding == '8bit' and !$this->has8bitChars($this->Body)) {
    18982216            $bodyEncoding = '7bit';
     2217            //All ISO 8859, Windows codepage and UTF-8 charsets are ascii compatible up to 7-bit
    18992218            $bodyCharSet = 'us-ascii';
    19002219        }
    1901         //If lines are too long, change to quoted-printable transfer encoding
    1902         if (self::hasLineLongerThanMax($this->Body)) {
    1903             $this->Encoding = 'quoted-printable';
     2220        //If lines are too long, and we're not already using an encoding that will shorten them,
     2221        //change to quoted-printable transfer encoding for the body part only
     2222        if ('base64' != $this->Encoding and self::hasLineLongerThanMax($this->Body)) {
    19042223            $bodyEncoding = 'quoted-printable';
    19052224        }
     
    19102229        if ($altBodyEncoding == '8bit' and !$this->has8bitChars($this->AltBody)) {
    19112230            $altBodyEncoding = '7bit';
     2231            //All ISO 8859, Windows codepage and UTF-8 charsets are ascii compatible up to 7-bit
    19122232            $altBodyCharSet = 'us-ascii';
    19132233        }
    1914         //If lines are too long, change to quoted-printable transfer encoding
    1915         if (self::hasLineLongerThanMax($this->AltBody)) {
     2234        //If lines are too long, and we're not already using an encoding that will shorten them,
     2235        //change to quoted-printable transfer encoding for the alt body part only
     2236        if ('base64' != $altBodyEncoding and self::hasLineLongerThanMax($this->AltBody)) {
    19162237            $altBodyEncoding = 'quoted-printable';
    19172238        }
     
    20162337                break;
    20172338            default:
    2018                 // catch case 'plain' and case ''
    2019                 $body .= $this->encodeString($this->Body, $bodyEncoding);
     2339                // Catch case 'plain' and case '', applies to simple `text/plain` and `text/html` body content types
     2340                //Reset the `Encoding` property in case we changed it for line length reasons
     2341                $this->Encoding = $bodyEncoding;
     2342                $body .= $this->encodeString($this->Body, $this->Encoding);
    20202343                break;
    20212344        }
     
    21232446    /**
    21242447     * Set the message type.
    2125      * PHPMailer only supports some preset message types,
    2126      * not arbitrary MIME structures.
     2448     * PHPMailer only supports some preset message types, not arbitrary MIME structures.
    21272449     * @access protected
    21282450     * @return void
     
    21422464        $this->message_type = implode('_', $type);
    21432465        if ($this->message_type == '') {
     2466            //The 'plain' message_type refers to the message having a single body element, not that it is plain-text
    21442467            $this->message_type = 'plain';
    21452468        }
     
    22672590                $disposition = $attachment[6];
    22682591                $cid = $attachment[7];
    2269                 if ($disposition == 'inline' && isset($cidUniq[$cid])) {
     2592                if ($disposition == 'inline' && array_key_exists($cid, $cidUniq)) {
    22702593                    continue;
    22712594                }
     
    22732596
    22742597                $mime[] = sprintf('--%s%s', $boundary, $this->LE);
    2275                 $mime[] = sprintf(
    2276                     'Content-Type: %s; name="%s"%s',
    2277                     $type,
    2278                     $this->encodeHeader($this->secureHeader($name)),
    2279                     $this->LE
    2280                 );
     2598                //Only include a filename property if we have one
     2599                if (!empty($name)) {
     2600                    $mime[] = sprintf(
     2601                        'Content-Type: %s; name="%s"%s',
     2602                        $type,
     2603                        $this->encodeHeader($this->secureHeader($name)),
     2604                        $this->LE
     2605                    );
     2606                } else {
     2607                    $mime[] = sprintf(
     2608                        'Content-Type: %s%s',
     2609                        $type,
     2610                        $this->LE
     2611                    );
     2612                }
    22812613                // RFC1341 part 5 says 7bit is assumed if not specified
    22822614                if ($encoding != '7bit') {
     
    23022634                        );
    23032635                    } else {
    2304                         $mime[] = sprintf(
    2305                             'Content-Disposition: %s; filename=%s%s',
    2306                             $disposition,
    2307                             $encoded_name,
    2308                             $this->LE . $this->LE
    2309                         );
     2636                        if (!empty($encoded_name)) {
     2637                            $mime[] = sprintf(
     2638                                'Content-Disposition: %s; filename=%s%s',
     2639                                $disposition,
     2640                                $encoded_name,
     2641                                $this->LE . $this->LE
     2642                            );
     2643                        } else {
     2644                            $mime[] = sprintf(
     2645                                'Content-Disposition: %s%s',
     2646                                $disposition,
     2647                                $this->LE . $this->LE
     2648                            );
     2649                        }
    23102650                    }
    23112651                } else {
     
    23412681     * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
    23422682     * @throws phpmailerException
    2343      * @see EncodeFile(encodeFile
    23442683     * @access protected
    23452684     * @return string
     
    25612900        // Use native function if it's available (>= PHP5.3)
    25622901        if (function_exists('quoted_printable_encode')) {
    2563             return $this->fixEOL(quoted_printable_encode($string));
     2902            return quoted_printable_encode($string);
    25642903        }
    25652904        // Fall back to a pure PHP implementation
     
    25692908            rawurlencode($string)
    25702909        );
    2571         $string = preg_replace('/[^\r\n]{' . ($line_max - 3) . '}[^=\r\n]{2}/', "$0=\r\n", $string);
    2572         return $this->fixEOL($string);
     2910        return preg_replace('/[^\r\n]{' . ($line_max - 3) . '}[^=\r\n]{2}/', "$0=\r\n", $string);
    25732911    }
    25742912
     
    26392977    }
    26402978
    2641 
    26422979    /**
    26432980     * Add a string or binary attachment (non-filesystem).
     
    27453082    ) {
    27463083        // If a MIME type is not specified, try to work it out from the name
    2747         if ($type == '') {
     3084        if ($type == '' and !empty($name)) {
    27483085            $type = self::filenameToType($name);
    27493086        }
     
    28023139
    28033140    /**
     3141     * Clear queued addresses of given kind.
     3142     * @access protected
     3143     * @param string $kind 'to', 'cc', or 'bcc'
     3144     * @return void
     3145     */
     3146    public function clearQueuedAddresses($kind)
     3147    {
     3148        $RecipientsQueue = $this->RecipientsQueue;
     3149        foreach ($RecipientsQueue as $address => $params) {
     3150            if ($params[0] == $kind) {
     3151                unset($this->RecipientsQueue[$address]);
     3152            }
     3153        }
     3154    }
     3155
     3156    /**
    28043157     * Clear all To recipients.
    28053158     * @return void
     
    28113164        }
    28123165        $this->to = array();
     3166        $this->clearQueuedAddresses('to');
    28133167    }
    28143168
     
    28233177        }
    28243178        $this->cc = array();
     3179        $this->clearQueuedAddresses('cc');
    28253180    }
    28263181
     
    28353190        }
    28363191        $this->bcc = array();
     3192        $this->clearQueuedAddresses('bcc');
    28373193    }
    28383194
     
    28443200    {
    28453201        $this->ReplyTo = array();
     3202        $this->ReplyToQueue = array();
    28463203    }
    28473204
     
    28563213        $this->bcc = array();
    28573214        $this->all_recipients = array();
     3215        $this->RecipientsQueue = array();
    28583216    }
    28593217
     
    30123370
    30133371    /**
    3014      * Returns all custom headers
    3015      *
     3372     * Returns all custom headers.
    30163373     * @return array
    30173374     */
     
    30223379
    30233380    /**
    3024      * Create a message from an HTML string.
    3025      * Automatically makes modifications for inline images and backgrounds
    3026      * and creates a plain-text version by converting the HTML.
    3027      * Overwrites any existing values in $this->Body and $this->AltBody
     3381     * Create a message body from an HTML string.
     3382     * Automatically inlines images and creates a plain-text version by converting the HTML,
     3383     * overwriting any existing values in Body and AltBody.
     3384     * $basedir is used when handling relative image paths, e.g. <img src="images/a.png">
     3385     * will look for an image file in $basedir/images/a.png and convert it to inline.
     3386     * If you don't want to apply these transformations to your HTML, just set Body and AltBody yourself.
    30283387     * @access public
    30293388     * @param string $message HTML message string
    3030      * @param string $basedir baseline directory for path
     3389     * @param string $basedir base directory for relative paths to images
    30313390     * @param boolean|callable $advanced Whether to use the internal HTML to text converter
    3032      *    or your own custom converter @see html2text()
    3033      * @return string $message
     3391     *    or your own custom converter @see PHPMailer::html2text()
     3392     * @return string $message The transformed message Body
    30343393     */
    30353394    public function msgHTML($message, $basedir = '', $advanced = false)
    30363395    {
    30373396        preg_match_all('/(src|background)=["\'](.*)["\']/Ui', $message, $images);
    3038         if (isset($images[2])) {
     3397        if (array_key_exists(2, $images)) {
    30393398            foreach ($images[2] as $imgindex => $url) {
    30403399                // Convert data URIs into embedded images
     
    30473406                    }
    30483407                    $cid = md5($url) . '@phpmailer.0'; // RFC2392 S 2
    3049                     if ($this->addStringEmbeddedImage($data, $cid, '', 'base64', $match[1])) {
     3408                    if ($this->addStringEmbeddedImage($data, $cid, 'embed' . $imgindex, 'base64', $match[1])) {
    30503409                        $message = str_replace(
    30513410                            $images[0][$imgindex],
     
    30543413                        );
    30553414                    }
    3056                 } elseif (!preg_match('#^[A-z]+://#', $url)) {
     3415                } elseif (substr($url, 0, 4) !== 'cid:' && !preg_match('#^[a-z][a-z0-9+.-]*://#i', $url)) {
    30573416                    // Do not change urls for absolute images (thanks to corvuscorax)
     3417                    // Do not change urls that are already inline images
    30583418                    $filename = basename($url);
    30593419                    $directory = dirname($url);
     
    30893449        $this->Body = $this->normalizeBreaks($message);
    30903450        $this->AltBody = $this->normalizeBreaks($this->html2text($message, $advanced));
    3091         if (empty($this->AltBody)) {
     3451        if (!$this->alternativeExists()) {
    30923452            $this->AltBody = 'To view this email message, open it in a program that understands HTML!' .
    30933453                self::CRLF . self::CRLF;
     
    31003460     * This is used by msgHTML().
    31013461     * Note - older versions of this function used a bundled advanced converter
    3102      * which was been removed for license reasons in #232
     3462     * which was been removed for license reasons in #232.
    31033463     * Example usage:
    31043464     * <code>
     
    31453505            'doc'   => 'application/msword',
    31463506            'word'  => 'application/msword',
     3507            'xlsx'  => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
     3508            'xltx'  => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
     3509            'potx'  => 'application/vnd.openxmlformats-officedocument.presentationml.template',
     3510            'ppsx'  => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
     3511            'pptx'  => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
     3512            'sldx'  => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
     3513            'docx'  => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
     3514            'dotx'  => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
     3515            'xlam'  => 'application/vnd.ms-excel.addin.macroEnabled.12',
     3516            'xlsb'  => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
    31473517            'class' => 'application/octet-stream',
    31483518            'dll'   => 'application/octet-stream',
     
    33493719    }
    33503720
    3351 
    33523721    /**
    33533722     * Set the public and private key files and password for S/MIME signing.
     
    33913760     * @param string $signHeader
    33923761     * @throws phpmailerException
    3393      * @return string
     3762     * @return string The DKIM signature value
    33943763     */
    33953764    public function DKIM_Sign($signHeader)
     
    34013770            return '';
    34023771        }
    3403         $privKeyStr = file_get_contents($this->DKIM_private);
    3404         if ($this->DKIM_passphrase != '') {
     3772        $privKeyStr = !empty($this->DKIM_private_string) ? $this->DKIM_private_string : file_get_contents($this->DKIM_private);
     3773        if ('' != $this->DKIM_passphrase) {
    34053774            $privKey = openssl_pkey_get_private($privKeyStr, $this->DKIM_passphrase);
    34063775        } else {
    3407             $privKey = $privKeyStr;
    3408         }
    3409         if (openssl_sign($signHeader, $signature, $privKey)) {
    3410             return base64_encode($signature);
    3411         }
     3776            $privKey = openssl_pkey_get_private($privKeyStr);
     3777        }
     3778        //Workaround for missing digest algorithms in old PHP & OpenSSL versions
     3779        //@link http://stackoverflow.com/a/11117338/333340
     3780        if (version_compare(PHP_VERSION, '5.3.0') >= 0 and
     3781            in_array('sha256WithRSAEncryption', openssl_get_md_methods(true))) {
     3782            if (openssl_sign($signHeader, $signature, $privKey, 'sha256WithRSAEncryption')) {
     3783                openssl_pkey_free($privKey);
     3784                return base64_encode($signature);
     3785            }
     3786        } else {
     3787            $pinfo = openssl_pkey_get_details($privKey);
     3788            $hash = hash('sha256', $signHeader);
     3789            //'Magic' constant for SHA256 from RFC3447
     3790            //@link https://tools.ietf.org/html/rfc3447#page-43
     3791            $t = '3031300d060960864801650304020105000420' . $hash;
     3792            $pslen = $pinfo['bits'] / 8 - (strlen($t) / 2 + 3);
     3793            $eb = pack('H*', '0001' . str_repeat('FF', $pslen) . '00' . $t);
     3794
     3795            if (openssl_private_encrypt($eb, $signature, $privKey, OPENSSL_NO_PADDING)) {
     3796                openssl_pkey_free($privKey);
     3797                return base64_encode($signature);
     3798            }
     3799        }
     3800        openssl_pkey_free($privKey);
    34123801        return '';
    34133802    }
     
    34263815            list($heading, $value) = explode(':', $line, 2);
    34273816            $heading = strtolower($heading);
    3428             $value = preg_replace('/\s+/', ' ', $value); // Compress useless spaces
     3817            $value = preg_replace('/\s{2,}/', ' ', $value); // Compress useless spaces
    34293818            $lines[$key] = $heading . ':' . trim($value); // Don't forget to remove WSP around the value
    34303819        }
     
    34643853    public function DKIM_Add($headers_line, $subject, $body)
    34653854    {
    3466         $DKIMsignatureType = 'rsa-sha1'; // Signature & hash algorithms
     3855        $DKIMsignatureType = 'rsa-sha256'; // Signature & hash algorithms
    34673856        $DKIMcanonicalization = 'relaxed/simple'; // Canonicalization of header/body
    34683857        $DKIMquery = 'dns/txt'; // Query method
     
    34723861        $from_header = '';
    34733862        $to_header = '';
     3863        $date_header = '';
    34743864        $current = '';
    34753865        foreach ($headers as $header) {
     
    34803870                $to_header = $header;
    34813871                $current = 'to_header';
     3872            } elseif (strpos($header, 'Date:') === 0) {
     3873                $date_header = $header;
     3874                $current = 'date_header';
    34823875            } else {
    34833876                if (!empty($$current) && strpos($header, ' =?') === 0) {
     
    34903883        $from = str_replace('|', '=7C', $this->DKIM_QP($from_header));
    34913884        $to = str_replace('|', '=7C', $this->DKIM_QP($to_header));
     3885        $date = str_replace('|', '=7C', $this->DKIM_QP($date_header));
    34923886        $subject = str_replace(
    34933887            '|',
     
    34973891        $body = $this->DKIM_BodyC($body);
    34983892        $DKIMlen = strlen($body); // Length of body
    3499         $DKIMb64 = base64_encode(pack('H*', sha1($body))); // Base64 of packed binary SHA-1 hash of body
     3893        $DKIMb64 = base64_encode(pack('H*', hash('sha256', $body))); // Base64 of packed binary SHA-256 hash of body
    35003894        if ('' == $this->DKIM_identity) {
    35013895            $ident = '';
     
    35103904            ";\r\n" .
    35113905            "\tt=" . $DKIMtime . '; c=' . $DKIMcanonicalization . ";\r\n" .
    3512             "\th=From:To:Subject;\r\n" .
     3906            "\th=From:To:Date:Subject;\r\n" .
    35133907            "\td=" . $this->DKIM_domain . ';' . $ident . "\r\n" .
    35143908            "\tz=$from\r\n" .
    35153909            "\t|$to\r\n" .
     3910            "\t|$date\r\n" .
    35163911            "\t|$subject;\r\n" .
    35173912            "\tbh=" . $DKIMb64 . ";\r\n" .
    35183913            "\tb=";
    35193914        $toSign = $this->DKIM_HeaderC(
    3520             $from_header . "\r\n" . $to_header . "\r\n" . $subject_header . "\r\n" . $dkimhdrs
     3915            $from_header . "\r\n" .
     3916            $to_header . "\r\n" .
     3917            $date_header . "\r\n" .
     3918            $subject_header . "\r\n" .
     3919            $dkimhdrs
    35213920        );
    35223921        $signed = $this->DKIM_Sign($toSign);
     
    35383937    /**
    35393938     * Allows for public read access to 'to' property.
     3939     * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included.
    35403940     * @access public
    35413941     * @return array
     
    35483948    /**
    35493949     * Allows for public read access to 'cc' property.
     3950     * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included.
    35503951     * @access public
    35513952     * @return array
     
    35583959    /**
    35593960     * Allows for public read access to 'bcc' property.
     3961     * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included.
    35603962     * @access public
    35613963     * @return array
     
    35683970    /**
    35693971     * Allows for public read access to 'ReplyTo' property.
     3972     * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included.
    35703973     * @access public
    35713974     * @return array
     
    35783981    /**
    35793982     * Allows for public read access to 'all_recipients' property.
     3983     * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included.
    35803984     * @access public
    35813985     * @return array
  • branches/4.3/src/wp-includes/class-smtp.php

    r33124 r39725  
    2929    /**
    3030     * The PHPMailer SMTP version number.
    31      * @type string
    32      */
    33     const VERSION = '5.2.10';
     31     * @var string
     32     */
     33    const VERSION = '5.2.21';
    3434
    3535    /**
    3636     * SMTP line break constant.
    37      * @type string
     37     * @var string
    3838     */
    3939    const CRLF = "\r\n";
     
    4141    /**
    4242     * The SMTP port to use if one is not specified.
    43      * @type integer
     43     * @var integer
    4444     */
    4545    const DEFAULT_SMTP_PORT = 25;
     
    4747    /**
    4848     * The maximum line length allowed by RFC 2822 section 2.1.1
    49      * @type integer
     49     * @var integer
    5050     */
    5151    const MAX_LINE_LENGTH = 998;
     
    7878    /**
    7979     * The PHPMailer SMTP Version number.
    80      * @type string
     80     * @var string
    8181     * @deprecated Use the `VERSION` constant instead
    8282     * @see SMTP::VERSION
    8383     */
    84     public $Version = '5.2.10';
     84    public $Version = '5.2.21';
    8585
    8686    /**
    8787     * SMTP server port number.
    88      * @type integer
     88     * @var integer
    8989     * @deprecated This is only ever used as a default value, so use the `DEFAULT_SMTP_PORT` constant instead
    9090     * @see SMTP::DEFAULT_SMTP_PORT
     
    9494    /**
    9595     * SMTP reply line ending.
    96      * @type string
     96     * @var string
    9797     * @deprecated Use the `CRLF` constant instead
    9898     * @see SMTP::CRLF
     
    108108     * * self::DEBUG_CONNECTION (`3`) As DEBUG_SERVER plus connection status
    109109     * * self::DEBUG_LOWLEVEL (`4`) Low-level data output, all messages
    110      * @type integer
     110     * @var integer
    111111     */
    112112    public $do_debug = self::DEBUG_OFF;
     
    123123     * $smtp->Debugoutput = function($str, $level) {echo "debug level $level; message: $str";};
    124124     * </code>
    125      * @type string|callable
     125     * @var string|callable
    126126     */
    127127    public $Debugoutput = 'echo';
     
    131131     * @link http://en.wikipedia.org/wiki/Variable_envelope_return_path
    132132     * @link http://www.postfix.org/VERP_README.html Info on VERP
    133      * @type boolean
     133     * @var boolean
    134134     */
    135135    public $do_verp = false;
     
    140140     * This needs to be quite high to function correctly with hosts using greetdelay as an anti-spam measure.
    141141     * @link http://tools.ietf.org/html/rfc2821#section-4.5.3.2
    142      * @type integer
     142     * @var integer
    143143     */
    144144    public $Timeout = 300;
     
    147147     * How long to wait for commands to complete, in seconds.
    148148     * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2
    149      * @type integer
     149     * @var integer
    150150     */
    151151    public $Timelimit = 300;
    152152
     153    /**
     154     * @var array patterns to extract smtp transaction id from smtp reply
     155     * Only first capture group will be use, use non-capturing group to deal with it
     156     * Extend this class to override this property to fulfil your needs.
     157     */
     158    protected $smtp_transaction_id_patterns = array(
     159        'exim' => '/[0-9]{3} OK id=(.*)/',
     160        'sendmail' => '/[0-9]{3} 2.0.0 (.*) Message/',
     161        'postfix' => '/[0-9]{3} 2.0.0 Ok: queued as (.*)/'
     162    );
     163
    153164    /**
    154165     * The socket for the server connection.
    155      * @type resource
     166     * @var resource
    156167     */
    157168    protected $smtp_conn;
     
    159170    /**
    160171     * Error information, if any, for the last SMTP command.
    161      * @type array
     172     * @var array
    162173     */
    163174    protected $error = array(
     
    171182     * The reply the server sent to us for HELO.
    172183     * If null, no HELO string has yet been received.
    173      * @type string|null
     184     * @var string|null
    174185     */
    175186    protected $helo_rply = null;
     
    182193     * Other values can be boolean TRUE or an array containing extension options.
    183194     * If null, no HELO/EHLO string has yet been received.
    184      * @type array|null
     195     * @var array|null
    185196     */
    186197    protected $server_caps = null;
     
    188199    /**
    189200     * The most recent reply received from the server.
    190      * @type string
     201     * @var string
    191202     */
    192203    protected $last_reply = '';
     
    207218        //Avoid clash with built-in function names
    208219        if (!in_array($this->Debugoutput, array('error_log', 'html', 'echo')) and is_callable($this->Debugoutput)) {
    209             call_user_func($this->Debugoutput, $str, $this->do_debug);
     220            call_user_func($this->Debugoutput, $str, $level);
    210221            return;
    211222        }
     
    273284        if ($streamok) {
    274285            $socket_context = stream_context_create($options);
    275             //Suppress errors; connection failures are handled at a higher level
    276             $this->smtp_conn = @stream_socket_client(
     286            set_error_handler(array($this, 'errorHandler'));
     287            $this->smtp_conn = stream_socket_client(
    277288                $host . ":" . $port,
    278289                $errno,
     
    282293                $socket_context
    283294            );
     295            restore_error_handler();
    284296        } else {
    285297            //Fall back to fsockopen which should work in more places, but is missing some features
     
    288300                self::DEBUG_CONNECTION
    289301            );
     302            set_error_handler(array($this, 'errorHandler'));
    290303            $this->smtp_conn = fsockopen(
    291304                $host,
     
    295308                $timeout
    296309            );
     310            restore_error_handler();
    297311        }
    298312        // Verify we connected properly
     
    337351            return false;
    338352        }
     353
     354        //Allow the best TLS version(s) we can
     355        $crypto_method = STREAM_CRYPTO_METHOD_TLS_CLIENT;
     356
     357        //PHP 5.6.7 dropped inclusion of TLS 1.1 and 1.2 in STREAM_CRYPTO_METHOD_TLS_CLIENT
     358        //so add them back in manually if we can
     359        if (defined('STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT')) {
     360            $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT;
     361            $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT;
     362        }
     363
    339364        // Begin encrypted connection
    340365        if (!stream_socket_enable_crypto(
    341366            $this->smtp_conn,
    342367            true,
    343             STREAM_CRYPTO_METHOD_TLS_CLIENT
     368            $crypto_method
    344369        )) {
    345370            return false;
     
    352377     * Must be run after hello().
    353378     * @see hello()
    354      * @param string $username    The user name
    355      * @param string $password    The password
    356      * @param string $authtype    The auth type (PLAIN, LOGIN, NTLM, CRAM-MD5)
    357      * @param string $realm       The auth realm for NTLM
     379     * @param string $username The user name
     380     * @param string $password The password
     381     * @param string $authtype The auth type (PLAIN, LOGIN, CRAM-MD5)
     382     * @param string $realm The auth realm for NTLM
    358383     * @param string $workstation The auth workstation for NTLM
    359      * @access public
    360      * @return boolean True if successfully authenticated.
     384     * @param null|OAuth $OAuth An optional OAuth instance (@see PHPMailerOAuth)
     385     * @return bool True if successfully authenticated.* @access public
    361386     */
    362387    public function authenticate(
     
    365390        $authtype = null,
    366391        $realm = '',
    367         $workstation = ''
     392        $workstation = '',
     393        $OAuth = null
    368394    ) {
    369395        if (!$this->server_caps) {
     
    389415
    390416            if (empty($authtype)) {
    391                 foreach (array('LOGIN', 'CRAM-MD5', 'PLAIN') as $method) {
     417                foreach (array('CRAM-MD5', 'LOGIN', 'PLAIN') as $method) {
    392418                    if (in_array($method, $this->server_caps['AUTH'])) {
    393419                        $authtype = $method;
     
    673699    {
    674700        $this->server_caps = array();
    675         $lines = explode("\n", $this->last_reply);
     701        $lines = explode("\n", $this->helo_rply);
     702
    676703        foreach ($lines as $n => $s) {
     704            //First 4 chars contain response code followed by - or space
    677705            $s = trim(substr($s, 4));
    678             if (!$s) {
     706            if (empty($s)) {
    679707                continue;
    680708            }
     
    686714                } else {
    687715                    $name = array_shift($fields);
    688                     if ($name == 'SIZE') {
    689                         $fields = ($fields) ? $fields[0] : 0;
     716                    switch ($name) {
     717                        case 'SIZE':
     718                            $fields = ($fields ? $fields[0] : 0);
     719                            break;
     720                        case 'AUTH':
     721                            if (!is_array($fields)) {
     722                                $fields = array();
     723                            }
     724                            break;
     725                        default:
     726                            $fields = true;
    690727                    }
    691728                }
    692                 $this->server_caps[$name] = ($fields ? $fields : true);
     729                $this->server_caps[$name] = $fields;
    693730            }
    694731        }
     
    740777     * Returns true if the recipient was accepted false if it was rejected.
    741778     * Implements from rfc 821: RCPT <SP> TO:<forward-path> <CRLF>
    742      * @param string $toaddr The address the message is being sent to
    743      * @access public
    744      * @return boolean
    745      */
    746     public function recipient($toaddr)
     779     * @param string $address The address the message is being sent to
     780     * @access public
     781     * @return boolean
     782     */
     783    public function recipient($address)
    747784    {
    748785        return $this->sendCommand(
    749786            'RCPT TO',
    750             'RCPT TO:<' . $toaddr . '>',
     787            'RCPT TO:<' . $address . '>',
    751788            array(250, 251)
    752789        );
     
    767804    /**
    768805     * Send a command to an SMTP server and check its return code.
    769      * @param string $command       The command name - not sent to the server
     806     * @param string $command The command name - not sent to the server
    770807     * @param string $commandstring The actual command to send
    771      * @param integer|array $expect     One or more expected integer success codes
     808     * @param integer|array $expect One or more expected integer success codes
    772809     * @access protected
    773810     * @return boolean True on success.
     
    777814        if (!$this->connected()) {
    778815            $this->setError("Called $command without being connected");
     816            return false;
     817        }
     818        //Reject line breaks in all commands
     819        if (strpos($commandstring, "\n") !== false or strpos($commandstring, "\r") !== false) {
     820            $this->setError("Command '$command' contained line breaks");
    779821            return false;
    780822        }
     
    9821024        while (is_resource($this->smtp_conn) && !feof($this->smtp_conn)) {
    9831025            $str = @fgets($this->smtp_conn, 515);
    984             $this->edebug("SMTP -> get_lines(): \$data was \"$data\"", self::DEBUG_LOWLEVEL);
    985             $this->edebug("SMTP -> get_lines(): \$str is \"$str\"", self::DEBUG_LOWLEVEL);
     1026            $this->edebug("SMTP -> get_lines(): \$data is \"$data\"", self::DEBUG_LOWLEVEL);
     1027            $this->edebug("SMTP -> get_lines(): \$str is  \"$str\"", self::DEBUG_LOWLEVEL);
    9861028            $data .= $str;
    987             $this->edebug("SMTP -> get_lines(): \$data is \"$data\"", self::DEBUG_LOWLEVEL);
    9881029            // If 4th character is a space, we are done reading, break the loop, micro-optimisation over strlen
    9891030            if ((isset($str[3]) and $str[3] == ' ')) {
     
    11001141        return $this->Timeout;
    11011142    }
     1143
     1144    /**
     1145     * Reports an error number and string.
     1146     * @param integer $errno The error number returned by PHP.
     1147     * @param string $errmsg The error message returned by PHP.
     1148     */
     1149    protected function errorHandler($errno, $errmsg)
     1150    {
     1151        $notice = 'Connection: Failed to connect to server.';
     1152        $this->setError(
     1153            $notice,
     1154            $errno,
     1155            $errmsg
     1156        );
     1157        $this->edebug(
     1158            $notice . ' Error number ' . $errno . '. "Error notice: ' . $errmsg,
     1159            self::DEBUG_CONNECTION
     1160        );
     1161    }
     1162
     1163    /**
     1164     * Will return the ID of the last smtp transaction based on a list of patterns provided
     1165     * in SMTP::$smtp_transaction_id_patterns.
     1166     * If no reply has been received yet, it will return null.
     1167     * If no pattern has been matched, it will return false.
     1168     * @return bool|null|string
     1169     */
     1170    public function getLastTransactionID()
     1171    {
     1172        $reply = $this->getLastReply();
     1173
     1174        if (empty($reply)) {
     1175            return null;
     1176        }
     1177
     1178        foreach($this->smtp_transaction_id_patterns as $smtp_transaction_id_pattern) {
     1179            if(preg_match($smtp_transaction_id_pattern, $reply, $matches)) {
     1180                return $matches[1];
     1181            }
     1182        }
     1183
     1184        return false;
     1185    }
    11021186}
Note: See TracChangeset for help on using the changeset viewer.