WordPress.org

Make WordPress Core

Changeset 50397


Ignore:
Timestamp:
02/21/2021 09:32:41 AM (7 months ago)
Author:
SergeyBiryukov
Message:

External Libraries: Upgrade PHPMailer to version 6.3.0.

This is a maintenance release. Changes include:

  • Handle early connection errors such as 421 during connection and EHLO states.
  • Make the mail() and sendmail transports set the envelope sender the same way as SMTP does, i.e. use whatever From is set to, only falling back to the sendmail_from php.ini setting if From is unset. This avoids errors from the mail() function if Sender is not set explicitly and php.ini is not configured. This is a minor functionality change, so bumps the minor version number.
  • Extend parseAddresses to decode encoded names.

Release notes: https://github.com/PHPMailer/PHPMailer/releases/tag/v6.3.0

For a full list of changes in this update, see the PHPMailer GitHub:
https://github.com/PHPMailer/PHPMailer/compare/v6.2.0...v6.3.0

Props ayeshrajans.
Fixes #52577.

Location:
trunk/src/wp-includes/PHPMailer
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/PHPMailer/PHPMailer.php

    r49713 r50397  
    749749     * @var string
    750750     */
    751     const VERSION = '6.2.0';
     751    const VERSION = '6.3.0';
    752752
    753753    /**
     
    863863        }
    864864        //Calling mail() with null params breaks
     865        $this->edebug('Sending with mail()');
     866        $this->edebug('Sendmail path: ' . ini_get('sendmail_path'));
     867        $this->edebug("Envelope sender: {$this->Sender}");
     868        $this->edebug("To: {$to}");
     869        $this->edebug("Subject: {$subject}");
     870        $this->edebug("Headers: {$header}");
    865871        if (!$this->UseSendmailOptions || null === $params) {
    866872            $result = @mail($to, $subject, $body, $header);
    867873        } else {
     874            $this->edebug("Additional params: {$params}");
    868875            $result = @mail($to, $subject, $body, $header, $params);
    869876        }
    870 
     877        $this->edebug('Result: ' . ($result ? 'true' : 'false'));
    871878        return $result;
    872879    }
    873880
    874881    /**
    875      * Output debugging info via user-defined method.
    876      * Only generates output if SMTP debug output is enabled (@see SMTP::$do_debug).
     882     * Output debugging info via a user-defined method.
     883     * Only generates output if debug output is enabled.
    877884     *
    878885     * @see PHPMailer::$Debugoutput
     
    10711078        $pos = strrpos($address, '@');
    10721079        if (false === $pos) {
    1073             // At-sign is missing.
     1080            //At-sign is missing.
    10741081            $error_message = sprintf(
    10751082                '%s (%s): %s',
     
    10871094        }
    10881095        $params = [$kind, $address, $name];
    1089         // Enqueue addresses with IDN until we know the PHPMailer::$CharSet.
     1096        //Enqueue addresses with IDN until we know the PHPMailer::$CharSet.
    10901097        if (static::idnSupported() && $this->has8bitChars(substr($address, ++$pos))) {
    10911098            if ('Reply-To' !== $kind) {
     
    11041111        }
    11051112
    1106         // Immediately add standard addresses without IDN.
     1113        //Immediately add standard addresses without IDN.
    11071114        return call_user_func_array([$this, 'addAnAddress'], $params);
    11081115    }
     
    11921199                    )
    11931200                ) {
     1201                    //Decode the name part if it's present and encoded
     1202                    if (property_exists($address, 'personal') && preg_match('/^=\?.*\?=$/', $address->personal)) {
     1203                        $address->personal = mb_decode_mimeheader($address->personal);
     1204                    }
     1205
    11941206                    $addresses[] = [
    11951207                        'name' => (property_exists($address, 'personal') ? $address->personal : ''),
     
    12151227                    list($name, $email) = explode('<', $address);
    12161228                    $email = trim(str_replace('>', '', $email));
     1229                    $name = trim($name);
    12171230                    if (static::validateAddress($email)) {
     1231                        //If this name is encoded, decode it
     1232                        if (preg_match('/^=\?.*\?=$/', $name)) {
     1233                            $name = mb_decode_mimeheader($name);
     1234                        }
    12181235                        $addresses[] = [
    1219                             'name' => trim(str_replace(['"', "'"], '', $name)),
     1236                            //Remove any surrounding quotes and spaces from the name
     1237                            'name' => trim($name, '\'" '),
    12201238                            'address' => $email,
    12211239                        ];
     
    12431261        $address = trim($address);
    12441262        $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
    1245         // Don't validate now addresses with IDN. Will be done in send().
     1263        //Don't validate now addresses with IDN. Will be done in send().
    12461264        $pos = strrpos($address, '@');
    12471265        if (
     
    13961414    public function punyencodeAddress($address)
    13971415    {
    1398         // Verify we have required functions, CharSet, and at-sign.
     1416        //Verify we have required functions, CharSet, and at-sign.
    13991417        $pos = strrpos($address, '@');
    14001418        if (
     
    14041422        ) {
    14051423            $domain = substr($address, ++$pos);
    1406             // Verify CharSet string is a valid one, and domain properly encoded in this CharSet.
     1424            //Verify CharSet string is a valid one, and domain properly encoded in this CharSet.
    14071425            if ($this->has8bitChars($domain) && @mb_check_encoding($domain, $this->CharSet)) {
    1408                 $domain = mb_convert_encoding($domain, 'UTF-8', $this->CharSet);
     1426                //Convert the domain from whatever charset it's in to UTF-8
     1427                $domain = mb_convert_encoding($domain, self::CHARSET_UTF8, $this->CharSet);
    14091428                //Ignore IDE complaints about this line - method signature changed in PHP 5.4
    14101429                $errorcode = 0;
    14111430                if (defined('INTL_IDNA_VARIANT_UTS46')) {
    1412                     $punycode = idn_to_ascii($domain, $errorcode, INTL_IDNA_VARIANT_UTS46);
     1431                    //Use the current punycode standard (appeared in PHP 7.2)
     1432                    $punycode = idn_to_ascii($domain, $errorcode, \INTL_IDNA_VARIANT_UTS46);
    14131433                } elseif (defined('INTL_IDNA_VARIANT_2003')) {
     1434                    //Fall back to this old, deprecated/removed encoding
    14141435                    // phpcs:ignore PHPCompatibility.Constants.RemovedConstants.intl_idna_variant_2003Deprecated
    1415                     $punycode = idn_to_ascii($domain, $errorcode, INTL_IDNA_VARIANT_2003);
     1436                    $punycode = idn_to_ascii($domain, $errorcode, \INTL_IDNA_VARIANT_2003);
    14161437                } else {
     1438                    //Fall back to a default we don't know about
    14171439                    // phpcs:ignore PHPCompatibility.ParameterValues.NewIDNVariantDefault.NotSet
    14181440                    $punycode = idn_to_ascii($domain, $errorcode);
     
    14651487        if (
    14661488            'smtp' === $this->Mailer
    1467             || ('mail' === $this->Mailer && (PHP_VERSION_ID >= 80000 || stripos(PHP_OS, 'WIN') === 0))
     1489            || ('mail' === $this->Mailer && (\PHP_VERSION_ID >= 80000 || stripos(PHP_OS, 'WIN') === 0))
    14681490        ) {
    14691491            //SMTP mandates RFC-compliant line endings
     
    14771499        if (
    14781500            'mail' === $this->Mailer
    1479             && ((PHP_VERSION_ID >= 70000 && PHP_VERSION_ID < 70017)
    1480                 || (PHP_VERSION_ID >= 70100 && PHP_VERSION_ID < 70103))
     1501            && ((\PHP_VERSION_ID >= 70000 && \PHP_VERSION_ID < 70017)
     1502                || (\PHP_VERSION_ID >= 70100 && \PHP_VERSION_ID < 70103))
    14811503            && ini_get('mail.add_x_header') === '1'
    14821504            && stripos(PHP_OS, 'WIN') === 0
     
    14911513
    14921514        try {
    1493             $this->error_count = 0; // Reset errors
     1515            $this->error_count = 0; //Reset errors
    14941516            $this->mailHeader = '';
    14951517
    1496             // Dequeue recipient and Reply-To addresses with IDN
     1518            //Dequeue recipient and Reply-To addresses with IDN
    14971519            foreach (array_merge($this->RecipientsQueue, $this->ReplyToQueue) as $params) {
    14981520                $params[1] = $this->punyencodeAddress($params[1]);
     
    15031525            }
    15041526
    1505             // Validate From, Sender, and ConfirmReadingTo addresses
     1527            //Validate From, Sender, and ConfirmReadingTo addresses
    15061528            foreach (['From', 'Sender', 'ConfirmReadingTo'] as $address_kind) {
    15071529                $this->$address_kind = trim($this->$address_kind);
     
    15271549            }
    15281550
    1529             // Set whether the message is multipart/alternative
     1551            //Set whether the message is multipart/alternative
    15301552            if ($this->alternativeExists()) {
    15311553                $this->ContentType = static::CONTENT_TYPE_MULTIPART_ALTERNATIVE;
     
    15331555
    15341556            $this->setMessageType();
    1535             // Refuse to send an empty message unless we are specifically allowing it
     1557            //Refuse to send an empty message unless we are specifically allowing it
    15361558            if (!$this->AllowEmpty && empty($this->Body)) {
    15371559                throw new Exception($this->lang('empty_message'), self::STOP_CRITICAL);
     
    15401562            //Trim subject consistently
    15411563            $this->Subject = trim($this->Subject);
    1542             // Create body before headers in case body makes changes to headers (e.g. altering transfer encoding)
     1564            //Create body before headers in case body makes changes to headers (e.g. altering transfer encoding)
    15431565            $this->MIMEHeader = '';
    15441566            $this->MIMEBody = $this->createBody();
    1545             // createBody may have added some headers, so retain them
     1567            //createBody may have added some headers, so retain them
    15461568            $tempheaders = $this->MIMEHeader;
    15471569            $this->MIMEHeader = $this->createHeader();
    15481570            $this->MIMEHeader .= $tempheaders;
    15491571
    1550             // To capture the complete message when using mail(), create
    1551             // an extra header list which createHeader() doesn't fold in
     1572            //To capture the complete message when using mail(), create
     1573            //an extra header list which createHeader() doesn't fold in
    15521574            if ('mail' === $this->Mailer) {
    15531575                if (count($this->to) > 0) {
     
    15621584            }
    15631585
    1564             // Sign with DKIM if enabled
     1586            //Sign with DKIM if enabled
    15651587            if (
    15661588                !empty($this->DKIM_domain)
     
    16031625    {
    16041626        try {
    1605             // Choose the mailer and send through it
     1627            //Choose the mailer and send through it
    16061628            switch ($this->Mailer) {
    16071629                case 'sendmail':
     
    16481670    protected function sendmailSend($header, $body)
    16491671    {
     1672        if ($this->Mailer === 'qmail') {
     1673            $this->edebug('Sending with qmail');
     1674        } else {
     1675            $this->edebug('Sending with sendmail');
     1676        }
    16501677        $header = static::stripTrailingWSP($header) . static::$LE . static::$LE;
    1651 
    1652         // CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
    1653         if (!empty($this->Sender) && self::isShellSafe($this->Sender)) {
    1654             if ('qmail' === $this->Mailer) {
     1678        //This sets the SMTP envelope sender which gets turned into a return-path header by the receiver
     1679        //A space after `-f` is optional, but there is a long history of its presence
     1680        //causing problems, so we don't use one
     1681        //Exim docs: http://www.exim.org/exim-html-current/doc/html/spec_html/ch-the_exim_command_line.html
     1682        //Sendmail docs: http://www.sendmail.org/~ca/email/man/sendmail.html
     1683        //Qmail docs: http://www.qmail.org/man/man8/qmail-inject.html
     1684        //Example problem: https://www.drupal.org/node/1057954
     1685        //CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
     1686        if ('' === $this->Sender) {
     1687            $this->Sender = $this->From;
     1688        }
     1689        if (empty($this->Sender) && !empty(ini_get('sendmail_from'))) {
     1690            //PHP config has a sender address we can use
     1691            $this->Sender = ini_get('sendmail_from');
     1692        }
     1693        //CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
     1694        //But sendmail requires this param, so fail without it
     1695        if (!empty($this->Sender) && static::validateAddress($this->Sender) && self::isShellSafe($this->Sender)) {
     1696            if ($this->Mailer === 'qmail') {
    16551697                $sendmailFmt = '%s -f%s';
    16561698            } else {
    16571699                $sendmailFmt = '%s -oi -f%s -t';
    16581700            }
    1659         } elseif ('qmail' === $this->Mailer) {
    1660             $sendmailFmt = '%s';
    16611701        } else {
    1662             $sendmailFmt = '%s -oi -t';
     1702            $this->edebug('Sender address unusable or missing: ' . $this->Sender);
     1703            return false;
    16631704        }
    16641705
    16651706        $sendmail = sprintf($sendmailFmt, escapeshellcmd($this->Sendmail), $this->Sender);
     1707        $this->edebug('Sendmail path: ' . $this->Sendmail);
     1708        $this->edebug('Sendmail command: ' . $sendmail);
     1709        $this->edebug('Envelope sender: ' . $this->Sender);
     1710        $this->edebug("Headers: {$header}");
    16661711
    16671712        if ($this->SingleTo) {
     
    16711716                    throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
    16721717                }
     1718                $this->edebug("To: {$toAddr}");
    16731719                fwrite($mail, 'To: ' . $toAddr . "\n");
    16741720                fwrite($mail, $header);
     
    16851731                    []
    16861732                );
     1733                $this->edebug("Result: " . ($result === 0 ? 'true' : 'false'));
    16871734                if (0 !== $result) {
    16881735                    throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
     
    17071754                []
    17081755            );
     1756            $this->edebug("Result: " . ($result === 0 ? 'true' : 'false'));
    17091757            if (0 !== $result) {
    17101758                throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
     
    17271775    protected static function isShellSafe($string)
    17281776    {
    1729         // Future-proof
     1777        //Future-proof
    17301778        if (
    17311779            escapeshellcmd($string) !== $string
     
    17401788            $c = $string[$i];
    17411789
    1742             // All other characters have a special meaning in at least one common shell, including = and +.
    1743             // Full stop (.) has a special meaning in cmd.exe, but its impact should be negligible here.
    1744             // Note that this does permit non-Latin alphanumeric characters based on the current locale.
     1790            //All other characters have a special meaning in at least one common shell, including = and +.
     1791            //Full stop (.) has a special meaning in cmd.exe, but its impact should be negligible here.
     1792            //Note that this does permit non-Latin alphanumeric characters based on the current locale.
    17451793            if (!ctype_alnum($c) && strpos('@_-.', $c) === false) {
    17461794                return false;
     
    18121860        //Qmail docs: http://www.qmail.org/man/man8/qmail-inject.html
    18131861        //Example problem: https://www.drupal.org/node/1057954
    1814         // CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
    1815         if (!empty($this->Sender) && static::validateAddress($this->Sender) && self::isShellSafe($this->Sender)) {
    1816             $params = sprintf('-f%s', $this->Sender);
     1862        //CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
     1863        if ('' === $this->Sender) {
     1864            $this->Sender = $this->From;
     1865        }
     1866        if (empty($this->Sender) && !empty(ini_get('sendmail_from'))) {
     1867            //PHP config has a sender address we can use
     1868            $this->Sender = ini_get('sendmail_from');
    18171869        }
    18181870        if (!empty($this->Sender) && static::validateAddress($this->Sender)) {
     1871            if (self::isShellSafe($this->Sender)) {
     1872                $params = sprintf('-f%s', $this->Sender);
     1873            }
    18191874            $old_from = ini_get('sendmail_from');
    18201875            ini_set('sendmail_from', $this->Sender);
     
    19021957
    19031958        $callbacks = [];
    1904         // Attempt to send to all recipients
     1959        //Attempt to send to all recipients
    19051960        foreach ([$this->to, $this->cc, $this->bcc] as $togroup) {
    19061961            foreach ($togroup as $to) {
     
    19171972        }
    19181973
    1919         // Only send the DATA command if we have viable recipients
     1974        //Only send the DATA command if we have viable recipients
    19201975        if ((count($this->all_recipients) > count($bad_rcpt)) && !$this->smtp->data($header . $body)) {
    19211976            throw new Exception($this->lang('data_not_accepted'), self::STOP_CRITICAL);
     
    19792034        }
    19802035
    1981         // Already connected?
     2036        //Already connected?
    19822037        if ($this->smtp->connected()) {
    19832038            return true;
     
    20012056            ) {
    20022057                $this->edebug($this->lang('invalid_hostentry') . ' ' . trim($hostentry));
    2003                 // Not a valid host entry
     2058                //Not a valid host entry
    20042059                continue;
    20052060            }
    2006             // $hostinfo[1]: optional ssl or tls prefix
    2007             // $hostinfo[2]: the hostname
    2008             // $hostinfo[3]: optional port number
    2009             // The host string prefix can temporarily override the current setting for SMTPSecure
    2010             // If it's not specified, the default value is used
     2061            //$hostinfo[1]: optional ssl or tls prefix
     2062            //$hostinfo[2]: the hostname
     2063            //$hostinfo[3]: optional port number
     2064            //The host string prefix can temporarily override the current setting for SMTPSecure
     2065            //If it's not specified, the default value is used
    20112066
    20122067            //Check the host name is a valid name or IP address before trying to use it
     
    20202075            if ('ssl' === $hostinfo[1] || ('' === $hostinfo[1] && static::ENCRYPTION_SMTPS === $this->SMTPSecure)) {
    20212076                $prefix = 'ssl://';
    2022                 $tls = false; // Can't have SSL and TLS at the same time
     2077                $tls = false; //Can't have SSL and TLS at the same time
    20232078                $secure = static::ENCRYPTION_SMTPS;
    20242079            } elseif ('tls' === $hostinfo[1]) {
    20252080                $tls = true;
    2026                 // tls doesn't use a prefix
     2081                //TLS doesn't use a prefix
    20272082                $secure = static::ENCRYPTION_STARTTLS;
    20282083            }
     
    20542109                    $this->smtp->hello($hello);
    20552110                    //Automatically enable TLS encryption if:
    2056                     // * it's not disabled
    2057                     // * we have openssl extension
    2058                     // * we are not already using SSL
    2059                     // * the server offers STARTTLS
     2111                    //* it's not disabled
     2112                    //* we have openssl extension
     2113                    //* we are not already using SSL
     2114                    //* the server offers STARTTLS
    20602115                    if ($this->SMTPAutoTLS && $sslext && 'ssl' !== $secure && $this->smtp->getServerExt('STARTTLS')) {
    20612116                        $tls = true;
     
    20652120                            throw new Exception($this->lang('connect_host'));
    20662121                        }
    2067                         // We must resend EHLO after TLS negotiation
     2122                        //We must resend EHLO after TLS negotiation
    20682123                        $this->smtp->hello($hello);
    20692124                    }
     
    20832138                    $lastexception = $exc;
    20842139                    $this->edebug($exc->getMessage());
    2085                     // We must have connected, but then failed TLS or Auth, so close connection nicely
     2140                    //We must have connected, but then failed TLS or Auth, so close connection nicely
    20862141                    $this->smtp->quit();
    20872142                }
    20882143            }
    20892144        }
    2090         // If we get here, all connection attempts have failed, so close connection hard
     2145        //If we get here, all connection attempts have failed, so close connection hard
    20912146        $this->smtp->close();
    2092         // As we've caught all exceptions, just report whatever the last one was
     2147        //As we've caught all exceptions, just report whatever the last one was
    20932148        if ($this->exceptions && null !== $lastexception) {
    20942149            throw $lastexception;
     
    21212176    public function setLanguage($langcode = 'en', $lang_path = '')
    21222177    {
    2123         // Backwards compatibility for renamed language codes
     2178        //Backwards compatibility for renamed language codes
    21242179        $renamed_langcodes = [
    21252180            'br' => 'pt_br',
     
    21372192        }
    21382193
    2139         // Define full set of translatable strings in English
     2194        //Define full set of translatable strings in English
    21402195        $PHPMAILER_LANG = [
    21412196            'authenticate' => 'SMTP Error: Could not authenticate.',
     
    21622217        ];
    21632218        if (empty($lang_path)) {
    2164             // Calculate an absolute path so it can work if CWD is not here
     2219            //Calculate an absolute path so it can work if CWD is not here
    21652220            $lang_path = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'language' . DIRECTORY_SEPARATOR;
    21662221        }
     
    21712226        $foundlang = true;
    21722227        $lang_file = $lang_path . 'phpmailer.lang-' . $langcode . '.php';
    2173         // There is no English translation file
     2228        //There is no English translation file
    21742229        if ('en' !== $langcode) {
    2175             // Make sure language file path is readable
     2230            //Make sure language file path is readable
    21762231            if (!static::fileIsAccessible($lang_file)) {
    21772232                $foundlang = false;
    21782233            } else {
    2179                 // Overwrite language-specific strings.
    2180                 // This way we'll never have missing translation keys.
     2234                //Overwrite language-specific strings.
     2235                //This way we'll never have missing translation keys.
    21812236                $foundlang = include $lang_file;
    21822237            }
     
    21842239        $this->language = $PHPMAILER_LANG;
    21852240
    2186         return (bool) $foundlang; // Returns false if language not found
     2241        return (bool) $foundlang; //Returns false if language not found
    21872242    }
    21882243
     
    22282283    public function addrFormat($addr)
    22292284    {
    2230         if (empty($addr[1])) { // No name provided
     2285        if (empty($addr[1])) { //No name provided
    22312286            return $this->secureHeader($addr[0]);
    22322287        }
     
    22552310            $soft_break = static::$LE;
    22562311        }
    2257         // If utf-8 encoding is used, we will need to make sure we don't
    2258         // split multibyte characters when we wrap
     2312        //If utf-8 encoding is used, we will need to make sure we don't
     2313        //split multibyte characters when we wrap
    22592314        $is_utf8 = static::CHARSET_UTF8 === strtolower($this->CharSet);
    22602315        $lelen = strlen(static::$LE);
     
    23562411            $encodedCharPos = strpos($lastChunk, '=');
    23572412            if (false !== $encodedCharPos) {
    2358                 // Found start of encoded character byte within $lookBack block.
    2359                 // Check the encoded byte value (the 2 chars after the '=')
     2413                //Found start of encoded character byte within $lookBack block.
     2414                //Check the encoded byte value (the 2 chars after the '=')
    23602415                $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2);
    23612416                $dec = hexdec($hex);
    23622417                if ($dec < 128) {
    2363                     // Single byte character.
    2364                     // If the encoded char was found at pos 0, it will fit
    2365                     // otherwise reduce maxLength to start of the encoded char
     2418                    //Single byte character.
     2419                    //If the encoded char was found at pos 0, it will fit
     2420                    //otherwise reduce maxLength to start of the encoded char
    23662421                    if ($encodedCharPos > 0) {
    23672422                        $maxLength -= $lookBack - $encodedCharPos;
     
    23692424                    $foundSplitPos = true;
    23702425                } elseif ($dec >= 192) {
    2371                     // First byte of a multi byte character
    2372                     // Reduce maxLength to split at start of character
     2426                    //First byte of a multi byte character
     2427                    //Reduce maxLength to split at start of character
    23732428                    $maxLength -= $lookBack - $encodedCharPos;
    23742429                    $foundSplitPos = true;
    23752430                } elseif ($dec < 192) {
    2376                     // Middle byte of a multi byte character, look further back
     2431                    //Middle byte of a multi byte character, look further back
    23772432                    $lookBack += 3;
    23782433                }
    23792434            } else {
    2380                 // No encoded character found
     2435                //No encoded character found
    23812436                $foundSplitPos = true;
    23822437            }
     
    24222477        $result .= $this->headerLine('Date', '' === $this->MessageDate ? self::rfcDate() : $this->MessageDate);
    24232478
    2424         // The To header is created automatically by mail(), so needs to be omitted here
     2479        //The To header is created automatically by mail(), so needs to be omitted here
    24252480        if ('mail' !== $this->Mailer) {
    24262481            if ($this->SingleTo) {
     
    24362491        $result .= $this->addrAppend('From', [[trim($this->From), $this->FromName]]);
    24372492
    2438         // sendmail and mail() extract Cc from the header before sending
     2493        //sendmail and mail() extract Cc from the header before sending
    24392494        if (count($this->cc) > 0) {
    24402495            $result .= $this->addrAppend('Cc', $this->cc);
    24412496        }
    24422497
    2443         // sendmail and mail() extract Bcc from the header before sending
     2498        //sendmail and mail() extract Bcc from the header before sending
    24442499        if (
    24452500            (
     
    24552510        }
    24562511
    2457         // mail() sets the subject itself
     2512        //mail() sets the subject itself
    24582513        if ('mail' !== $this->Mailer) {
    24592514            $result .= $this->headerLine('Subject', $this->encodeHeader($this->secureHeader($this->Subject)));
    24602515        }
    24612516
    2462         // Only allow a custom message ID if it conforms to RFC 5322 section 3.6.4
    2463         // https://tools.ietf.org/html/rfc5322#section-3.6.4
     2517        //Only allow a custom message ID if it conforms to RFC 5322 section 3.6.4
     2518        //https://tools.ietf.org/html/rfc5322#section-3.6.4
    24642519        if ('' !== $this->MessageID && preg_match('/^<.*@.*>$/', $this->MessageID)) {
    24652520            $this->lastMessageID = $this->MessageID;
     
    24872542        }
    24882543
    2489         // Add custom headers
     2544        //Add custom headers
    24902545        foreach ($this->CustomHeader as $header) {
    24912546            $result .= $this->headerLine(
     
    25292584                break;
    25302585            default:
    2531                 // Catches case 'plain': and case '':
     2586                //Catches case 'plain': and case '':
    25322587                $result .= $this->textLine('Content-Type: ' . $this->ContentType . '; charset=' . $this->CharSet);
    25332588                $ismultipart = false;
    25342589                break;
    25352590        }
    2536         // RFC1341 part 5 says 7bit is assumed if not specified
     2591        //RFC1341 part 5 says 7bit is assumed if not specified
    25372592        if (static::ENCODING_7BIT !== $this->Encoding) {
    2538             // RFC 2045 section 6.4 says multipart MIME parts may only use 7bit, 8bit or binary CTE
     2593            //RFC 2045 section 6.4 says multipart MIME parts may only use 7bit, 8bit or binary CTE
    25392594            if ($ismultipart) {
    25402595                if (static::ENCODING_8BIT === $this->Encoding) {
    25412596                    $result .= $this->headerLine('Content-Transfer-Encoding', static::ENCODING_8BIT);
    25422597                }
    2543                 // The only remaining alternatives are quoted-printable and base64, which are both 7bit compatible
     2598                //The only remaining alternatives are quoted-printable and base64, which are both 7bit compatible
    25442599            } else {
    25452600                $result .= $this->headerLine('Content-Transfer-Encoding', $this->Encoding);
    25462601            }
    2547         }
    2548 
    2549         if ('mail' !== $this->Mailer) {
    2550 //            $result .= static::$LE;
    25512602        }
    25522603
     
    28192870                break;
    28202871            default:
    2821                 // Catch case 'plain' and case '', applies to simple `text/plain` and `text/html` body content types
     2872                //Catch case 'plain' and case '', applies to simple `text/plain` and `text/html` body content types
    28222873                //Reset the `Encoding` property in case we changed it for line length reasons
    28232874                $this->Encoding = $bodyEncoding;
     
    29102961        $result .= sprintf('Content-Type: %s; charset=%s', $contentType, $charSet);
    29112962        $result .= static::$LE;
    2912         // RFC1341 part 5 says 7bit is assumed if not specified
     2963        //RFC1341 part 5 says 7bit is assumed if not specified
    29132964        if (static::ENCODING_7BIT !== $encoding) {
    29142965            $result .= $this->headerLine('Content-Transfer-Encoding', $encoding);
     
    30083059            }
    30093060
    3010             // If a MIME type is not specified, try to work it out from the file name
     3061            //If a MIME type is not specified, try to work it out from the file name
    30113062            if ('' === $type) {
    30123063                $type = static::filenameToType($path);
     
    30273078                3 => $encoding,
    30283079                4 => $type,
    3029                 5 => false, // isStringAttachment
     3080                5 => false, //isStringAttachment
    30303081                6 => $disposition,
    30313082                7 => $name,
     
    30673118    protected function attachAll($disposition_type, $boundary)
    30683119    {
    3069         // Return text of body
     3120        //Return text of body
    30703121        $mime = [];
    30713122        $cidUniq = [];
    30723123        $incl = [];
    30733124
    3074         // Add all attachments
     3125        //Add all attachments
    30753126        foreach ($this->attachment as $attachment) {
    3076             // Check if it is a valid disposition_filter
     3127            //Check if it is a valid disposition_filter
    30773128            if ($attachment[6] === $disposition_type) {
    3078                 // Check for string attachment
     3129                //Check for string attachment
    30793130                $string = '';
    30803131                $path = '';
     
    31173168                    );
    31183169                }
    3119                 // RFC1341 part 5 says 7bit is assumed if not specified
     3170                //RFC1341 part 5 says 7bit is assumed if not specified
    31203171                if (static::ENCODING_7BIT !== $encoding) {
    31213172                    $mime[] = sprintf('Content-Transfer-Encoding: %s%s', $encoding, static::$LE);
     
    31273178                }
    31283179
    3129                 // Allow for bypassing the Content-Disposition header
     3180                //Allow for bypassing the Content-Disposition header
    31303181                if (!empty($disposition)) {
    31313182                    $encoded_name = $this->encodeHeader($this->secureHeader($name));
     
    31483199                }
    31493200
    3150                 // Encode as string attachment
     3201                //Encode as string attachment
    31513202                if ($bString) {
    31523203                    $mime[] = $this->encodeString($string, $encoding);
     
    32243275            case static::ENCODING_8BIT:
    32253276                $encoded = static::normalizeBreaks($str);
    3226                 // Make sure it ends with a line break
     3277                //Make sure it ends with a line break
    32273278                if (substr($encoded, -(strlen(static::$LE))) !== static::$LE) {
    32283279                    $encoded .= static::$LE;
     
    32623313            case 'phrase':
    32633314                if (!preg_match('/[\200-\377]/', $str)) {
    3264                     // Can't use addslashes as we don't know the value of magic_quotes_sybase
     3315                    //Can't use addslashes as we don't know the value of magic_quotes_sybase
    32653316                    $encoded = addcslashes($str, "\0..\37\177\\\"");
    32663317                    if (($str === $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) {
     
    32883339        }
    32893340
    3290         // Q/B encoding adds 8 chars and the charset ("` =?<charset>?[QB]?<content>?=`").
     3341        //Q/B encoding adds 8 chars and the charset ("` =?<charset>?[QB]?<content>?=`").
    32913342        $overhead = 8 + strlen($charset);
    32923343
     
    32973348        }
    32983349
    3299         // Select the encoding that produces the shortest output and/or prevents corruption.
     3350        //Select the encoding that produces the shortest output and/or prevents corruption.
    33003351        if ($matchcount > strlen($str) / 3) {
    3301             // More than 1/3 of the content needs encoding, use B-encode.
     3352            //More than 1/3 of the content needs encoding, use B-encode.
    33023353            $encoding = 'B';
    33033354        } elseif ($matchcount > 0) {
    3304             // Less than 1/3 of the content needs encoding, use Q-encode.
     3355            //Less than 1/3 of the content needs encoding, use Q-encode.
    33053356            $encoding = 'Q';
    33063357        } elseif (strlen($str) > $maxlen) {
    3307             // No encoding needed, but value exceeds max line length, use Q-encode to prevent corruption.
     3358            //No encoding needed, but value exceeds max line length, use Q-encode to prevent corruption.
    33083359            $encoding = 'Q';
    33093360        } else {
    3310             // No reformatting needed
     3361            //No reformatting needed
    33113362            $encoding = false;
    33123363        }
     
    33153366            case 'B':
    33163367                if ($this->hasMultiBytes($str)) {
    3317                     // Use a custom function which correctly encodes and wraps long
    3318                     // multibyte strings without breaking lines within a character
     3368                    //Use a custom function which correctly encodes and wraps long
     3369                    //multibyte strings without breaking lines within a character
    33193370                    $encoded = $this->base64EncodeWrapMB($str, "\n");
    33203371                } else {
     
    33513402        }
    33523403
    3353         // Assume no multibytes (we can't handle without mbstring functions anyway)
     3404        //Assume no multibytes (we can't handle without mbstring functions anyway)
    33543405        return false;
    33553406    }
     
    33893440
    33903441        $mb_length = mb_strlen($str, $this->CharSet);
    3391         // Each line must have length <= 75, including $start and $end
     3442        //Each line must have length <= 75, including $start and $end
    33923443        $length = 75 - strlen($start) - strlen($end);
    3393         // Average multi-byte ratio
     3444        //Average multi-byte ratio
    33943445        $ratio = $mb_length / strlen($str);
    3395         // Base64 has a 4:3 ratio
     3446        //Base64 has a 4:3 ratio
    33963447        $avgLength = floor($length * $ratio * .75);
    33973448
     
    34083459        }
    34093460
    3410         // Chomp the last linefeed
     3461        //Chomp the last linefeed
    34113462        return substr($encoded, 0, -strlen($linebreak));
    34123463    }
     
    34373488    public function encodeQ($str, $position = 'text')
    34383489    {
    3439         // There should not be any EOL in the string
     3490        //There should not be any EOL in the string
    34403491        $pattern = '';
    34413492        $encoded = str_replace(["\r", "\n"], '', $str);
    34423493        switch (strtolower($position)) {
    34433494            case 'phrase':
    3444                 // RFC 2047 section 5.3
     3495                //RFC 2047 section 5.3
    34453496                $pattern = '^A-Za-z0-9!*+\/ -';
    34463497                break;
     
    34553506            case 'text':
    34563507            default:
    3457                 // RFC 2047 section 5.1
    3458                 // Replace every high ascii, control, =, ? and _ characters
     3508                //RFC 2047 section 5.1
     3509                //Replace every high ascii, control, =, ? and _ characters
    34593510                $pattern = '\000-\011\013\014\016-\037\075\077\137\177-\377' . $pattern;
    34603511                break;
     
    34623513        $matches = [];
    34633514        if (preg_match_all("/[{$pattern}]/", $encoded, $matches)) {
    3464             // If the string contains an '=', make sure it's the first thing we replace
    3465             // so as to avoid double-encoding
     3515            //If the string contains an '=', make sure it's the first thing we replace
     3516            //so as to avoid double-encoding
    34663517            $eqkey = array_search('=', $matches[0], true);
    34673518            if (false !== $eqkey) {
     
    34733524            }
    34743525        }
    3475         // Replace spaces with _ (more readable than =20)
    3476         // RFC 2047 section 4.2(2)
     3526        //Replace spaces with _ (more readable than =20)
     3527        //RFC 2047 section 4.2(2)
    34773528        return str_replace(' ', '_', $encoded);
    34783529    }
     
    35013552    ) {
    35023553        try {
    3503             // If a MIME type is not specified, try to work it out from the file name
     3554            //If a MIME type is not specified, try to work it out from the file name
    35043555            if ('' === $type) {
    35053556                $type = static::filenameToType($filename);
     
    35103561            }
    35113562
    3512             // Append to $attachment array
     3563            //Append to $attachment array
    35133564            $this->attachment[] = [
    35143565                0 => $string,
     
    35173568                3 => $encoding,
    35183569                4 => $type,
    3519                 5 => true, // isStringAttachment
     3570                5 => true, //isStringAttachment
    35203571                6 => $disposition,
    35213572                7 => 0,
     
    35683619            }
    35693620
    3570             // If a MIME type is not specified, try to work it out from the file name
     3621            //If a MIME type is not specified, try to work it out from the file name
    35713622            if ('' === $type) {
    35723623                $type = static::filenameToType($path);
     
    35823633            }
    35833634
    3584             // Append to $attachment array
     3635            //Append to $attachment array
    35853636            $this->attachment[] = [
    35863637                0 => $path,
     
    35893640                3 => $encoding,
    35903641                4 => $type,
    3591                 5 => false, // isStringAttachment
     3642                5 => false, //isStringAttachment
    35923643                6 => $disposition,
    35933644                7 => $cid,
     
    36343685    ) {
    36353686        try {
    3636             // If a MIME type is not specified, try to work it out from the name
     3687            //If a MIME type is not specified, try to work it out from the name
    36373688            if ('' === $type && !empty($name)) {
    36383689                $type = static::filenameToType($name);
     
    36433694            }
    36443695
    3645             // Append to $attachment array
     3696            //Append to $attachment array
    36463697            $this->attachment[] = [
    36473698                0 => $string,
     
    36503701                3 => $encoding,
    36513702                4 => $type,
    3652                 5 => true, // isStringAttachment
     3703                5 => true, //isStringAttachment
    36533704                6 => $disposition,
    36543705                7 => $cid,
     
    38703921    public static function rfcDate()
    38713922    {
    3872         // Set the time zone to whatever the default is to avoid 500 errors
    3873         // Will default to UTC if it's not set properly in php.ini
     3923        //Set the time zone to whatever the default is to avoid 500 errors
     3924        //Will default to UTC if it's not set properly in php.ini
    38743925        date_default_timezone_set(@date_default_timezone_get());
    38753926
     
    39494000    {
    39504001        if (count($this->language) < 1) {
    3951             $this->setLanguage(); // set the default language
     4002            $this->setLanguage(); //Set the default language
    39524003        }
    39534004
    39544005        if (array_key_exists($key, $this->language)) {
    39554006            if ('smtp_connect_failed' === $key) {
    3956                 //Include a link to troubleshooting docs on SMTP connection failure
    3957                 //this is by far the biggest cause of support questions
     4007                //Include a link to troubleshooting docs on SMTP connection failure.
     4008                //This is by far the biggest cause of support questions
    39584009                //but it's usually not PHPMailer's fault.
    39594010                return $this->language[$key] . ' https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting';
     
    39904041    {
    39914042        if (null === $value && strpos($name, ':') !== false) {
    3992             // Value passed in as name:value
     4043            //Value passed in as name:value
    39934044            list($name, $value) = explode(':', $name, 2);
    39944045        }
     
    40444095        if (array_key_exists(2, $images)) {
    40454096            if (strlen($basedir) > 1 && '/' !== substr($basedir, -1)) {
    4046                 // Ensure $basedir has a trailing /
     4097                //Ensure $basedir has a trailing /
    40474098                $basedir .= '/';
    40484099            }
    40494100            foreach ($images[2] as $imgindex => $url) {
    4050                 // Convert data URIs into embedded images
     4101                //Convert data URIs into embedded images
    40514102                //e.g. "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="
    40524103                $match = [];
     
    40624113                    //Hash the decoded data, not the URL, so that the same data-URI image used in multiple places
    40634114                    //will only be embedded once, even if it used a different encoding
    4064                     $cid = substr(hash('sha256', $data), 0, 32) . '@phpmailer.0'; // RFC2392 S 2
     4115                    $cid = substr(hash('sha256', $data), 0, 32) . '@phpmailer.0'; //RFC2392 S 2
    40654116
    40664117                    if (!$this->cidExists($cid)) {
     
    40814132                }
    40824133                if (
    4083                     // Only process relative URLs if a basedir is provided (i.e. no absolute local paths)
     4134                    //Only process relative URLs if a basedir is provided (i.e. no absolute local paths)
    40844135                    !empty($basedir)
    4085                     // Ignore URLs containing parent dir traversal (..)
     4136                    //Ignore URLs containing parent dir traversal (..)
    40864137                    && (strpos($url, '..') === false)
    4087                     // Do not change urls that are already inline images
     4138                    //Do not change urls that are already inline images
    40884139                    && 0 !== strpos($url, 'cid:')
    4089                     // Do not change absolute URLs, including anonymous protocol
     4140                    //Do not change absolute URLs, including anonymous protocol
    40904141                    && !preg_match('#^[a-z][a-z0-9+.-]*:?//#i', $url)
    40914142                ) {
     
    40954146                        $directory = '';
    40964147                    }
    4097                     // RFC2392 S 2
     4148                    //RFC2392 S 2
    40984149                    $cid = substr(hash('sha256', $url), 0, 32) . '@phpmailer.0';
    40994150                    if (strlen($basedir) > 1 && '/' !== substr($basedir, -1)) {
     
    41224173        }
    41234174        $this->isHTML();
    4124         // Convert all message body line breaks to LE, makes quoted-printable encoding work much better
     4175        //Convert all message body line breaks to LE, makes quoted-printable encoding work much better
    41254176        $this->Body = static::normalizeBreaks($message);
    41264177        $this->AltBody = static::normalizeBreaks($this->html2text($message, $advanced));
     
    41414192     *
    41424193     * ```php
    4143      * // Use default conversion
     4194     * //Use default conversion
    41444195     * $plain = $mail->html2text($html);
    4145      * // Use your own custom converter
     4196     * //Use your own custom converter
    41464197     * $plain = $mail->html2text($html, function($html) {
    41474198     *     $converter = new MyHtml2text($html);
     
    43104361    public static function filenameToType($filename)
    43114362    {
    4312         // In case the path is a URL, strip any query string before getting extension
     4363        //In case the path is a URL, strip any query string before getting extension
    43134364        $qpos = strpos($filename, '?');
    43144365        if (false !== $qpos) {
     
    44214472            $breaktype = static::$LE;
    44224473        }
    4423         // Normalise to \n
     4474        //Normalise to \n
    44244475        $text = str_replace([self::CRLF, "\r"], "\n", $text);
    4425         // Now convert LE as needed
     4476        //Now convert LE as needed
    44264477        if ("\n" !== $breaktype) {
    44274478            $text = str_replace("\n", $breaktype, $text);
     
    45294580        }
    45304581        if (openssl_sign($signHeader, $signature, $privKey, 'sha256WithRSAEncryption')) {
    4531             if (PHP_MAJOR_VERSION < 8) {
     4582            if (\PHP_MAJOR_VERSION < 8) {
    45324583                openssl_pkey_free($privKey);
    45334584            }
     
    45354586            return base64_encode($signature);
    45364587        }
    4537         if (PHP_MAJOR_VERSION < 8) {
     4588        if (\PHP_MAJOR_VERSION < 8) {
    45384589            openssl_pkey_free($privKey);
    45394590        }
     
    46024653            return self::CRLF;
    46034654        }
    4604         // Normalize line endings to CRLF
     4655        //Normalize line endings to CRLF
    46054656        $body = static::normalizeBreaks($body, self::CRLF);
    46064657
     
    46224673    public function DKIM_Add($headers_line, $subject, $body)
    46234674    {
    4624         $DKIMsignatureType = 'rsa-sha256'; // Signature & hash algorithms
    4625         $DKIMcanonicalization = 'relaxed/simple'; // Canonicalization methods of header & body
    4626         $DKIMquery = 'dns/txt'; // Query method
     4675        $DKIMsignatureType = 'rsa-sha256'; //Signature & hash algorithms
     4676        $DKIMcanonicalization = 'relaxed/simple'; //Canonicalization methods of header & body
     4677        $DKIMquery = 'dns/txt'; //Query method
    46274678        $DKIMtime = time();
    46284679        //Always sign these headers without being asked
     
    47254776        $headerValues = implode(static::$LE, $headersToSign);
    47264777        $body = $this->DKIM_BodyC($body);
    4727         $DKIMb64 = base64_encode(pack('H*', hash('sha256', $body))); // Base64 of packed binary SHA-256 hash of body
     4778        //Base64 of packed binary SHA-256 hash of body
     4779        $DKIMb64 = base64_encode(pack('H*', hash('sha256', $body)));
    47284780        $ident = '';
    47294781        if ('' !== $this->DKIM_identity) {
  • trunk/src/wp-includes/PHPMailer/SMTP.php

    r49713 r50397  
    3636     * @var string
    3737     */
    38     const VERSION = '6.2.0';
     38    const VERSION = '6.3.0';
    3939
    4040    /**
     
    313313    public function connect($host, $port = null, $timeout = 30, $options = [])
    314314    {
    315         // Clear errors to avoid confusion
     315        //Clear errors to avoid confusion
    316316        $this->setError('');
    317         // Make sure we are __not__ connected
     317        //Make sure we are __not__ connected
    318318        if ($this->connected()) {
    319             // Already connected, generate error
     319            //Already connected, generate error
    320320            $this->setError('Already connected to a server');
    321321
     
    325325            $port = self::DEFAULT_PORT;
    326326        }
    327         // Connect to the SMTP server
     327        //Connect to the SMTP server
    328328        $this->edebug(
    329329            "Connection: opening to $host:$port, timeout=$timeout, options=" .
     
    341341        $this->edebug('Connection: opened', self::DEBUG_CONNECTION);
    342342
    343         // Get any announcement
     343        //Get any announcement
    344344        $this->last_reply = $this->get_lines();
    345345        $this->edebug('SERVER -> CLIENT: ' . $this->last_reply, self::DEBUG_SERVER);
    346 
    347         return true;
     346        $responseCode = (int)substr($this->last_reply, 0, 3);
     347        if ($responseCode === 220) {
     348            return true;
     349        }
     350        //Anything other than a 220 response means something went wrong
     351        //RFC 5321 says the server will wait for us to send a QUIT in response to a 554 error
     352        //https://tools.ietf.org/html/rfc5321#section-3.1
     353        if ($responseCode === 554) {
     354            $this->quit();
     355        }
     356        //This will handle 421 responses which may not wait for a QUIT (e.g. if the server is being shut down)
     357        $this->edebug('Connection: closing due to error', self::DEBUG_CONNECTION);
     358        $this->close();
     359        return false;
    348360    }
    349361
     
    398410        }
    399411
    400         // Verify we connected properly
     412        //Verify we connected properly
    401413        if (!is_resource($connection)) {
    402414            $this->setError(
     
    415427        }
    416428
    417         // SMTP server can take longer to respond, give longer timeout for first read
    418         // Windows does not have support for this timeout function
     429        //SMTP server can take longer to respond, give longer timeout for first read
     430        //Windows does not have support for this timeout function
    419431        if (strpos(PHP_OS, 'WIN') !== 0) {
    420432            $max = (int)ini_get('max_execution_time');
    421             // Don't bother if unlimited, or if set_time_limit is disabled
     433            //Don't bother if unlimited, or if set_time_limit is disabled
    422434            if (0 !== $max && $timeout > $max && strpos(ini_get('disable_functions'), 'set_time_limit') === false) {
    423435                @set_time_limit($timeout);
     
    450462        }
    451463
    452         // Begin encrypted connection
     464        //Begin encrypted connection
    453465        set_error_handler([$this, 'errorHandler']);
    454466        $crypto_ok = stream_socket_enable_crypto(
     
    488500
    489501        if (array_key_exists('EHLO', $this->server_caps)) {
    490             // SMTP extensions are available; try to find a proper authentication method
     502            //SMTP extensions are available; try to find a proper authentication method
    491503            if (!array_key_exists('AUTH', $this->server_caps)) {
    492504                $this->setError('Authentication is not allowed at this stage');
    493                 // 'at this stage' means that auth may be allowed after the stage changes
    494                 // e.g. after STARTTLS
     505                //'at this stage' means that auth may be allowed after the stage changes
     506                //e.g. after STARTTLS
    495507
    496508                return false;
     
    536548        switch ($authtype) {
    537549            case 'PLAIN':
    538                 // Start authentication
     550                //Start authentication
    539551                if (!$this->sendCommand('AUTH', 'AUTH PLAIN', 334)) {
    540552                    return false;
    541553                }
    542                 // Send encoded username and password
     554                //Send encoded username and password
    543555                if (
    544556                    !$this->sendCommand(
     
    552564                break;
    553565            case 'LOGIN':
    554                 // Start authentication
     566                //Start authentication
    555567                if (!$this->sendCommand('AUTH', 'AUTH LOGIN', 334)) {
    556568                    return false;
     
    564576                break;
    565577            case 'CRAM-MD5':
    566                 // Start authentication
     578                //Start authentication
    567579                if (!$this->sendCommand('AUTH CRAM-MD5', 'AUTH CRAM-MD5', 334)) {
    568580                    return false;
    569581                }
    570                 // Get the challenge
     582                //Get the challenge
    571583                $challenge = base64_decode(substr($this->last_reply, 4));
    572584
    573                 // Build the response
     585                //Build the response
    574586                $response = $username . ' ' . $this->hmac($challenge, $password);
    575587
    576                 // send encoded credentials
     588                //send encoded credentials
    577589                return $this->sendCommand('Username', base64_encode($response), 235);
    578590            case 'XOAUTH2':
     
    583595                $oauth = $OAuth->getOauth64();
    584596
    585                 // Start authentication
     597                //Start authentication
    586598                if (!$this->sendCommand('AUTH', 'AUTH XOAUTH2 ' . $oauth, 235)) {
    587599                    return false;
     
    613625        }
    614626
    615         // The following borrowed from
    616         // http://php.net/manual/en/function.mhash.php#27225
    617 
    618         // RFC 2104 HMAC implementation for php.
    619         // Creates an md5 HMAC.
    620         // Eliminates the need to install mhash to compute a HMAC
    621         // by Lance Rushing
    622 
    623         $bytelen = 64; // byte length for md5
     627        //The following borrowed from
     628        //http://php.net/manual/en/function.mhash.php#27225
     629
     630        //RFC 2104 HMAC implementation for php.
     631        //Creates an md5 HMAC.
     632        //Eliminates the need to install mhash to compute a HMAC
     633        //by Lance Rushing
     634
     635        $bytelen = 64; //byte length for md5
    624636        if (strlen($key) > $bytelen) {
    625637            $key = pack('H*', md5($key));
     
    644656            $sock_status = stream_get_meta_data($this->smtp_conn);
    645657            if ($sock_status['eof']) {
    646                 // The socket is valid but we are not connected
     658                //The socket is valid but we are not connected
    647659                $this->edebug(
    648660                    'SMTP NOTICE: EOF caught while checking if connected',
     
    654666            }
    655667
    656             return true; // everything looks good
     668            return true; //everything looks good
    657669        }
    658670
     
    672684        $this->helo_rply = null;
    673685        if (is_resource($this->smtp_conn)) {
    674             // close the connection and cleanup
     686            //Close the connection and cleanup
    675687            fclose($this->smtp_conn);
    676688            $this->smtp_conn = null; //Makes for cleaner serialization
     
    707719         */
    708720
    709         // Normalize line breaks before exploding
     721        //Normalize line breaks before exploding
    710722        $lines = explode("\n", str_replace(["\r\n", "\r"], "\n", $msg_data));
    711723
     
    753765            //Send the lines to the server
    754766            foreach ($lines_out as $line_out) {
    755                 //RFC2821 section 4.5.2
     767                //Dot-stuffing as per RFC5321 section 4.5.2
     768                //https://tools.ietf.org/html/rfc5321#section-4.5.2
    756769                if (!empty($line_out) && $line_out[0] === '.') {
    757770                    $line_out = '.' . $line_out;
     
    787800    {
    788801        //Try extended hello first (RFC 2821)
    789         return $this->sendHello('EHLO', $host) or $this->sendHello('HELO', $host);
     802        if ($this->sendHello('EHLO', $host)) {
     803            return true;
     804        }
     805
     806        //Some servers shut down the SMTP service here (RFC 5321)
     807        if (substr($this->helo_rply, 0, 3) == '421') {
     808            return false;
     809        }
     810
     811        return $this->sendHello('HELO', $host);
    790812    }
    791813
     
    977999
    9781000        $this->last_reply = $this->get_lines();
    979         // Fetch SMTP code and possible error code explanation
     1001        //Fetch SMTP code and possible error code explanation
    9801002        $matches = [];
    9811003        if (preg_match('/^([\d]{3})[ -](?:([\d]\\.[\d]\\.[\d]{1,2}) )?/', $this->last_reply, $matches)) {
    9821004            $code = (int) $matches[1];
    9831005            $code_ex = (count($matches) > 2 ? $matches[2] : null);
    984             // Cut off error code from each response line
     1006            //Cut off error code from each response line
    9851007            $detail = preg_replace(
    9861008                "/{$code}[ -]" .
     
    9901012            );
    9911013        } else {
    992             // Fall back to simple parsing if regex fails
     1014            //Fall back to simple parsing if regex fails
    9931015            $code = (int) substr($this->last_reply, 0, 3);
    9941016            $code_ex = null;
     
    11851207    protected function get_lines()
    11861208    {
    1187         // If the connection is bad, give up straight away
     1209        //If the connection is bad, give up straight away
    11881210        if (!is_resource($this->smtp_conn)) {
    11891211            return '';
     
    12381260            $this->edebug('SMTP INBOUND: "' . trim($str) . '"', self::DEBUG_LOWLEVEL);
    12391261            $data .= $str;
    1240             // If response is only 3 chars (not valid, but RFC5321 S4.2 says it must be handled),
    1241             // or 4th character is a space or a line break char, we are done reading, break the loop.
    1242             // String array access is a significant micro-optimisation over strlen
     1262            //If response is only 3 chars (not valid, but RFC5321 S4.2 says it must be handled),
     1263            //or 4th character is a space or a line break char, we are done reading, break the loop.
     1264            //String array access is a significant micro-optimisation over strlen
    12431265            if (!isset($str[3]) || $str[3] === ' ' || $str[3] === "\r" || $str[3] === "\n") {
    12441266                break;
    12451267            }
    1246             // Timed-out? Log and break
     1268            //Timed-out? Log and break
    12471269            $info = stream_get_meta_data($this->smtp_conn);
    12481270            if ($info['timed_out']) {
     
    12531275                break;
    12541276            }
    1255             // Now check if reads took too long
     1277            //Now check if reads took too long
    12561278            if ($endtime && time() > $endtime) {
    12571279                $this->edebug(
Note: See TracChangeset for help on using the changeset viewer.