Make WordPress Core

Changeset 60813


Ignore:
Timestamp:
09/30/2025 12:46:53 PM (5 months ago)
Author:
SergeyBiryukov
Message:

External Libraries: Upgrade PHPMailer to version 6.11.0.

This is a large maintenance release with address parser improvements.

References:

Follow-up to [54937], [55557], [56484], [57137], [59246], [59481], [60623].

Props SirLouen, jrf, mukesh27, SergeyBiryukov.
Fixes #64052.

Location:
trunk/src/wp-includes
Files:
4 edited

Legend:

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

    r60797 r60813  
    562562     *   string  $from          email address of sender
    563563     *   string  $extra         extra information of possible use
    564      *                          "smtp_transaction_id' => last smtp transaction id
    565      *
    566      * @var string
     564     *                          'smtp_transaction_id' => last smtp transaction id
     565     *
     566     * @var callable|callable-string
    567567     */
    568568    public $action_function = '';
     
    712712     * @var array
    713713     */
    714     protected $language = [];
     714    protected static $language = [];
    715715
    716716    /**
     
    769769     * @var string
    770770     */
    771     const VERSION = '6.10.0';
     771    const VERSION = '6.11.0';
    772772
    773773    /**
     
    11031103            $error_message = sprintf(
    11041104                '%s (%s): %s',
    1105                 $this->lang('invalid_address'),
     1105                self::lang('invalid_address'),
    11061106                $kind,
    11071107                $address
     
    11881188            $error_message = sprintf(
    11891189                '%s: %s',
    1190                 $this->lang('Invalid recipient kind'),
     1190                self::lang('Invalid recipient kind'),
    11911191                $kind
    11921192            );
     
    12021202            $error_message = sprintf(
    12031203                '%s (%s): %s',
    1204                 $this->lang('invalid_address'),
     1204                self::lang('invalid_address'),
    12051205                $kind,
    12061206                $address
     
    12211221                return true;
    12221222            }
    1223         } elseif (!array_key_exists(strtolower($address), $this->ReplyTo)) {
    1224             $this->ReplyTo[strtolower($address)] = [$address, $name];
     1223        } else {
     1224            foreach ($this->ReplyTo as $replyTo) {
     1225                if (0 === strcasecmp($replyTo[0], $address)) {
     1226                    return false;
     1227                }
     1228            }
     1229            $this->ReplyTo[] = [$address, $name];
    12251230
    12261231            return true;
    12271232        }
    1228 
    12291233        return false;
    12301234    }
     
    12381242     * @see https://www.andrew.cmu.edu/user/agreen1/testing/mrbs/web/Mail/RFC822.php A more careful implementation
    12391243     *
    1240      * @param string $addrstr The address list string
    1241      * @param bool   $useimap Whether to use the IMAP extension to parse the list
    1242      * @param string $charset The charset to use when decoding the address list string.
     1244     * @param string      $addrstr      The address list string
     1245     * @param string|null $deprecatedArg Deprecated argument since 6.11.0.
     1246     * @param string      $charset      The charset to use when decoding the address list string.
    12431247     *
    12441248     * @return array
    12451249     */
    1246     public static function parseAddresses($addrstr, $useimap = true, $charset = self::CHARSET_ISO88591)
    1247     {
     1250    public static function parseAddresses($addrstr, $deprecatedArg = null, $charset = self::CHARSET_ISO88591)
     1251    {
     1252        if ($deprecatedArg !== null) {
     1253            trigger_error(self::lang('deprecated_argument'), E_USER_DEPRECATED);
     1254        }
    12481255        $addresses = [];
    1249         if ($useimap && function_exists('imap_rfc822_parse_adrlist')) {
     1256        if (function_exists('imap_rfc822_parse_adrlist')) {
    12501257            //Use this built-in parser if it's available
    12511258            $list = imap_rfc822_parse_adrlist($addrstr, '');
     
    12571264                    static::validateAddress($address->mailbox . '@' . $address->host)
    12581265                ) {
    1259                     //Decode the name part if it's present and encoded
     1266                    //Decode the name part if it's present and maybe encoded
    12601267                    if (
    1261                         property_exists($address, 'personal') &&
    1262                         //Check for a Mbstring constant rather than using extension_loaded, which is sometimes disabled
    1263                         defined('MB_CASE_UPPER') &&
    1264                         preg_match('/^=\?.*\?=$/s', $address->personal)
     1268                        property_exists($address, 'personal')
     1269                        && is_string($address->personal)
     1270                        && $address->personal !== ''
    12651271                    ) {
    1266                         $origCharset = mb_internal_encoding();
    1267                         mb_internal_encoding($charset);
    1268                         //Undo any RFC2047-encoded spaces-as-underscores
    1269                         $address->personal = str_replace('_', '=20', $address->personal);
    1270                         //Decode the name
    1271                         $address->personal = mb_decode_mimeheader($address->personal);
    1272                         mb_internal_encoding($origCharset);
     1272                        $address->personal = static::decodeHeader($address->personal, $charset);
    12731273                    }
    12741274
     
    12811281        } else {
    12821282            //Use this simpler parser
    1283             $list = explode(',', $addrstr);
    1284             foreach ($list as $address) {
    1285                 $address = trim($address);
    1286                 //Is there a separate name part?
    1287                 if (strpos($address, '<') === false) {
    1288                     //No separate name, just use the whole thing
    1289                     if (static::validateAddress($address)) {
    1290                         $addresses[] = [
    1291                             'name' => '',
    1292                             'address' => $address,
    1293                         ];
    1294                     }
    1295                 } else {
    1296                     list($name, $email) = explode('<', $address);
    1297                     $email = trim(str_replace('>', '', $email));
    1298                     $name = trim($name);
    1299                     if (static::validateAddress($email)) {
    1300                         //Check for a Mbstring constant rather than using extension_loaded, which is sometimes disabled
    1301                         //If this name is encoded, decode it
    1302                         if (defined('MB_CASE_UPPER') && preg_match('/^=\?.*\?=$/s', $name)) {
    1303                             $origCharset = mb_internal_encoding();
    1304                             mb_internal_encoding($charset);
    1305                             //Undo any RFC2047-encoded spaces-as-underscores
    1306                             $name = str_replace('_', '=20', $name);
    1307                             //Decode the name
    1308                             $name = mb_decode_mimeheader($name);
    1309                             mb_internal_encoding($origCharset);
    1310                         }
    1311                         $addresses[] = [
    1312                             //Remove any surrounding quotes and spaces from the name
    1313                             'name' => trim($name, '\'" '),
    1314                             'address' => $email,
    1315                         ];
    1316                     }
    1317                 }
    1318             }
     1283            $addresses = static::parseSimplerAddresses($addrstr, $charset);
    13191284        }
    13201285
    13211286        return $addresses;
     1287    }
     1288
     1289    /**
     1290     * Parse a string containing one or more RFC822-style comma-separated email addresses
     1291     * with the form "display name <address>" into an array of name/address pairs.
     1292     * Uses a simpler parser that does not require the IMAP extension but doesnt support
     1293     * the full RFC822 spec. For full RFC822 support, use the PHP IMAP extension.
     1294     *
     1295     * @param string $addrstr The address list string
     1296     * @param string $charset The charset to use when decoding the address list string.
     1297     *
     1298     * @return array
     1299     */
     1300    protected static function parseSimplerAddresses($addrstr, $charset)
     1301    {
     1302        // Emit a runtime notice to recommend using the IMAP extension for full RFC822 parsing
     1303        trigger_error(self::lang('imap_recommended'), E_USER_NOTICE);
     1304
     1305        $addresses = [];
     1306        $list = explode(',', $addrstr);
     1307        foreach ($list as $address) {
     1308            $address = trim($address);
     1309            //Is there a separate name part?
     1310            if (strpos($address, '<') === false) {
     1311                //No separate name, just use the whole thing
     1312                if (static::validateAddress($address)) {
     1313                    $addresses[] = [
     1314                        'name' => '',
     1315                        'address' => $address,
     1316                    ];
     1317                }
     1318            } else {
     1319                $parsed = static::parseEmailString($address);
     1320                $email = $parsed['email'];
     1321                if (static::validateAddress($email)) {
     1322                    $name = static::decodeHeader($parsed['name'], $charset);
     1323                    $addresses[] = [
     1324                        //Remove any surrounding quotes and spaces from the name
     1325                        'name' => trim($name, '\'" '),
     1326                        'address' => $email,
     1327                    ];
     1328                }
     1329            }
     1330        }
     1331
     1332        return $addresses;
     1333    }
     1334
     1335    /**
     1336     * Parse a string containing an email address with an optional name
     1337     * and divide it into a name and email address.
     1338     *
     1339     * @param string $input The email with name.
     1340     *
     1341     * @return array{name: string, email: string}
     1342     */
     1343    private static function parseEmailString($input)
     1344    {
     1345        $input = trim((string)$input);
     1346
     1347        if ($input === '') {
     1348            return ['name' => '', 'email' => ''];
     1349        }
     1350
     1351        $pattern = '/^\s*(?:(?:"([^"]*)"|\'([^\']*)\'|([^<]*?))\s*)?<\s*([^>]+)\s*>\s*$/';
     1352        if (preg_match($pattern, $input, $matches)) {
     1353            $name = '';
     1354            // Double quotes including special scenarios.
     1355            if (isset($matches[1]) && $matches[1] !== '') {
     1356                $name = $matches[1];
     1357            // Single quotes including special scenarios.
     1358            } elseif (isset($matches[2]) && $matches[2] !== '') {
     1359                $name = $matches[2];
     1360            // Simplest scenario, name and email are in the format "Name <email>".
     1361            } elseif (isset($matches[3])) {
     1362                $name = trim($matches[3]);
     1363            }
     1364
     1365            return ['name' => $name, 'email' => trim($matches[4])];
     1366        }
     1367
     1368        return ['name' => '', 'email' => $input];
    13221369    }
    13231370
     
    13351382    public function setFrom($address, $name = '', $auto = true)
    13361383    {
     1384        if (is_null($name)) {
     1385            //Helps avoid a deprecation warning in the preg_replace() below
     1386            $name = '';
     1387        }
    13371388        $address = trim((string)$address);
    13381389        $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
     
    13461397            $error_message = sprintf(
    13471398                '%s (From): %s',
    1348                 $this->lang('invalid_address'),
     1399                self::lang('invalid_address'),
    13491400                $address
    13501401            );
     
    16021653            && stripos(PHP_OS, 'WIN') === 0
    16031654        ) {
    1604             trigger_error($this->lang('buggy_php'), E_USER_WARNING);
     1655            trigger_error(self::lang('buggy_php'), E_USER_WARNING);
    16051656        }
    16061657
     
    16321683            }
    16331684            if (count($this->to) + count($this->cc) + count($this->bcc) < 1) {
    1634                 throw new Exception($this->lang('provide_address'), self::STOP_CRITICAL);
     1685                throw new Exception(self::lang('provide_address'), self::STOP_CRITICAL);
    16351686            }
    16361687
     
    16491700                    $error_message = sprintf(
    16501701                        '%s (%s): %s',
    1651                         $this->lang('invalid_address'),
     1702                        self::lang('invalid_address'),
    16521703                        $address_kind,
    16531704                        $this->{$address_kind}
     
    16711722            //Refuse to send an empty message unless we are specifically allowing it
    16721723            if (!$this->AllowEmpty && empty($this->Body)) {
    1673                 throw new Exception($this->lang('empty_message'), self::STOP_CRITICAL);
     1724                throw new Exception(self::lang('empty_message'), self::STOP_CRITICAL);
    16741725            }
    16751726
     
    18101861                $sendmailFmt = '%s -oi -f%s -t';
    18111862            }
     1863        } elseif ($this->Mailer === 'qmail') {
     1864            $sendmailFmt = '%s';
    18121865        } else {
    1813             //allow sendmail to choose a default envelope sender. It may
     1866            //Allow sendmail to choose a default envelope sender. It may
    18141867            //seem preferable to force it to use the From header as with
    18151868            //SMTP, but that introduces new problems (see
     
    18291882                $mail = @popen($sendmail, 'w');
    18301883                if (!$mail) {
    1831                     throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
     1884                    throw new Exception(self::lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
    18321885                }
    18331886                $this->edebug("To: {$toAddr}");
     
    18361889                fwrite($mail, $body);
    18371890                $result = pclose($mail);
    1838                 $addrinfo = static::parseAddresses($toAddr, true, $this->CharSet);
    1839                 $this->doCallback(
    1840                     ($result === 0),
    1841                     [[$addrinfo['address'], $addrinfo['name']]],
    1842                     $this->cc,
    1843                     $this->bcc,
    1844                     $this->Subject,
    1845                     $body,
    1846                     $this->From,
    1847                     []
    1848                 );
     1891                $addrinfo = static::parseAddresses($toAddr, null, $this->CharSet);
     1892                foreach ($addrinfo as $addr) {
     1893                    $this->doCallback(
     1894                        ($result === 0),
     1895                        [[$addr['address'], $addr['name']]],
     1896                        $this->cc,
     1897                        $this->bcc,
     1898                        $this->Subject,
     1899                        $body,
     1900                        $this->From,
     1901                        []
     1902                    );
     1903                }
    18491904                $this->edebug("Result: " . ($result === 0 ? 'true' : 'false'));
    18501905                if (0 !== $result) {
    1851                     throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
     1906                    throw new Exception(self::lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
    18521907                }
    18531908            }
     
    18551910            $mail = @popen($sendmail, 'w');
    18561911            if (!$mail) {
    1857                 throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
     1912                throw new Exception(self::lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
    18581913            }
    18591914            fwrite($mail, $header);
     
    18721927            $this->edebug("Result: " . ($result === 0 ? 'true' : 'false'));
    18731928            if (0 !== $result) {
    1874                 throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
     1929                throw new Exception(self::lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
    18751930            }
    18761931        }
     
    20112066            foreach ($toArr as $toAddr) {
    20122067                $result = $this->mailPassthru($toAddr, $this->Subject, $body, $header, $params);
    2013                 $addrinfo = static::parseAddresses($toAddr, true, $this->CharSet);
    2014                 $this->doCallback(
    2015                     $result,
    2016                     [[$addrinfo['address'], $addrinfo['name']]],
    2017                     $this->cc,
    2018                     $this->bcc,
    2019                     $this->Subject,
    2020                     $body,
    2021                     $this->From,
    2022                     []
    2023                 );
     2068                $addrinfo = static::parseAddresses($toAddr, null, $this->CharSet);
     2069                foreach ($addrinfo as $addr) {
     2070                    $this->doCallback(
     2071                        $result,
     2072                        [[$addr['address'], $addr['name']]],
     2073                        $this->cc,
     2074                        $this->bcc,
     2075                        $this->Subject,
     2076                        $body,
     2077                        $this->From,
     2078                        []
     2079                    );
     2080                }
    20242081            }
    20252082        } else {
     
    20312088        }
    20322089        if (!$result) {
    2033             throw new Exception($this->lang('instantiate'), self::STOP_CRITICAL);
     2090            throw new Exception(self::lang('instantiate'), self::STOP_CRITICAL);
    20342091        }
    20352092
     
    21172174        $bad_rcpt = [];
    21182175        if (!$this->smtpConnect($this->SMTPOptions)) {
    2119             throw new Exception($this->lang('smtp_connect_failed'), self::STOP_CRITICAL);
     2176            throw new Exception(self::lang('smtp_connect_failed'), self::STOP_CRITICAL);
    21202177        }
    21212178        //If we have recipient addresses that need Unicode support,
    21222179        //but the server doesn't support it, stop here
    21232180        if ($this->UseSMTPUTF8 && !$this->smtp->getServerExt('SMTPUTF8')) {
    2124             throw new Exception($this->lang('no_smtputf8'), self::STOP_CRITICAL);
     2181            throw new Exception(self::lang('no_smtputf8'), self::STOP_CRITICAL);
    21252182        }
    21262183        //Sender already validated in preSend()
     
    21342191        }
    21352192        if (!$this->smtp->mail($smtp_from)) {
    2136             $this->setError($this->lang('from_failed') . $smtp_from . ' : ' . implode(',', $this->smtp->getError()));
     2193            $this->setError(self::lang('from_failed') . $smtp_from . ' : ' . implode(',', $this->smtp->getError()));
    21372194            throw new Exception($this->ErrorInfo, self::STOP_CRITICAL);
    21382195        }
     
    21562213        //Only send the DATA command if we have viable recipients
    21572214        if ((count($this->all_recipients) > count($bad_rcpt)) && !$this->smtp->data($header . $body)) {
    2158             throw new Exception($this->lang('data_not_accepted'), self::STOP_CRITICAL);
     2215            throw new Exception(self::lang('data_not_accepted'), self::STOP_CRITICAL);
    21592216        }
    21602217
     
    21872244                $errstr .= $bad['to'] . ': ' . $bad['error'];
    21882245            }
    2189             throw new Exception($this->lang('recipients_failed') . $errstr, self::STOP_CONTINUE);
     2246            throw new Exception(self::lang('recipients_failed') . $errstr, self::STOP_CONTINUE);
    21902247        }
    21912248
     
    22412298                )
    22422299            ) {
    2243                 $this->edebug($this->lang('invalid_hostentry') . ' ' . trim($hostentry));
     2300                $this->edebug(self::lang('invalid_hostentry') . ' ' . trim($hostentry));
    22442301                //Not a valid host entry
    22452302                continue;
     
    22532310            //Check the host name is a valid name or IP address before trying to use it
    22542311            if (!static::isValidHost($hostinfo[2])) {
    2255                 $this->edebug($this->lang('invalid_host') . ' ' . $hostinfo[2]);
     2312                $this->edebug(self::lang('invalid_host') . ' ' . $hostinfo[2]);
    22562313                continue;
    22572314            }
     
    22732330                //Check for an OpenSSL constant rather than using extension_loaded, which is sometimes disabled
    22742331                if (!$sslext) {
    2275                     throw new Exception($this->lang('extension_missing') . 'openssl', self::STOP_CRITICAL);
     2332                    throw new Exception(self::lang('extension_missing') . 'openssl', self::STOP_CRITICAL);
    22762333                }
    22772334            }
     
    23252382                        )
    23262383                    ) {
    2327                         throw new Exception($this->lang('authenticate'));
     2384                        throw new Exception(self::lang('authenticate'));
    23282385                    }
    23292386
     
    23752432     * @return bool Returns true if the requested language was loaded, false otherwise.
    23762433     */
    2377     public function setLanguage($langcode = 'en', $lang_path = '')
     2434    public static function setLanguage($langcode = 'en', $lang_path = '')
    23782435    {
    23792436        //Backwards compatibility for renamed language codes
     
    24242481            'variable_set' => 'Cannot set or reset variable: ',
    24252482            'no_smtputf8' => 'Server does not support SMTPUTF8 needed to send to Unicode addresses',
     2483            'imap_recommended' => 'Using simplified address parser is not recommended. ' .
     2484                'Install the PHP IMAP extension for full RFC822 parsing.',
     2485            'deprecated_argument' => 'Argument $deprecatedArg is deprecated',
    24262486        ];
    24272487        if (empty($lang_path)) {
     
    24902550            }
    24912551        }
    2492         $this->language = $PHPMAILER_LANG;
     2552        self::$language = $PHPMAILER_LANG;
    24932553
    24942554        return $foundlang; //Returns false if language not found
     
    25022562    public function getTranslations()
    25032563    {
    2504         if (empty($this->language)) {
    2505             $this->setLanguage(); // Set the default language.
    2506         }
    2507 
    2508         return $this->language;
     2564        if (empty(self::$language)) {
     2565            self::setLanguage(); // Set the default language.
     2566        }
     2567
     2568        return self::$language;
    25092569    }
    25102570
     
    29292989        $this->setBoundaries();
    29302990
    2931         if ($this->sign_key_file) {
    2932             $body .= $this->getMailMIME() . static::$LE;
    2933         }
    2934 
    29352991        $this->setWordWrap();
    29362992
     
    29643020            $altBodyEncoding = static::ENCODING_QUOTED_PRINTABLE;
    29653021        }
     3022
     3023        if ($this->sign_key_file) {
     3024            $this->Encoding = $bodyEncoding;
     3025            $body .= $this->getMailMIME() . static::$LE;
     3026        }
     3027
    29663028        //Use this as a preamble in all multipart message types
    29673029        $mimepre = '';
     
    31453207            $body = '';
    31463208            if ($this->exceptions) {
    3147                 throw new Exception($this->lang('empty_message'), self::STOP_CRITICAL);
     3209                throw new Exception(self::lang('empty_message'), self::STOP_CRITICAL);
    31483210            }
    31493211        } elseif ($this->sign_key_file) {
    31503212            try {
    31513213                if (!defined('PKCS7_TEXT')) {
    3152                     throw new Exception($this->lang('extension_missing') . 'openssl');
     3214                    throw new Exception(self::lang('extension_missing') . 'openssl');
    31533215                }
    31543216
     
    31883250                } else {
    31893251                    @unlink($signed);
    3190                     throw new Exception($this->lang('signing') . openssl_error_string());
     3252                    throw new Exception(self::lang('signing') . openssl_error_string());
    31913253                }
    31923254            } catch (Exception $exc) {
     
    33333395        try {
    33343396            if (!static::fileIsAccessible($path)) {
    3335                 throw new Exception($this->lang('file_access') . $path, self::STOP_CONTINUE);
     3397                throw new Exception(self::lang('file_access') . $path, self::STOP_CONTINUE);
    33363398            }
    33373399
     
    33463408            }
    33473409            if (!$this->validateEncoding($encoding)) {
    3348                 throw new Exception($this->lang('encoding') . $encoding);
     3410                throw new Exception(self::lang('encoding') . $encoding);
    33493411            }
    33503412
     
    35073569        try {
    35083570            if (!static::fileIsAccessible($path)) {
    3509                 throw new Exception($this->lang('file_open') . $path, self::STOP_CONTINUE);
     3571                throw new Exception(self::lang('file_open') . $path, self::STOP_CONTINUE);
    35103572            }
    35113573            $file_buffer = file_get_contents($path);
    35123574            if (false === $file_buffer) {
    3513                 throw new Exception($this->lang('file_open') . $path, self::STOP_CONTINUE);
     3575                throw new Exception(self::lang('file_open') . $path, self::STOP_CONTINUE);
    35143576            }
    35153577            $file_buffer = $this->encodeString($file_buffer, $encoding);
     
    35643626                break;
    35653627            default:
    3566                 $this->setError($this->lang('encoding') . $encoding);
     3628                $this->setError(self::lang('encoding') . $encoding);
    35673629                if ($this->exceptions) {
    3568                     throw new Exception($this->lang('encoding') . $encoding);
     3630                    throw new Exception(self::lang('encoding') . $encoding);
    35693631                }
    35703632                break;
     
    36703732
    36713733        return trim(static::normalizeBreaks($encoded));
     3734    }
     3735
     3736    /**
     3737     * Decode an RFC2047-encoded header value
     3738     * Attempts multiple strategies so it works even when the mbstring extension is disabled.
     3739     *
     3740     * @param string $value   The header value to decode
     3741     * @param string $charset The target charset to convert to, defaults to ISO-8859-1 for BC
     3742     *
     3743     * @return string The decoded header value
     3744     */
     3745    public static function decodeHeader($value, $charset = self::CHARSET_ISO88591)
     3746    {
     3747        if (!is_string($value) || $value === '') {
     3748            return '';
     3749        }
     3750        // Detect the presence of any RFC2047 encoded-words
     3751        $hasEncodedWord = (bool) preg_match('/=\?.*\?=/s', $value);
     3752        if ($hasEncodedWord && defined('MB_CASE_UPPER')) {
     3753            $origCharset = mb_internal_encoding();
     3754            // Always decode to UTF-8 to provide a consistent, modern output encoding.
     3755            mb_internal_encoding($charset);
     3756            if (PHP_VERSION_ID < 80300) {
     3757                // Undo any RFC2047-encoded spaces-as-underscores.
     3758                $value = str_replace('_', '=20', $value);
     3759            } else {
     3760                // PHP 8.3+ already interprets underscores as spaces. Remove additional
     3761                // linear whitespace between adjacent encoded words to avoid double spacing.
     3762                $value = preg_replace('/(\?=)\s+(=\?)/', '$1$2', $value);
     3763            }
     3764            // Decode the header value
     3765            $value = mb_decode_mimeheader($value);
     3766            mb_internal_encoding($origCharset);
     3767        }
     3768
     3769        return $value;
    36723770    }
    36733771
     
    38413939
    38423940            if (!$this->validateEncoding($encoding)) {
    3843                 throw new Exception($this->lang('encoding') . $encoding);
     3941                throw new Exception(self::lang('encoding') . $encoding);
    38443942            }
    38453943
     
    39003998        try {
    39013999            if (!static::fileIsAccessible($path)) {
    3902                 throw new Exception($this->lang('file_access') . $path, self::STOP_CONTINUE);
     4000                throw new Exception(self::lang('file_access') . $path, self::STOP_CONTINUE);
    39034001            }
    39044002
     
    39094007
    39104008            if (!$this->validateEncoding($encoding)) {
    3911                 throw new Exception($this->lang('encoding') . $encoding);
     4009                throw new Exception(self::lang('encoding') . $encoding);
    39124010            }
    39134011
     
    39754073
    39764074            if (!$this->validateEncoding($encoding)) {
    3977                 throw new Exception($this->lang('encoding') . $encoding);
     4075                throw new Exception(self::lang('encoding') . $encoding);
    39784076            }
    39794077
     
    42324330                if (strpbrk($name . $value, "\r\n") !== false) {
    42334331                    if ($this->exceptions) {
    4234                         throw new Exception($this->lang('invalid_header'));
     4332                        throw new Exception(self::lang('invalid_header'));
    42354333                    }
    42364334
     
    42564354            $lasterror = $this->smtp->getError();
    42574355            if (!empty($lasterror['error'])) {
    4258                 $msg .= ' ' . $this->lang('smtp_error') . $lasterror['error'];
     4356                $msg .= ' ' . self::lang('smtp_error') . $lasterror['error'];
    42594357                if (!empty($lasterror['detail'])) {
    4260                     $msg .= ' ' . $this->lang('smtp_detail') . $lasterror['detail'];
     4358                    $msg .= ' ' . self::lang('smtp_detail') . $lasterror['detail'];
    42614359                }
    42624360                if (!empty($lasterror['smtp_code'])) {
    4263                     $msg .= ' ' . $this->lang('smtp_code') . $lasterror['smtp_code'];
     4361                    $msg .= ' ' . self::lang('smtp_code') . $lasterror['smtp_code'];
    42644362                }
    42654363                if (!empty($lasterror['smtp_code_ex'])) {
    4266                     $msg .= ' ' . $this->lang('smtp_code_ex') . $lasterror['smtp_code_ex'];
     4364                    $msg .= ' ' . self::lang('smtp_code_ex') . $lasterror['smtp_code_ex'];
    42674365                }
    42684366            }
     
    43894487     * @return string
    43904488     */
    4391     protected function lang($key)
    4392     {
    4393         if (count($this->language) < 1) {
    4394             $this->setLanguage(); //Set the default language
    4395         }
    4396 
    4397         if (array_key_exists($key, $this->language)) {
     4489    protected static function lang($key)
     4490    {
     4491        if (count(self::$language) < 1) {
     4492            self::setLanguage(); //Set the default language
     4493        }
     4494
     4495        if (array_key_exists($key, self::$language)) {
    43984496            if ('smtp_connect_failed' === $key) {
    43994497                //Include a link to troubleshooting docs on SMTP connection failure.
    44004498                //This is by far the biggest cause of support questions
    44014499                //but it's usually not PHPMailer's fault.
    4402                 return $this->language[$key] . ' https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting';
    4403             }
    4404 
    4405             return $this->language[$key];
     4500                return self::$language[$key] . ' https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting';
     4501            }
     4502
     4503            return self::$language[$key];
    44064504        }
    44074505
     
    44184516    private function getSmtpErrorMessage($base_key)
    44194517    {
    4420         $message = $this->lang($base_key);
     4518        $message = self::lang($base_key);
    44214519        $error = $this->smtp->getError();
    44224520        if (!empty($error['error'])) {
     
    44624560        if (empty($name) || strpbrk($name . $value, "\r\n") !== false) {
    44634561            if ($this->exceptions) {
    4464                 throw new Exception($this->lang('invalid_header'));
     4562                throw new Exception(self::lang('invalid_header'));
    44654563            }
    44664564
     
    48554953            return true;
    48564954        }
    4857         $this->setError($this->lang('variable_set') . $name);
     4955        $this->setError(self::lang('variable_set') . $name);
    48584956
    48594957        return false;
     
    49935091        if (!defined('PKCS7_TEXT')) {
    49945092            if ($this->exceptions) {
    4995                 throw new Exception($this->lang('extension_missing') . 'openssl');
     5093                throw new Exception(self::lang('extension_missing') . 'openssl');
    49965094            }
    49975095
  • trunk/src/wp-includes/PHPMailer/POP3.php

    r60623 r60813  
    4747     * @var string
    4848     */
    49     const VERSION = '6.10.0';
     49    const VERSION = '6.11.0';
    5050
    5151    /**
  • trunk/src/wp-includes/PHPMailer/SMTP.php

    r60623 r60813  
    3636     * @var string
    3737     */
    38     const VERSION = '6.10.0';
     38    const VERSION = '6.11.0';
    3939
    4040    /**
     
    206206        'ZoneMTA' => '/[\d]{3} Message queued as (.*)/',
    207207        'Mailjet' => '/[\d]{3} OK queued as (.*)/',
     208        'Gsmtp' => '/[\d]{3} 2\.0\.0 OK (.*) - gsmtp/',
    208209    ];
    209210
     
    634635                }
    635636                $oauth = $OAuth->getOauth64();
    636 
    637                 //Start authentication
    638                 if (!$this->sendCommand('AUTH', 'AUTH XOAUTH2 ' . $oauth, 235)) {
    639                     return false;
     637                /*
     638                 * An SMTP command line can have a maximum length of 512 bytes, including the command name,
     639                 * so the base64-encoded OAUTH token has a maximum length of:
     640                 * 512 - 13 (AUTH XOAUTH2) - 2 (CRLF) = 497 bytes
     641                 * If the token is longer than that, the command and the token must be sent separately as described in
     642                 * https://www.rfc-editor.org/rfc/rfc4954#section-4
     643                 */
     644                if ($oauth === '') {
     645                    //Sending an empty auth token is legitimate, but it must be encoded as '='
     646                    //to indicate it's not a 2-part command
     647                    if (!$this->sendCommand('AUTH', 'AUTH XOAUTH2 =', 235)) {
     648                        return false;
     649                    }
     650                } elseif (strlen($oauth) <= 497) {
     651                    //Authenticate using a token in the initial-response part
     652                    if (!$this->sendCommand('AUTH', 'AUTH XOAUTH2 ' . $oauth, 235)) {
     653                        return false;
     654                    }
     655                } else {
     656                    //The token is too long, so we need to send it in two parts.
     657                    //Send the auth command without a token and expect a 334
     658                    if (!$this->sendCommand('AUTH', 'AUTH XOAUTH2', 334)) {
     659                        return false;
     660                    }
     661                    //Send the token
     662                    if (!$this->sendCommand('OAuth TOKEN', $oauth, [235, 334])) {
     663                        return false;
     664                    }
     665                    //If the server answers with 334, send an empty line and wait for a 235
     666                    if (
     667                        substr($this->last_reply, 0, 3) === '334'
     668                        && $this->sendCommand('AUTH End', '', 235)
     669                    ) {
     670                        return false;
     671                    }
    640672                }
    641673                break;
     
    13101342                //stream_select returns false when the `select` system call is interrupted
    13111343                //by an incoming signal, try the select again
    1312                 if (stripos($message, 'interrupted system call') !== false) {
     1344                if (
     1345                    stripos($message, 'interrupted system call') !== false ||
     1346                    (
     1347                        // on applications with a different locale than english, the message above is not found because
     1348                        // it's translated. So we also check for the SOCKET_EINTR constant which is defined under
     1349                        // Windows and UNIX-like platforms (if available on the platform).
     1350                        defined('SOCKET_EINTR') &&
     1351                        stripos($message, 'stream_select(): Unable to select [' . SOCKET_EINTR . ']') !== false
     1352                    )
     1353                ) {
    13131354                    $this->edebug(
    13141355                        'SMTP -> get_lines(): retrying stream_select',
  • trunk/src/wp-includes/class-wp-phpmailer.php

    r60623 r60813  
    2525    public function __construct( $exceptions = false ) {
    2626        parent::__construct( $exceptions );
    27         $this->setLanguage();
     27        static::setLanguage();
    2828    }
    2929
     
    3737     * @return true Always returns true.
    3838     */
    39     public function setLanguage( $langcode = 'en', $lang_path = '' ) {
    40         $this->language = array(
     39    public static function setLanguage( $langcode = 'en', $lang_path = '' ) {
     40        static::$language = array(
    4141            'authenticate'         => __( 'SMTP Error: Could not authenticate.' ),
    4242            'buggy_php'            => sprintf(
     
    9090            'variable_set'         => __( 'Cannot set or reset variable: ' ),
    9191            'no_smtputf8'          => __( 'Server does not support SMTPUTF8 needed to send to Unicode addresses' ),
     92            'imap_recommended'     => __( 'Using simplified address parser is not recommended. Install the PHP IMAP extension for full RFC822 parsing.' ),
     93            'deprecated_argument'  => sprintf(
     94                /* translators: %s: $deprecatedArg */
     95                __( 'Argument %s is deprecated' ),
     96                '$deprecatedArg'
     97            ),
    9298        );
    9399
Note: See TracChangeset for help on using the changeset viewer.