WordPress.org

Make WordPress Core

Changeset 46097


Ignore:
Timestamp:
09/12/2019 02:36:42 PM (6 weeks ago)
Author:
SergeyBiryukov
Message:

Mail: Update PHPMailer to 5.2.27.

The full list of changes is available here:
https://github.com/PHPMailer/PHPMailer/compare/v5.2.22...PHPMailer:v5.2.27

Props MattyRob, ayeshrajans, rogueresearch, bgermann, slaFFik, Presskopp, aaroncampbell.
Fixes #40472.

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

Legend:

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

    r39759 r46097  
    3232     * @var string
    3333     */
    34     public $Version = '5.2.22';
     34    public $Version = '5.2.27';
    3535
    3636    /**
     
    441441     * Parameters:
    442442     *   boolean $result        result of the send action
    443      *   string  $to            email address of the recipient
    444      *   string  $cc            cc email addresses
    445      *   string  $bcc           bcc email addresses
     443     *   array   $to            email addresses of the recipients
     444     *   array   $cc            cc email addresses
     445     *   array   $bcc           bcc email addresses
    446446     *   string  $subject       the subject
    447447     *   string  $body          the email body
     
    660660            $this->exceptions = (boolean)$exceptions;
    661661        }
     662        //Pick an appropriate debug output format automatically
     663        $this->Debugoutput = (strpos(PHP_SAPI, 'cli') !== false ? 'echo' : 'html');
    662664    }
    663665
     
    12951297            // Sign with DKIM if enabled
    12961298            if (!empty($this->DKIM_domain)
    1297                 && !empty($this->DKIM_selector)
    1298                 && (!empty($this->DKIM_private_string)
    1299                    || (!empty($this->DKIM_private) && file_exists($this->DKIM_private))
     1299                and !empty($this->DKIM_selector)
     1300                and (!empty($this->DKIM_private_string)
     1301                    or (!empty($this->DKIM_private)
     1302                        and self::isPermittedPath($this->DKIM_private)
     1303                        and file_exists($this->DKIM_private)
     1304                    )
    13001305                )
    13011306            ) {
     
    14631468
    14641469    /**
     1470     * Check whether a file path is of a permitted type.
     1471     * Used to reject URLs and phar files from functions that access local file paths,
     1472     * such as addAttachment.
     1473     * @param string $path A relative or absolute path to a file.
     1474     * @return bool
     1475     */
     1476    protected static function isPermittedPath($path)
     1477    {
     1478        return !preg_match('#^[a-z]+://#i', $path);
     1479    }
     1480
     1481    /**
    14651482     * Send mail using the PHP mail() function.
    14661483     * @param string $header The message headers
     
    16241641        foreach ($hosts as $hostentry) {
    16251642            $hostinfo = array();
    1626             if (!preg_match('/^((ssl|tls):\/\/)*([a-zA-Z0-9\.-]*):?([0-9]*)$/', trim($hostentry), $hostinfo)) {
     1643            if (!preg_match(
     1644                '/^((ssl|tls):\/\/)*([a-zA-Z0-9\.-]*|\[[a-fA-F0-9:]+\]):?([0-9]*)$/',
     1645                trim($hostentry),
     1646                $hostinfo
     1647            )) {
    16271648                // Not a valid host entry
     1649                $this->edebug('Ignoring invalid host: ' . $hostentry);
    16281650                continue;
    16291651            }
     
    17441766            'no' => 'nb',
    17451767            'se' => 'sv',
     1768            'sr' => 'rs'
    17461769        );
    17471770
     
    17851808        if ($langcode != 'en') {
    17861809            // Make sure language file path is readable
    1787             if (!is_readable($lang_file)) {
     1810            if (!self::isPermittedPath($lang_file) or !is_readable($lang_file)) {
    17881811                $foundlang = false;
    17891812            } else {
     
    20262049        $result = '';
    20272050
    2028         if ($this->MessageDate == '') {
    2029             $this->MessageDate = self::rfcDate();
    2030         }
    2031         $result .= $this->headerLine('Date', $this->MessageDate);
     2051        $result .= $this->headerLine('Date', $this->MessageDate == '' ? self::rfcDate() : $this->MessageDate);
    20322052
    20332053        // To be created automatically by mail()
     
    24962516     * Never use a user-supplied path to a file!
    24972517     * Returns false if the file could not be found or read.
     2518     * Explicitly *does not* support passing URLs; PHPMailer is not an HTTP client.
     2519     * If you need to do that, fetch the resource yourself and pass it in via a local file or string.
    24982520     * @param string $path Path to the attachment.
    24992521     * @param string $name Overrides the attachment name.
     
    25072529    {
    25082530        try {
    2509             if (!@is_file($path)) {
     2531            if (!self::isPermittedPath($path) or !@is_file($path)) {
    25102532                throw new phpmailerException($this->lang('file_access') . $path, self::STOP_CONTINUE);
    25112533            }
     
    26882710    {
    26892711        try {
    2690             if (!is_readable($path)) {
     2712            if (!self::isPermittedPath($path) or !file_exists($path)) {
    26912713                throw new phpmailerException($this->lang('file_open') . $path, self::STOP_CONTINUE);
    26922714            }
     
    30323054    public function addEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = '', $disposition = 'inline')
    30333055    {
    3034         if (!@is_file($path)) {
     3056        if (!self::isPermittedPath($path) or !@is_file($path)) {
    30353057            $this->setError($this->lang('file_access') . $path);
    30363058            return false;
     
    40354057    public function errorMessage()
    40364058    {
    4037         $errorMsg = '<strong>' . $this->getMessage() . "</strong><br />\n";
     4059        $errorMsg = '<strong>' . htmlspecialchars($this->getMessage()) . "</strong><br />\n";
    40384060        return $errorMsg;
    40394061    }
  • trunk/src/wp-includes/class-smtp.php

    r44894 r46097  
    3131     * @var string
    3232     */
    33     const VERSION = '5.2.22';
     33    const VERSION = '5.2.27';
    3434
    3535    /**
     
    8282     * @see SMTP::VERSION
    8383     */
    84     public $Version = '5.2.22';
     84    public $Version = '5.2.27';
    8585
    8686    /**
     
    151151    public $Timelimit = 300;
    152152
    153     /**
    154      * @var array patterns to extract smtp transaction id from smtp reply
    155      * Only first capture group will be use, use non-capturing group to deal with it
    156      * Extend this class to override this property to fulfil your needs.
    157      */
    158     protected $smtp_transaction_id_patterns = array(
    159         'exim' => '/[0-9]{3} OK id=(.*)/',
    160         'sendmail' => '/[0-9]{3} 2.0.0 (.*) Message/',
    161         'postfix' => '/[0-9]{3} 2.0.0 Ok: queued as (.*)/'
    162     );
     153    /**
     154     * @var array Patterns to extract an SMTP transaction id from reply to a DATA command.
     155     * The first capture group in each regex will be used as the ID.
     156     */
     157    protected $smtp_transaction_id_patterns = array(
     158        'exim' => '/[0-9]{3} OK id=(.*)/',
     159        'sendmail' => '/[0-9]{3} 2.0.0 (.*) Message/',
     160        'postfix' => '/[0-9]{3} 2.0.0 Ok: queued as (.*)/'
     161    );
     162
     163    /**
     164     * @var string The last transaction ID issued in response to a DATA command,
     165     * if one was detected
     166     */
     167    protected $last_smtp_transaction_id;
    163168
    164169    /**
     
    228233            case 'html':
    229234                //Cleans up output a bit for a better looking, HTML-safe output
    230                 echo htmlentities(
     235                echo gmdate('Y-m-d H:i:s') . ' ' . htmlentities(
    231236                    preg_replace('/[\r\n]+/', '', $str),
    232237                    ENT_QUOTES,
    233238                    'UTF-8'
    234                 )
    235                 . "<br>\n";
     239                ) . "<br>\n";
    236240                break;
    237241            case 'echo':
     
    243247                    "\n                   \t                  ",
    244248                    trim($str)
    245                 )."\n";
     249                ) . "\n";
    246250        }
    247251    }
     
    277281        // Connect to the SMTP server
    278282        $this->edebug(
    279             "Connection: opening to $host:$port, timeout=$timeout, options=".var_export($options, true),
     283            "Connection: opening to $host:$port, timeout=$timeout, options=" .
     284            var_export($options, true),
    280285            self::DEBUG_CONNECTION
    281286        );
     
    363368
    364369        // Begin encrypted connection
    365         if (!stream_socket_enable_crypto(
     370        set_error_handler(array($this, 'errorHandler'));
     371        $crypto_ok = stream_socket_enable_crypto(
    366372            $this->smtp_conn,
    367373            true,
    368374            $crypto_method
    369         )) {
    370             return false;
    371         }
    372         return true;
     375        );
     376        restore_error_handler();
     377        return $crypto_ok;
    373378    }
    374379
     
    399404
    400405        if (array_key_exists('EHLO', $this->server_caps)) {
    401         // SMTP extensions are available. Let's try to find a proper authentication method
    402 
     406            // SMTP extensions are available; try to find a proper authentication method
    403407            if (!array_key_exists('AUTH', $this->server_caps)) {
    404408                $this->setError('Authentication is not allowed at this stage');
     
    425429                    return false;
    426430                }
    427                 self::edebug('Auth method selected: '.$authtype, self::DEBUG_LOWLEVEL);
     431                self::edebug('Auth method selected: ' . $authtype, self::DEBUG_LOWLEVEL);
    428432            }
    429433
     
    488492     * in case that function is not available
    489493     * @param string $data The data to hash
    490      * @param string $key  The key to hash with
     494     * @param string $key The key to hash with
    491495     * @access protected
    492496     * @return string
     
    565569     * Send an SMTP DATA command.
    566570     * Issues a data command and sends the msg_data to the server,
    567      * finalizing the mail transaction. $msg_data is the message
     571     * finializing the mail transaction. $msg_data is the message
    568572     * that is to be send with the headers. Each header needs to be
    569573     * on a single line followed by a <CRLF> with the message headers
    570      * and the message body being separated by an additional <CRLF>.
     574     * and the message body being separated by and additional <CRLF>.
    571575     * Implements rfc 821: DATA <CRLF>
    572576     * @param string $msg_data Message data to send
     
    648652        $this->Timelimit = $this->Timelimit * 2;
    649653        $result = $this->sendCommand('DATA END', '.', 250);
     654        $this->recordLastTransactionID();
    650655        //Restore timelimit
    651656        $this->Timelimit = $savetimelimit;
     
    831836            // Cut off error code from each response line
    832837            $detail = preg_replace(
    833                 "/{$code}[ -]".($code_ex ? str_replace('.', '\\.', $code_ex).' ' : '')."/m",
     838                "/{$code}[ -]" .
     839                ($code_ex ? str_replace('.', '\\.', $code_ex) . ' ' : '') . "/m",
    834840                '',
    835841                $this->last_reply
     
    927933    {
    928934        $this->edebug("CLIENT -> SERVER: $data", self::DEBUG_CLIENT);
    929         return fwrite($this->smtp_conn, $data);
     935        set_error_handler(array($this, 'errorHandler'));
     936        $result = fwrite($this->smtp_conn, $data);
     937        restore_error_handler();
     938        return $result;
    930939    }
    931940
     
    10271036            $this->edebug("SMTP -> get_lines(): \$str is  \"$str\"", self::DEBUG_LOWLEVEL);
    10281037            $data .= $str;
    1029             // If 4th character is a space, we are done reading, break the loop, micro-optimisation over strlen
    1030             if ((isset($str[3]) and $str[3] == ' ')) {
     1038            // If response is only 3 chars (not valid, but RFC5321 S4.2 says it must be handled),
     1039            // or 4th character is a space, we are done reading, break the loop,
     1040            // string array access is a micro-optimisation over strlen
     1041            if (!isset($str[3]) or (isset($str[3]) and $str[3] == ' ')) {
    10311042                break;
    10321043            }
     
    10431054            if ($endtime and time() > $endtime) {
    10441055                $this->edebug(
    1045                     'SMTP -> get_lines(): timelimit reached ('.
     1056                    'SMTP -> get_lines(): timelimit reached (' .
    10461057                    $this->Timelimit . ' sec)',
    10471058                    self::DEBUG_LOWLEVEL
     
    11461157     * @param integer $errno The error number returned by PHP.
    11471158     * @param string $errmsg The error message returned by PHP.
    1148      */
    1149     protected function errorHandler($errno, $errmsg)
    1150     {
    1151         $notice = 'Connection: Failed to connect to server.';
     1159     * @param string $errfile The file the error occurred in
     1160     * @param integer $errline The line number the error occurred on
     1161     */
     1162    protected function errorHandler($errno, $errmsg, $errfile = '', $errline = 0)
     1163    {
     1164        $notice = 'Connection failed.';
    11521165        $this->setError(
    11531166            $notice,
     
    11561169        );
    11571170        $this->edebug(
    1158             $notice . ' Error number ' . $errno . '. "Error notice: ' . $errmsg,
     1171            $notice . ' Error #' . $errno . ': ' . $errmsg . " [$errfile line $errline]",
    11591172            self::DEBUG_CONNECTION
    11601173        );
    11611174    }
    11621175
    1163     /**
    1164      * Will return the ID of the last smtp transaction based on a list of patterns provided
    1165      * in SMTP::$smtp_transaction_id_patterns.
    1166      * If no reply has been received yet, it will return null.
    1167      * If no pattern has been matched, it will return false.
    1168      * @return bool|null|string
    1169      */
    1170     public function getLastTransactionID()
    1171     {
    1172         $reply = $this->getLastReply();
    1173 
    1174         if (empty($reply)) {
    1175             return null;
    1176         }
    1177 
    1178         foreach($this->smtp_transaction_id_patterns as $smtp_transaction_id_pattern) {
    1179             if(preg_match($smtp_transaction_id_pattern, $reply, $matches)) {
    1180                 return $matches[1];
    1181             }
    1182         }
    1183 
    1184         return false;
     1176    /**
     1177     * Extract and return the ID of the last SMTP transaction based on
     1178     * a list of patterns provided in SMTP::$smtp_transaction_id_patterns.
     1179     * Relies on the host providing the ID in response to a DATA command.
     1180     * If no reply has been received yet, it will return null.
     1181     * If no pattern was matched, it will return false.
     1182     * @return bool|null|string
     1183     */
     1184    protected function recordLastTransactionID()
     1185    {
     1186        $reply = $this->getLastReply();
     1187
     1188        if (empty($reply)) {
     1189            $this->last_smtp_transaction_id = null;
     1190        } else {
     1191            $this->last_smtp_transaction_id = false;
     1192            foreach ($this->smtp_transaction_id_patterns as $smtp_transaction_id_pattern) {
     1193                if (preg_match($smtp_transaction_id_pattern, $reply, $matches)) {
     1194                    $this->last_smtp_transaction_id = $matches[1];
     1195                }
     1196            }
     1197        }
     1198
     1199        return $this->last_smtp_transaction_id;
     1200    }
     1201
     1202    /**
     1203     * Get the queue/transaction ID of the last SMTP transaction
     1204     * If no reply has been received yet, it will return null.
     1205     * If no pattern was matched, it will return false.
     1206     * @return bool|null|string
     1207     * @see recordLastTransactionID()
     1208     */
     1209    public function getLastTransactionID()
     1210    {
     1211        return $this->last_smtp_transaction_id;
    11851212    }
    11861213}
Note: See TracChangeset for help on using the changeset viewer.