WordPress 4.6.2 wordpress-4.6.2
authorEdward Z. Yang <ezyang@cs.stanford.edu>
Thu, 26 Jan 2017 23:07:39 +0000 (15:07 -0800)
committerEdward Z. Yang <ezyang@cs.stanford.edu>
Thu, 26 Jan 2017 23:07:39 +0000 (15:07 -0800)
Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
21 files changed:
license.txt
readme.html
wp-admin/about.php
wp-admin/includes/class-wp-screen.php
wp-admin/includes/media.php
wp-admin/update-core.php
wp-admin/widgets.php
wp-content/plugins/akismet/readme.txt
wp-includes/Requests/IRI.php
wp-includes/Requests/Transport/cURL.php
wp-includes/Requests/Transport/fsockopen.php
wp-includes/class-http.php
wp-includes/class-phpmailer.php
wp-includes/class-requests.php
wp-includes/class-smtp.php
wp-includes/class-wp-theme.php
wp-includes/functions.php
wp-includes/ms-functions.php
wp-includes/version.php
wp-includes/wp-db.php
wp-mail.php

index 9166e6203889fc0637eebfdc48a8b79d707eef66..5a605dac3b4a5e52e5fec6e38d94adad98281dc5 100644 (file)
@@ -1,6 +1,6 @@
 WordPress - Web publishing software\r
 \r
-Copyright 2011-2016 by the contributors\r
+Copyright 2011-2017 by the contributors\r
 \r
 This program is free software; you can redistribute it and/or modify\r
 it under the terms of the GNU General Public License as published by\r
index 63b2598d2763132572cb4a5e155b6e32446b3146..b3ef500801e4649f9b1de5e3d0d43c24e33c3231 100644 (file)
@@ -9,7 +9,7 @@
 <body>
 <h1 id="logo">
        <a href="https://wordpress.org/"><img alt="WordPress" src="wp-admin/images/wordpress-logo.png" /></a>
-       <br /> Version 4.6.1
+       <br /> Version 4.6.2
 </h1>
 <p style="text-align: center">Semantic Personal Publishing Platform</p>
 
index 6e77b1b4323393f9a79a93665fd8d2f0027dd554..f43006c7a4ccf19bd85ecb91d6234af4777e639a 100644 (file)
@@ -59,7 +59,10 @@ include( ABSPATH . 'wp-admin/admin-header.php' );
                </h2>
 
                <div class="changelog point-releases">
-                       <h3><?php _e( 'Maintenance and Security Release' ); ?></h3>
+                       <h3><?php _e( 'Maintenance and Security Releases' ); ?></h3>
+                       <p><?php printf( __( '<strong>Version %s</strong> addressed some security issues.' ), '4.6.2' ); ?>
+                               <?php printf( __( 'For more information, see <a href="%s">the release notes</a>.' ), 'https://codex.wordpress.org/Version_4.6.2' ); ?>
+                       </p>
                        <p><?php printf( _n( '<strong>Version %1$s</strong> addressed some security issues and fixed %2$s bug.',
                                '<strong>Version %1$s</strong> addressed some security issues and fixed %2$s bugs.', 15 ), '4.6.1', number_format_i18n( 15 ) ); ?>
                                <?php printf( __( 'For more information, see <a href="%s">the release notes</a>.' ), 'https://codex.wordpress.org/Version_4.6.1' ); ?>
index a7d9a1a5c34c13602f5e135605e8d0c96695dcf9..967875917c688dad2abb8a915d37cb7cbadf554a 100644 (file)
@@ -915,7 +915,8 @@ final class WP_Screen {
 
                switch ( $this->base ) {
                        case 'widgets':
-                               $this->_screen_settings = '<p><a id="access-on" href="widgets.php?widgets-access=on">' . __('Enable accessibility mode') . '</a><a id="access-off" href="widgets.php?widgets-access=off">' . __('Disable accessibility mode') . "</a></p>\n";
+                               $nonce = wp_create_nonce( 'widgets-access' );
+                               $this->_screen_settings = '<p><a id="access-on" href="widgets.php?widgets-access=on&_wpnonce=' . urlencode( $nonce ) . '">' . __('Enable accessibility mode') . '</a><a id="access-off" href="widgets.php?widgets-access=off&_wpnonce=' . urlencode( $nonce ) . '">' . __('Disable accessibility mode') . "</a></p>\n";
                                break;
                        case 'post' :
                                $expand = '<fieldset class="editor-expand hidden"><legend>' . __( 'Additional settings' ) . '</legend><label for="editor-expand-toggle">';
index c6b2dcd1ba4fb25271de5e637dcc9ce793268eb2..7ff6e4a652865b89c9cb47ea8b2ce2ddcb1ce799 100644 (file)
@@ -290,7 +290,7 @@ function media_handle_upload($file_id, $post_id, $post_data = array(), $override
        $url = $file['url'];
        $type = $file['type'];
        $file = $file['file'];
-       $title = sanitize_title( $name );
+       $title = sanitize_text_field( $name );
        $content = '';
        $excerpt = '';
 
index 404bb8ac8b10a5fbd5ca37222f88c9933a0d9864..e123463bb0caa33695a80f855f4f9f56a08a8c92 100644 (file)
@@ -253,6 +253,8 @@ function list_plugin_updates() {
        <tbody class="plugins">
 <?php
        foreach ( (array) $plugins as $plugin_file => $plugin_data ) {
+               $plugin_data = (object) _get_plugin_data_markup_translate( $plugin_file, (array) $plugin_data, false, true );
+
                // Get plugin compat for running version of WordPress.
                if ( isset($plugin_data->update->tested) && version_compare($plugin_data->update->tested, $cur_wp_version, '>=') ) {
                        $compat = '<br />' . sprintf(__('Compatibility with WordPress %1$s: 100%% (according to its author)'), $cur_wp_version);
index a9876b891cef4d6dd6eb5a76440c8a1d9945c1e0..c70b1d1ad72ee86a099bda4cae986587ba045f48 100644 (file)
@@ -22,6 +22,8 @@ if ( ! current_user_can( 'edit_theme_options' ) ) {
 
 $widgets_access = get_user_setting( 'widgets_access' );
 if ( isset($_GET['widgets-access']) ) {
+       check_admin_referer( 'widgets-access' );
+
        $widgets_access = 'on' == $_GET['widgets-access'] ? 'on' : 'off';
        set_user_setting( 'widgets_access', $widgets_access );
 }
index 41c75408d14b8b2437d9deb8f8fd36820192a1e2..a21862a01a1201bfbc88b794067a38d608e27fbb 100644 (file)
@@ -2,7 +2,7 @@
 Contributors: matt, ryan, andy, mdawaffe, tellyworth, josephscott, lessbloat, eoigal, cfinke, automattic, jgs
 Tags: akismet, comments, spam, antispam, anti-spam, anti spam, comment moderation, comment spam, contact form spam, spam comments
 Requires at least: 3.7
-Tested up to: 4.6.1
+Tested up to: 4.7
 Stable tag: 3.2
 License: GPLv2 or later
 
index 44a95171b7dcd9725029752f04ce065fe2e6fd8e..8dc2fa2841ed3006210328254ca57cbb2cfd13b2 100644 (file)
@@ -688,10 +688,7 @@ class Requests_IRI {
                $isauthority = $this->iuserinfo !== null || $this->ihost !== null || $this->port !== null;
                if ($this->ipath !== '' &&
                        (
-                               $isauthority && (
-                                       $this->ipath[0] !== '/' ||
-                                       substr($this->ipath, 0, 2) === '//'
-                               ) ||
+                               $isauthority && $this->ipath[0] !== '/' ||
                                (
                                        $this->scheme === null &&
                                        !$isauthority &&
index 7979b2eba0430f121a0e6e71d50a5c9ad73a5c10..4429edb647321c18bcd6bc44cce025a868fae1af 100644 (file)
@@ -375,8 +375,9 @@ class Requests_Transport_cURL implements Requests_Transport {
                curl_setopt($this->handle, CURLOPT_URL, $url);
                curl_setopt($this->handle, CURLOPT_REFERER, $url);
                curl_setopt($this->handle, CURLOPT_USERAGENT, $options['useragent']);
-               curl_setopt($this->handle, CURLOPT_HTTPHEADER, $headers);
-
+               if (!empty($headers)) {
+                       curl_setopt($this->handle, CURLOPT_HTTPHEADER, $headers);
+               }
                if ($options['protocol_version'] === 1.1) {
                        curl_setopt($this->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
                }
@@ -458,7 +459,7 @@ class Requests_Transport_cURL implements Requests_Transport {
         * @param string $data Body data
         * @return integer Length of provided data
         */
-       protected function stream_body($handle, $data) {
+       public function stream_body($handle, $data) {
                $this->hooks->dispatch('request.progress', array($data, $this->response_bytes, $this->response_byte_limit));
                $data_length = strlen($data);
 
index e9170f417ceb2d424be89700ebf23ae4cca0a75d..21cb56d5eccab6cf65dbbb230c3515661a30ff25 100644 (file)
@@ -70,7 +70,9 @@ class Requests_Transport_fsockopen implements Requests_Transport {
                // HTTPS support
                if (isset($url_parts['scheme']) && strtolower($url_parts['scheme']) === 'https') {
                        $remote_socket = 'ssl://' . $host;
-                       $url_parts['port'] = 443;
+                       if (!isset($url_parts['port'])) {
+                               $url_parts['port'] = 443;
+                       }
 
                        $context_options = array(
                                'verify_peer' => true,
@@ -97,6 +99,7 @@ class Requests_Transport_fsockopen implements Requests_Transport {
                        }
 
                        if (isset($options['verifyname']) && $options['verifyname'] === false) {
+                               $context_options['verify_peer_name'] = false;
                                $verifyname = false;
                        }
 
@@ -171,7 +174,7 @@ class Requests_Transport_fsockopen implements Requests_Transport {
                if (!isset($case_insensitive_headers['Host'])) {
                        $out .= sprintf('Host: %s', $url_parts['host']);
 
-                       if ($url_parts['port'] !== 80) {
+                       if (( 'http' === strtolower($url_parts['scheme']) && $url_parts['port'] !== 80 ) || ( 'https' === strtolower($url_parts['scheme']) && $url_parts['port'] !== 443 )) {
                                $out .= ':' . $url_parts['port'];
                        }
                        $out .= "\r\n";
index c0272ba487fbc89d42cc9cfff28e4890e9317db7..5a3075846c4a76acefd3f57c5613d04b3c007599 100644 (file)
@@ -332,6 +332,7 @@ class WP_Http {
                // SSL certificate handling
                if ( ! $r['sslverify'] ) {
                        $options['verify'] = false;
+                       $options['verifyname'] = false;
                } else {
                        $options['verify'] = $r['sslcertificates'];
                }
@@ -362,8 +363,8 @@ class WP_Http {
                        }
                }
 
-               // Work around a bug in Requests when the path starts with // See https://github.com/rmccue/Requests/issues/231
-               $url = preg_replace( '!^(\w+://[^/]+)//(.*)$!i', '$1/$2', $url );
+               // Avoid issues where mbstring.func_overload is enabled
+               mbstring_binary_safe_encoding();
 
                try {
                        $requests_response = Requests::request( $url, $headers, $data, $type, $options );
@@ -379,6 +380,8 @@ class WP_Http {
                        $response = new WP_Error( 'http_request_failed', $e->getMessage() );
                }
 
+               reset_mbstring_encoding();
+
                /**
                 * Fires after an HTTP API response is received and before the response is returned.
                 *
index b28c4ef2fad1be14d42682c0d9d0334464501e75..0e48d7269f0d734e1d4b67430e46cb456b668d55 100644 (file)
@@ -31,7 +31,7 @@ class PHPMailer
      * The PHPMailer Version number.
      * @var string
      */
-    public $Version = '5.2.14';
+    public $Version = '5.2.22';
 
     /**
      * Email priority.
@@ -201,6 +201,9 @@ class PHPMailer
     /**
      * An ID to be used in the Message-ID header.
      * If empty, a unique id will be generated.
+     * You can set your own, but it must be in the format "<id@domain>",
+     * as defined in RFC5322 section 3.6.4 or it will be ignored.
+     * @see https://tools.ietf.org/html/rfc5322#section-3.6.4
      * @var string
      */
     public $MessageID = '';
@@ -285,7 +288,7 @@ class PHPMailer
 
     /**
      * SMTP auth type.
-     * Options are LOGIN (default), PLAIN, NTLM, CRAM-MD5
+     * Options are CRAM-MD5, LOGIN, PLAIN, attempted in that order if not specified
      * @var string
      */
     public $AuthType = '';
@@ -352,6 +355,7 @@ class PHPMailer
     /**
      * Whether to split multiple to addresses into multiple messages
      * or send them all in one message.
+     * Only supported in `mail` and `sendmail` transports, not in SMTP.
      * @var boolean
      */
     public $SingleTo = false;
@@ -394,7 +398,7 @@ class PHPMailer
 
     /**
      * DKIM Identity.
-     * Usually the email address used as the source of the email
+     * Usually the email address used as the source of the email.
      * @var string
      */
     public $DKIM_identity = '';
@@ -419,6 +423,13 @@ class PHPMailer
      */
     public $DKIM_private = '';
 
+    /**
+     * DKIM private key string.
+     * If set, takes precedence over `$DKIM_private`.
+     * @var string
+     */
+    public $DKIM_private_string = '';
+
     /**
      * Callback Action function name.
      *
@@ -446,6 +457,15 @@ class PHPMailer
      */
     public $XMailer = '';
 
+    /**
+     * Which validator to use by default when validating email addresses.
+     * May be a callable to inject your own validator, but there are several built-in validators.
+     * @see PHPMailer::validateAddress()
+     * @var string|callable
+     * @static
+     */
+    public static $validator = 'auto';
+
     /**
      * An instance of the SMTP sender class.
      * @var SMTP
@@ -634,9 +654,11 @@ class PHPMailer
      * Constructor.
      * @param boolean $exceptions Should we throw external exceptions?
      */
-    public function __construct($exceptions = false)
+    public function __construct($exceptions = null)
     {
-        $this->exceptions = (boolean)$exceptions;
+        if ($exceptions !== null) {
+            $this->exceptions = (boolean)$exceptions;
+        }
     }
 
     /**
@@ -645,9 +667,7 @@ class PHPMailer
     public function __destruct()
     {
         //Close any open SMTP connection nicely
-        if ($this->Mailer == 'smtp') {
-            $this->smtpClose();
-        }
+        $this->smtpClose();
     }
 
     /**
@@ -671,14 +691,16 @@ class PHPMailer
         } else {
             $subject = $this->encodeHeader($this->secureHeader($subject));
         }
-        if (ini_get('safe_mode') || !($this->UseSendmailOptions)) {
+
+        //Can't use additional_parameters in safe_mode, calling mail() with null params breaks
+        //@link http://php.net/manual/en/function.mail.php
+        if (ini_get('safe_mode') or !$this->UseSendmailOptions or is_null($params)) {
             $result = @mail($to, $subject, $body, $header);
         } else {
             $result = @mail($to, $subject, $body, $header, $params);
         }
         return $result;
     }
-
     /**
      * Output debugging info via user-defined method.
      * Only generates output if SMTP debug output is enabled (@see SMTP::$do_debug).
@@ -713,7 +735,7 @@ class PHPMailer
             case 'echo':
             default:
                 //Normalize line breaks
-                $str = preg_replace('/(\r\n|\r|\n)/ms', "\n", $str);
+                $str = preg_replace('/\r\n?/ms', "\n", $str);
                 echo gmdate('Y-m-d H:i:s') . "\t" . str_replace(
                     "\n",
                     "\n                   \t                  ",
@@ -850,7 +872,7 @@ class PHPMailer
         $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
         if (($pos = strrpos($address, '@')) === false) {
             // At-sign is misssing.
-            $error_message = $this->lang('invalid_address') . $address;
+            $error_message = $this->lang('invalid_address') . " (addAnAddress $kind): $address";
             $this->setError($error_message);
             $this->edebug($error_message);
             if ($this->exceptions) {
@@ -900,7 +922,7 @@ class PHPMailer
             return false;
         }
         if (!$this->validateAddress($address)) {
-            $error_message = $this->lang('invalid_address') . $address;
+            $error_message = $this->lang('invalid_address') . " (addAnAddress $kind): $address";
             $this->setError($error_message);
             $this->edebug($error_message);
             if ($this->exceptions) {
@@ -923,6 +945,61 @@ class PHPMailer
         return false;
     }
 
+    /**
+     * Parse and validate a string containing one or more RFC822-style comma-separated email addresses
+     * of the form "display name <address>" into an array of name/address pairs.
+     * Uses the imap_rfc822_parse_adrlist function if the IMAP extension is available.
+     * Note that quotes in the name part are removed.
+     * @param string $addrstr The address list string
+     * @param bool $useimap Whether to use the IMAP extension to parse the list
+     * @return array
+     * @link http://www.andrew.cmu.edu/user/agreen1/testing/mrbs/web/Mail/RFC822.php A more careful implementation
+     */
+    public function parseAddresses($addrstr, $useimap = true)
+    {
+        $addresses = array();
+        if ($useimap and function_exists('imap_rfc822_parse_adrlist')) {
+            //Use this built-in parser if it's available
+            $list = imap_rfc822_parse_adrlist($addrstr, '');
+            foreach ($list as $address) {
+                if ($address->host != '.SYNTAX-ERROR.') {
+                    if ($this->validateAddress($address->mailbox . '@' . $address->host)) {
+                        $addresses[] = array(
+                            'name' => (property_exists($address, 'personal') ? $address->personal : ''),
+                            'address' => $address->mailbox . '@' . $address->host
+                        );
+                    }
+                }
+            }
+        } else {
+            //Use this simpler parser
+            $list = explode(',', $addrstr);
+            foreach ($list as $address) {
+                $address = trim($address);
+                //Is there a separate name part?
+                if (strpos($address, '<') === false) {
+                    //No separate name, just use the whole thing
+                    if ($this->validateAddress($address)) {
+                        $addresses[] = array(
+                            'name' => '',
+                            'address' => $address
+                        );
+                    }
+                } else {
+                    list($name, $email) = explode('<', $address);
+                    $email = trim(str_replace('>', '', $email));
+                    if ($this->validateAddress($email)) {
+                        $addresses[] = array(
+                            'name' => trim(str_replace(array('"', "'"), '', $name)),
+                            'address' => $email
+                        );
+                    }
+                }
+            }
+        }
+        return $addresses;
+    }
+
     /**
      * Set the From and FromName properties.
      * @param string $address
@@ -939,7 +1016,7 @@ class PHPMailer
         if (($pos = strrpos($address, '@')) === false or
             (!$this->has8bitChars(substr($address, ++$pos)) or !$this->idnSupported()) and
             !$this->validateAddress($address)) {
-            $error_message = $this->lang('invalid_address') . $address;
+            $error_message = $this->lang('invalid_address') . " (setFrom) $address";
             $this->setError($error_message);
             $this->edebug($error_message);
             if ($this->exceptions) {
@@ -972,19 +1049,30 @@ class PHPMailer
     /**
      * Check that a string looks like an email address.
      * @param string $address The email address to check
-     * @param string $patternselect A selector for the validation pattern to use :
+     * @param string|callable $patternselect A selector for the validation pattern to use :
      * * `auto` Pick best pattern automatically;
      * * `pcre8` Use the squiloople.com pattern, requires PCRE > 8.0, PHP >= 5.3.2, 5.2.14;
      * * `pcre` Use old PCRE implementation;
      * * `php` Use PHP built-in FILTER_VALIDATE_EMAIL;
      * * `html5` Use the pattern given by the HTML5 spec for 'email' type form input elements.
      * * `noregex` Don't use a regex: super fast, really dumb.
+     * Alternatively you may pass in a callable to inject your own validator, for example:
+     * PHPMailer::validateAddress('user@example.com', function($address) {
+     *     return (strpos($address, '@') !== false);
+     * });
+     * You can also set the PHPMailer::$validator static to a callable, allowing built-in methods to use your validator.
      * @return boolean
      * @static
      * @access public
      */
-    public static function validateAddress($address, $patternselect = 'auto')
+    public static function validateAddress($address, $patternselect = null)
     {
+        if (is_null($patternselect)) {
+            $patternselect = self::$validator;
+        }
+        if (is_callable($patternselect)) {
+            return call_user_func($patternselect, $address);
+        }
         //Reject line breaks in addresses; it's valid RFC5322, but not RFC5321
         if (strpos($address, "\n") !== false or strpos($address, "\r") !== false) {
             return false;
@@ -1161,7 +1249,7 @@ class PHPMailer
                 }
                 $this->$address_kind = $this->punyencodeAddress($this->$address_kind);
                 if (!$this->validateAddress($this->$address_kind)) {
-                    $error_message = $this->lang('invalid_address') . $this->$address_kind;
+                    $error_message = $this->lang('invalid_address') . ' (punyEncode) ' . $this->$address_kind;
                     $this->setError($error_message);
                     $this->edebug($error_message);
                     if ($this->exceptions) {
@@ -1172,7 +1260,7 @@ class PHPMailer
             }
 
             // Set whether the message is multipart/alternative
-            if (!empty($this->AltBody)) {
+            if ($this->alternativeExists()) {
                 $this->ContentType = 'multipart/alternative';
             }
 
@@ -1206,9 +1294,11 @@ class PHPMailer
 
             // Sign with DKIM if enabled
             if (!empty($this->DKIM_domain)
-                && !empty($this->DKIM_private)
                 && !empty($this->DKIM_selector)
-                && file_exists($this->DKIM_private)) {
+                && (!empty($this->DKIM_private_string)
+                   || (!empty($this->DKIM_private) && file_exists($this->DKIM_private))
+                )
+            ) {
                 $header_dkim = $this->DKIM_Add(
                     $this->MIMEHeader . $this->mailHeader,
                     $this->encodeHeader($this->secureHeader($this->Subject)),
@@ -1274,19 +1364,24 @@ class PHPMailer
      */
     protected function sendmailSend($header, $body)
     {
-        if ($this->Sender != '') {
+        // CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
+        if (!empty($this->Sender) and self::isShellSafe($this->Sender)) {
             if ($this->Mailer == 'qmail') {
-                $sendmail = sprintf('%s -f%s', escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
+                $sendmailFmt = '%s -f%s';
             } else {
-                $sendmail = sprintf('%s -oi -f%s -t', escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
+                $sendmailFmt = '%s -oi -f%s -t';
             }
         } else {
             if ($this->Mailer == 'qmail') {
-                $sendmail = sprintf('%s', escapeshellcmd($this->Sendmail));
+                $sendmailFmt = '%s';
             } else {
-                $sendmail = sprintf('%s -oi -t', escapeshellcmd($this->Sendmail));
+                $sendmailFmt = '%s -oi -t';
             }
         }
+
+        // TODO: If possible, this should be changed to escapeshellarg.  Needs thorough testing.
+        $sendmail = sprintf($sendmailFmt, escapeshellcmd($this->Sendmail), $this->Sender);
+
         if ($this->SingleTo) {
             foreach ($this->SingleToArray as $toAddr) {
                 if (!@$mail = popen($sendmail, 'w')) {
@@ -1332,6 +1427,40 @@ class PHPMailer
         return true;
     }
 
+    /**
+     * Fix CVE-2016-10033 and CVE-2016-10045 by disallowing potentially unsafe shell characters.
+     *
+     * Note that escapeshellarg and escapeshellcmd are inadequate for our purposes, especially on Windows.
+     * @param string $string The string to be validated
+     * @see https://github.com/PHPMailer/PHPMailer/issues/924 CVE-2016-10045 bug report
+     * @access protected
+     * @return boolean
+     */
+    protected static function isShellSafe($string)
+    {
+        // Future-proof
+        if (escapeshellcmd($string) !== $string
+            or !in_array(escapeshellarg($string), array("'$string'", "\"$string\""))
+        ) {
+            return false;
+        }
+
+        $length = strlen($string);
+
+        for ($i = 0; $i < $length; $i++) {
+            $c = $string[$i];
+
+            // All other characters have a special meaning in at least one common shell, including = and +.
+            // Full stop (.) has a special meaning in cmd.exe, but its impact should be negligible here.
+            // Note that this does permit non-Latin alphanumeric characters based on the current locale.
+            if (!ctype_alnum($c) && strpos('@_-.', $c) === false) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
     /**
      * Send mail using the PHP mail() function.
      * @param string $header The message headers
@@ -1349,17 +1478,20 @@ class PHPMailer
         }
         $to = implode(', ', $toArr);
 
-        if (empty($this->Sender)) {
-            $params = ' ';
-        } else {
-            $params = sprintf('-f%s', $this->Sender);
+        $params = null;
+        //This sets the SMTP envelope sender which gets turned into a return-path header by the receiver
+        if (!empty($this->Sender) and $this->validateAddress($this->Sender)) {
+            // CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
+            if (self::isShellSafe($this->Sender)) {
+                $params = sprintf('-f%s', $this->Sender);
+            }
         }
-        if ($this->Sender != '' and !ini_get('safe_mode')) {
+        if (!empty($this->Sender) and !ini_get('safe_mode') and $this->validateAddress($this->Sender)) {
             $old_from = ini_get('sendmail_from');
             ini_set('sendmail_from', $this->Sender);
         }
         $result = false;
-        if ($this->SingleTo && count($toArr) > 1) {
+        if ($this->SingleTo and count($toArr) > 1) {
             foreach ($toArr as $toAddr) {
                 $result = $this->mailPassthru($toAddr, $this->Subject, $body, $header, $params);
                 $this->doCallback($result, array($toAddr), $this->cc, $this->bcc, $this->Subject, $body, $this->From);
@@ -1409,10 +1541,10 @@ class PHPMailer
         if (!$this->smtpConnect($this->SMTPOptions)) {
             throw new phpmailerException($this->lang('smtp_connect_failed'), self::STOP_CRITICAL);
         }
-        if ('' == $this->Sender) {
-            $smtp_from = $this->From;
-        } else {
+        if (!empty($this->Sender) and $this->validateAddress($this->Sender)) {
             $smtp_from = $this->Sender;
+        } else {
+            $smtp_from = $this->From;
         }
         if (!$this->smtp->mail($smtp_from)) {
             $this->setError($this->lang('from_failed') . $smtp_from . ' : ' . implode(',', $this->smtp->getError()));
@@ -1466,12 +1598,17 @@ class PHPMailer
      * @throws phpmailerException
      * @return boolean
      */
-    public function smtpConnect($options = array())
+    public function smtpConnect($options = null)
     {
         if (is_null($this->smtp)) {
             $this->smtp = $this->getSMTPInstance();
         }
 
+        //If no options are provided, use whatever is set in the instance
+        if (is_null($options)) {
+            $options = $this->SMTPOptions;
+        }
+
         // Already connected?
         if ($this->smtp->connected()) {
             return true;
@@ -1541,7 +1678,7 @@ class PHPMailer
                         if (!$this->smtp->startTLS()) {
                             throw new phpmailerException($this->lang('connect_host'));
                         }
-                        // We must resend HELO after tls negotiation
+                        // We must resend EHLO after TLS negotiation
                         $this->smtp->hello($hello);
                     }
                     if ($this->SMTPAuth) {
@@ -1580,7 +1717,7 @@ class PHPMailer
      */
     public function smtpClose()
     {
-        if ($this->smtp !== null) {
+        if (is_a($this->smtp, 'SMTP')) {
             if ($this->smtp->connected()) {
                 $this->smtp->quit();
                 $this->smtp->close();
@@ -1599,6 +1736,19 @@ class PHPMailer
      */
     public function setLanguage($langcode = 'en', $lang_path = '')
     {
+        // Backwards compatibility for renamed language codes
+        $renamed_langcodes = array(
+            'br' => 'pt_br',
+            'cz' => 'cs',
+            'dk' => 'da',
+            'no' => 'nb',
+            'se' => 'sv',
+        );
+
+        if (isset($renamed_langcodes[$langcode])) {
+            $langcode = $renamed_langcodes[$langcode];
+        }
+
         // Define full set of translatable strings in English
         $PHPMAILER_LANG = array(
             'authenticate' => 'SMTP Error: Could not authenticate.',
@@ -1625,6 +1775,10 @@ class PHPMailer
             // Calculate an absolute path so it can work if CWD is not here
             $lang_path = dirname(__FILE__). DIRECTORY_SEPARATOR . 'language'. DIRECTORY_SEPARATOR;
         }
+        //Validate $langcode
+        if (!preg_match('/^[a-z]{2}(?:_[a-zA-Z]{2})?$/', $langcode)) {
+            $langcode = 'en';
+        }
         $foundlang = true;
         $lang_file = $lang_path . 'phpmailer.lang-' . $langcode . '.php';
         // There is no English translation file
@@ -1918,7 +2072,9 @@ class PHPMailer
             $result .= $this->headerLine('Subject', $this->encodeHeader($this->secureHeader($this->Subject)));
         }
 
-        if ($this->MessageID != '') {
+        // Only allow a custom message ID if it conforms to RFC 5322 section 3.6.4
+        // https://tools.ietf.org/html/rfc5322#section-3.6.4
+        if ('' != $this->MessageID and preg_match('/^<.*@.*>$/', $this->MessageID)) {
             $this->lastMessageID = $this->MessageID;
         } else {
             $this->lastMessageID = sprintf('<%s@%s>', $this->uniqueid, $this->serverHostname());
@@ -2020,7 +2176,15 @@ class PHPMailer
      */
     public function getSentMIMEMessage()
     {
-        return $this->MIMEHeader . $this->mailHeader . self::CRLF . $this->MIMEBody;
+        return rtrim($this->MIMEHeader . $this->mailHeader, "\n\r") . self::CRLF . self::CRLF . $this->MIMEBody;
+    }
+
+    /**
+     * Create unique ID
+     * @return string
+     */
+    protected function generateId() {
+        return md5(uniqid(time()));
     }
 
     /**
@@ -2034,7 +2198,7 @@ class PHPMailer
     {
         $body = '';
         //Create unique IDs and preset boundaries
-        $this->uniqueid = md5(uniqid(time()));
+        $this->uniqueid = $this->generateId();
         $this->boundary[1] = 'b1_' . $this->uniqueid;
         $this->boundary[2] = 'b2_' . $this->uniqueid;
         $this->boundary[3] = 'b3_' . $this->uniqueid;
@@ -2050,11 +2214,12 @@ class PHPMailer
         //Can we do a 7-bit downgrade?
         if ($bodyEncoding == '8bit' and !$this->has8bitChars($this->Body)) {
             $bodyEncoding = '7bit';
+            //All ISO 8859, Windows codepage and UTF-8 charsets are ascii compatible up to 7-bit
             $bodyCharSet = 'us-ascii';
         }
-        //If lines are too long, change to quoted-printable transfer encoding
-        if (self::hasLineLongerThanMax($this->Body)) {
-            $this->Encoding = 'quoted-printable';
+        //If lines are too long, and we're not already using an encoding that will shorten them,
+        //change to quoted-printable transfer encoding for the body part only
+        if ('base64' != $this->Encoding and self::hasLineLongerThanMax($this->Body)) {
             $bodyEncoding = 'quoted-printable';
         }
 
@@ -2063,10 +2228,12 @@ class PHPMailer
         //Can we do a 7-bit downgrade?
         if ($altBodyEncoding == '8bit' and !$this->has8bitChars($this->AltBody)) {
             $altBodyEncoding = '7bit';
+            //All ISO 8859, Windows codepage and UTF-8 charsets are ascii compatible up to 7-bit
             $altBodyCharSet = 'us-ascii';
         }
-        //If lines are too long, change to quoted-printable transfer encoding
-        if (self::hasLineLongerThanMax($this->AltBody)) {
+        //If lines are too long, and we're not already using an encoding that will shorten them,
+        //change to quoted-printable transfer encoding for the alt body part only
+        if ('base64' != $altBodyEncoding and self::hasLineLongerThanMax($this->AltBody)) {
             $altBodyEncoding = 'quoted-printable';
         }
         //Use this as a preamble in all multipart message types
@@ -2169,8 +2336,10 @@ class PHPMailer
                 $body .= $this->attachAll('attachment', $this->boundary[1]);
                 break;
             default:
-                // catch case 'plain' and case ''
-                $body .= $this->encodeString($this->Body, $bodyEncoding);
+                // Catch case 'plain' and case '', applies to simple `text/plain` and `text/html` body content types
+                //Reset the `Encoding` property in case we changed it for line length reasons
+                $this->Encoding = $bodyEncoding;
+                $body .= $this->encodeString($this->Body, $this->Encoding);
                 break;
         }
 
@@ -2276,8 +2445,7 @@ class PHPMailer
 
     /**
      * Set the message type.
-     * PHPMailer only supports some preset message types,
-     * not arbitrary MIME structures.
+     * PHPMailer only supports some preset message types, not arbitrary MIME structures.
      * @access protected
      * @return void
      */
@@ -2295,6 +2463,7 @@ class PHPMailer
         }
         $this->message_type = implode('_', $type);
         if ($this->message_type == '') {
+            //The 'plain' message_type refers to the message having a single body element, not that it is plain-text
             $this->message_type = 'plain';
         }
     }
@@ -2324,6 +2493,7 @@ class PHPMailer
 
     /**
      * Add an attachment from a path on the filesystem.
+     * Never use a user-supplied path to a file!
      * Returns false if the file could not be found or read.
      * @param string $path Path to the attachment.
      * @param string $name Overrides the attachment name.
@@ -2849,6 +3019,7 @@ class PHPMailer
      * displayed inline with the message, not just attached for download.
      * This is used in HTML messages that embed the images
      * the HTML refers to using the $cid value.
+     * Never use a user-supplied path to a file!
      * @param string $path Path to the attachment.
      * @param string $cid Content ID of the attachment; Use this to reference
      *        the content when using an embedded image in HTML.
@@ -3209,21 +3380,29 @@ class PHPMailer
     }
 
     /**
-     * Create a message from an HTML string.
-     * Automatically makes modifications for inline images and backgrounds
-     * and creates a plain-text version by converting the HTML.
-     * Overwrites any existing values in $this->Body and $this->AltBody
+     * Create a message body from an HTML string.
+     * Automatically inlines images and creates a plain-text version by converting the HTML,
+     * overwriting any existing values in Body and AltBody.
+     * Do not source $message content from user input!
+     * $basedir is prepended when handling relative URLs, e.g. <img src="/images/a.png"> and must not be empty
+     * will look for an image file in $basedir/images/a.png and convert it to inline.
+     * If you don't provide a $basedir, relative paths will be left untouched (and thus probably break in email)
+     * If you don't want to apply these transformations to your HTML, just set Body and AltBody directly.
      * @access public
      * @param string $message HTML message string
-     * @param string $basedir baseline directory for path
+     * @param string $basedir Absolute path to a base directory to prepend to relative paths to images
      * @param boolean|callable $advanced Whether to use the internal HTML to text converter
      *    or your own custom converter @see PHPMailer::html2text()
-     * @return string $message
+     * @return string $message The transformed message Body
      */
     public function msgHTML($message, $basedir = '', $advanced = false)
     {
         preg_match_all('/(src|background)=["\'](.*)["\']/Ui', $message, $images);
         if (array_key_exists(2, $images)) {
+            if (strlen($basedir) > 1 && substr($basedir, -1) != '/') {
+                // Ensure $basedir has a trailing /
+                $basedir .= '/';
+            }
             foreach ($images[2] as $imgindex => $url) {
                 // Convert data URIs into embedded images
                 if (preg_match('#^data:(image[^;,]*)(;base64)?,#', $url, $match)) {
@@ -3241,18 +3420,24 @@ class PHPMailer
                             $message
                         );
                     }
-                } elseif (substr($url, 0, 4) !== 'cid:' && !preg_match('#^[A-z]+://#', $url)) {
-                    // Do not change urls for absolute images (thanks to corvuscorax)
+                    continue;
+                }
+                if (
+                    // Only process relative URLs if a basedir is provided (i.e. no absolute local paths)
+                    !empty($basedir)
+                    // Ignore URLs containing parent dir traversal (..)
+                    && (strpos($url, '..') === false)
                     // Do not change urls that are already inline images
+                    && substr($url, 0, 4) !== 'cid:'
+                    // Do not change absolute URLs, including anonymous protocol
+                    && !preg_match('#^[a-z][a-z0-9+.-]*:?//#i', $url)
+                ) {
                     $filename = basename($url);
                     $directory = dirname($url);
                     if ($directory == '.') {
                         $directory = '';
                     }
                     $cid = md5($url) . '@phpmailer.0'; // RFC2392 S 2
-                    if (strlen($basedir) > 1 && substr($basedir, -1) != '/') {
-                        $basedir .= '/';
-                    }
                     if (strlen($directory) > 1 && substr($directory, -1) != '/') {
                         $directory .= '/';
                     }
@@ -3277,7 +3462,7 @@ class PHPMailer
         // Convert all message body line breaks to CRLF, makes quoted-printable encoding work much better
         $this->Body = $this->normalizeBreaks($message);
         $this->AltBody = $this->normalizeBreaks($this->html2text($message, $advanced));
-        if (empty($this->AltBody)) {
+        if (!$this->alternativeExists()) {
             $this->AltBody = 'To view this email message, open it in a program that understands HTML!' .
                 self::CRLF . self::CRLF;
         }
@@ -3288,7 +3473,7 @@ class PHPMailer
      * Convert an HTML string into plain text.
      * This is used by msgHTML().
      * Note - older versions of this function used a bundled advanced converter
-     * which was been removed for license reasons in #232
+     * which was been removed for license reasons in #232.
      * Example usage:
      * <code>
      * // Use default conversion
@@ -3588,7 +3773,7 @@ class PHPMailer
      * @access public
      * @param string $signHeader
      * @throws phpmailerException
-     * @return string
+     * @return string The DKIM signature value
      */
     public function DKIM_Sign($signHeader)
     {
@@ -3598,15 +3783,35 @@ class PHPMailer
             }
             return '';
         }
-        $privKeyStr = file_get_contents($this->DKIM_private);
-        if ($this->DKIM_passphrase != '') {
+        $privKeyStr = !empty($this->DKIM_private_string) ? $this->DKIM_private_string : file_get_contents($this->DKIM_private);
+        if ('' != $this->DKIM_passphrase) {
             $privKey = openssl_pkey_get_private($privKeyStr, $this->DKIM_passphrase);
         } else {
-            $privKey = $privKeyStr;
+            $privKey = openssl_pkey_get_private($privKeyStr);
         }
-        if (openssl_sign($signHeader, $signature, $privKey)) {
-            return base64_encode($signature);
+        //Workaround for missing digest algorithms in old PHP & OpenSSL versions
+        //@link http://stackoverflow.com/a/11117338/333340
+        if (version_compare(PHP_VERSION, '5.3.0') >= 0 and
+            in_array('sha256WithRSAEncryption', openssl_get_md_methods(true))) {
+            if (openssl_sign($signHeader, $signature, $privKey, 'sha256WithRSAEncryption')) {
+                openssl_pkey_free($privKey);
+                return base64_encode($signature);
+            }
+        } else {
+            $pinfo = openssl_pkey_get_details($privKey);
+            $hash = hash('sha256', $signHeader);
+            //'Magic' constant for SHA256 from RFC3447
+            //@link https://tools.ietf.org/html/rfc3447#page-43
+            $t = '3031300d060960864801650304020105000420' . $hash;
+            $pslen = $pinfo['bits'] / 8 - (strlen($t) / 2 + 3);
+            $eb = pack('H*', '0001' . str_repeat('FF', $pslen) . '00' . $t);
+
+            if (openssl_private_encrypt($eb, $signature, $privKey, OPENSSL_NO_PADDING)) {
+                openssl_pkey_free($privKey);
+                return base64_encode($signature);
+            }
         }
+        openssl_pkey_free($privKey);
         return '';
     }
 
@@ -3623,7 +3828,7 @@ class PHPMailer
         foreach ($lines as $key => $line) {
             list($heading, $value) = explode(':', $line, 2);
             $heading = strtolower($heading);
-            $value = preg_replace('/\s+/', ' ', $value); // Compress useless spaces
+            $value = preg_replace('/\s{2,}/', ' ', $value); // Compress useless spaces
             $lines[$key] = $heading . ':' . trim($value); // Don't forget to remove WSP around the value
         }
         $signHeader = implode("\r\n", $lines);
@@ -3661,7 +3866,7 @@ class PHPMailer
      */
     public function DKIM_Add($headers_line, $subject, $body)
     {
-        $DKIMsignatureType = 'rsa-sha1'; // Signature & hash algorithms
+        $DKIMsignatureType = 'rsa-sha256'; // Signature & hash algorithms
         $DKIMcanonicalization = 'relaxed/simple'; // Canonicalization of header/body
         $DKIMquery = 'dns/txt'; // Query method
         $DKIMtime = time(); // Signature Timestamp = seconds since 00:00:00 - Jan 1, 1970 (UTC time zone)
@@ -3669,6 +3874,7 @@ class PHPMailer
         $headers = explode($this->LE, $headers_line);
         $from_header = '';
         $to_header = '';
+        $date_header = '';
         $current = '';
         foreach ($headers as $header) {
             if (strpos($header, 'From:') === 0) {
@@ -3677,6 +3883,9 @@ class PHPMailer
             } elseif (strpos($header, 'To:') === 0) {
                 $to_header = $header;
                 $current = 'to_header';
+            } elseif (strpos($header, 'Date:') === 0) {
+                $date_header = $header;
+                $current = 'date_header';
             } else {
                 if (!empty($$current) && strpos($header, ' =?') === 0) {
                     $$current .= $header;
@@ -3687,6 +3896,7 @@ class PHPMailer
         }
         $from = str_replace('|', '=7C', $this->DKIM_QP($from_header));
         $to = str_replace('|', '=7C', $this->DKIM_QP($to_header));
+        $date = str_replace('|', '=7C', $this->DKIM_QP($date_header));
         $subject = str_replace(
             '|',
             '=7C',
@@ -3694,7 +3904,7 @@ class PHPMailer
         ); // Copied header fields (dkim-quoted-printable)
         $body = $this->DKIM_BodyC($body);
         $DKIMlen = strlen($body); // Length of body
-        $DKIMb64 = base64_encode(pack('H*', sha1($body))); // Base64 of packed binary SHA-1 hash of body
+        $DKIMb64 = base64_encode(pack('H*', hash('sha256', $body))); // Base64 of packed binary SHA-256 hash of body
         if ('' == $this->DKIM_identity) {
             $ident = '';
         } else {
@@ -3707,16 +3917,18 @@ class PHPMailer
             $this->DKIM_selector .
             ";\r\n" .
             "\tt=" . $DKIMtime . '; c=' . $DKIMcanonicalization . ";\r\n" .
-            "\th=From:To:Subject;\r\n" .
+            "\th=From:To:Date:Subject;\r\n" .
             "\td=" . $this->DKIM_domain . ';' . $ident . "\r\n" .
             "\tz=$from\r\n" .
             "\t|$to\r\n" .
+            "\t|$date\r\n" .
             "\t|$subject;\r\n" .
             "\tbh=" . $DKIMb64 . ";\r\n" .
             "\tb=";
         $toSign = $this->DKIM_HeaderC(
             $from_header . "\r\n" .
             $to_header . "\r\n" .
+            $date_header . "\r\n" .
             $subject_header . "\r\n" .
             $dkimhdrs
         );
index 5a6257a8ac248acb7eabcfe7318699074233d8aa..bb266189c19c7bd498d548e214a48725afc4e64a 100644 (file)
@@ -749,15 +749,17 @@ class Requests {
         * @return string Decoded body
         */
        protected static function decode_chunked($data) {
-               if (!preg_match('/^([0-9a-f]+)[^\r\n]*\r\n/i', trim($data))) {
+               if (!preg_match('/^([0-9a-f]+)(?:;(?:[\w-]*)(?:=(?:(?:[\w-]*)*|"(?:[^\r\n])*"))?)*\r\n/i', trim($data))) {
                        return $data;
                }
 
+
+
                $decoded = '';
                $encoded = $data;
 
                while (true) {
-                       $is_chunked = (bool) preg_match('/^([0-9a-f]+)[^\r\n]*\r\n/i', $encoded, $matches);
+                       $is_chunked = (bool) preg_match('/^([0-9a-f]+)(?:;(?:[\w-]*)(?:=(?:(?:[\w-]*)*|"(?:[^\r\n])*"))?)*\r\n/i', $encoded, $matches);
                        if (!$is_chunked) {
                                // Looks like it's not chunked after all
                                return $data;
index f17ca0fd9717d618a37115083781385498303b65..3ad081926a51a32d12a350623d7237df7785235c 100644 (file)
@@ -30,7 +30,7 @@ class SMTP
      * The PHPMailer SMTP version number.
      * @var string
      */
-    const VERSION = '5.2.14';
+    const VERSION = '5.2.22';
 
     /**
      * SMTP line break constant.
@@ -81,7 +81,7 @@ class SMTP
      * @deprecated Use the `VERSION` constant instead
      * @see SMTP::VERSION
      */
-    public $Version = '5.2.14';
+    public $Version = '5.2.22';
 
     /**
      * SMTP server port number.
@@ -150,6 +150,17 @@ class SMTP
      */
     public $Timelimit = 300;
 
+       /**
+        * @var array patterns to extract smtp transaction id from smtp reply
+        * Only first capture group will be use, use non-capturing group to deal with it
+        * Extend this class to override this property to fulfil your needs.
+        */
+       protected $smtp_transaction_id_patterns = array(
+               'exim' => '/[0-9]{3} OK id=(.*)/',
+               'sendmail' => '/[0-9]{3} 2.0.0 (.*) Message/',
+               'postfix' => '/[0-9]{3} 2.0.0 Ok: queued as (.*)/'
+       );
+
     /**
      * The socket for the server connection.
      * @var resource
@@ -206,7 +217,7 @@ class SMTP
         }
         //Avoid clash with built-in function names
         if (!in_array($this->Debugoutput, array('error_log', 'html', 'echo')) and is_callable($this->Debugoutput)) {
-            call_user_func($this->Debugoutput, $str, $this->do_debug);
+            call_user_func($this->Debugoutput, $str, $level);
             return;
         }
         switch ($this->Debugoutput) {
@@ -272,8 +283,8 @@ class SMTP
         $errstr = '';
         if ($streamok) {
             $socket_context = stream_context_create($options);
-            //Suppress errors; connection failures are handled at a higher level
-            $this->smtp_conn = @stream_socket_client(
+            set_error_handler(array($this, 'errorHandler'));
+            $this->smtp_conn = stream_socket_client(
                 $host . ":" . $port,
                 $errno,
                 $errstr,
@@ -281,12 +292,14 @@ class SMTP
                 STREAM_CLIENT_CONNECT,
                 $socket_context
             );
+            restore_error_handler();
         } else {
             //Fall back to fsockopen which should work in more places, but is missing some features
             $this->edebug(
                 "Connection: stream_socket_client not available, falling back to fsockopen",
                 self::DEBUG_CONNECTION
             );
+            set_error_handler(array($this, 'errorHandler'));
             $this->smtp_conn = fsockopen(
                 $host,
                 $port,
@@ -294,6 +307,7 @@ class SMTP
                 $errstr,
                 $timeout
             );
+            restore_error_handler();
         }
         // Verify we connected properly
         if (!is_resource($this->smtp_conn)) {
@@ -336,11 +350,22 @@ class SMTP
         if (!$this->sendCommand('STARTTLS', 'STARTTLS', 220)) {
             return false;
         }
+
+        //Allow the best TLS version(s) we can
+        $crypto_method = STREAM_CRYPTO_METHOD_TLS_CLIENT;
+
+        //PHP 5.6.7 dropped inclusion of TLS 1.1 and 1.2 in STREAM_CRYPTO_METHOD_TLS_CLIENT
+        //so add them back in manually if we can
+        if (defined('STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT')) {
+            $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT;
+            $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT;
+        }
+
         // Begin encrypted connection
         if (!stream_socket_enable_crypto(
             $this->smtp_conn,
             true,
-            STREAM_CRYPTO_METHOD_TLS_CLIENT
+            $crypto_method
         )) {
             return false;
         }
@@ -353,7 +378,7 @@ class SMTP
      * @see hello()
      * @param string $username The user name
      * @param string $password The password
-     * @param string $authtype The auth type (PLAIN, LOGIN, NTLM, CRAM-MD5, XOAUTH2)
+     * @param string $authtype The auth type (PLAIN, LOGIN, CRAM-MD5)
      * @param string $realm The auth realm for NTLM
      * @param string $workstation The auth workstation for NTLM
      * @param null|OAuth $OAuth An optional OAuth instance (@see PHPMailerOAuth)
@@ -389,7 +414,7 @@ class SMTP
             );
 
             if (empty($authtype)) {
-                foreach (array('LOGIN', 'CRAM-MD5', 'PLAIN') as $method) {
+                foreach (array('CRAM-MD5', 'LOGIN', 'PLAIN') as $method) {
                     if (in_array($method, $this->server_caps['AUTH'])) {
                         $authtype = $method;
                         break;
@@ -673,7 +698,7 @@ class SMTP
     protected function parseHelloFields($type)
     {
         $this->server_caps = array();
-        $lines = explode("\n", $this->last_reply);
+        $lines = explode("\n", $this->helo_rply);
 
         foreach ($lines as $n => $s) {
             //First 4 chars contain response code followed by - or space
@@ -1115,4 +1140,47 @@ class SMTP
     {
         return $this->Timeout;
     }
+
+    /**
+     * Reports an error number and string.
+     * @param integer $errno The error number returned by PHP.
+     * @param string $errmsg The error message returned by PHP.
+     */
+    protected function errorHandler($errno, $errmsg)
+    {
+        $notice = 'Connection: Failed to connect to server.';
+        $this->setError(
+            $notice,
+            $errno,
+            $errmsg
+        );
+        $this->edebug(
+            $notice . ' Error number ' . $errno . '. "Error notice: ' . $errmsg,
+            self::DEBUG_CONNECTION
+        );
+    }
+
+       /**
+        * Will return the ID of the last smtp transaction based on a list of patterns provided
+        * in SMTP::$smtp_transaction_id_patterns.
+        * If no reply has been received yet, it will return null.
+        * If no pattern has been matched, it will return false.
+        * @return bool|null|string
+        */
+       public function getLastTransactionID()
+       {
+               $reply = $this->getLastReply();
+
+               if (empty($reply)) {
+                       return null;
+               }
+
+               foreach($this->smtp_transaction_id_patterns as $smtp_transaction_id_pattern) {
+                       if(preg_match($smtp_transaction_id_pattern, $reply, $matches)) {
+                               return $matches[1];
+                       }
+               }
+
+               return false;
+    }
 }
index 40af39df46575534b5d88bc37013f8c645ba8fcb..35c5650339e687c7b5f3a74619d7da9c44b08f19 100644 (file)
@@ -720,8 +720,9 @@ final class WP_Theme implements ArrayAccess {
        private function markup_header( $header, $value, $translate ) {
                switch ( $header ) {
                        case 'Name' :
-                               if ( empty( $value ) )
-                                       $value = $this->get_stylesheet();
+                               if ( empty( $value ) ) {
+                                       $value = esc_html( $this->get_stylesheet() );
+                               }
                                break;
                        case 'Description' :
                                $value = wptexturize( $value );
index ff09f3459d3bdf150462f8194727046ace99bee7..e3c9294909dced48a27dda773e5ef4af0af15966 100644 (file)
@@ -2234,7 +2234,7 @@ function wp_check_filetype( $filename, $mimes = null ) {
  * If it's determined that the extension does not match the file's real type,
  * then the "proper_filename" value will be set with a proper filename and extension.
  *
- * Currently this function only supports validating images known to getimagesize().
+ * Currently this function only supports renaming images validated via wp_get_image_mime().
  *
  * @since 3.0.0
  *
@@ -2258,14 +2258,15 @@ function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) {
                return compact( 'ext', 'type', 'proper_filename' );
        }
 
-       // We're able to validate images using GD
-       if ( $type && 0 === strpos( $type, 'image/' ) && function_exists('getimagesize') ) {
+       // Validate image types.
+       if ( $type && 0 === strpos( $type, 'image/' ) ) {
 
                // Attempt to figure out what type of image it actually is
-               $imgstats = @getimagesize( $file );
+               $real_mime = wp_get_image_mime( $file );
 
-               // If getimagesize() knows what kind of image it really is and if the real MIME doesn't match the claimed MIME
-               if ( !empty($imgstats['mime']) && $imgstats['mime'] != $type ) {
+               if ( ! $real_mime ) {
+                       $type = $ext = false;
+               } elseif ( $real_mime != $type ) {
                        /**
                         * Filters the list mapping image mime types to their respective extensions.
                         *
@@ -2282,10 +2283,10 @@ function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) {
                        ) );
 
                        // Replace whatever is after the last period in the filename with the correct extension
-                       if ( ! empty( $mime_to_ext[ $imgstats['mime'] ] ) ) {
+                       if ( ! empty( $mime_to_ext[ $real_mime ] ) ) {
                                $filename_parts = explode( '.', $filename );
                                array_pop( $filename_parts );
-                               $filename_parts[] = $mime_to_ext[ $imgstats['mime'] ];
+                               $filename_parts[] = $mime_to_ext[ $real_mime ];
                                $new_filename = implode( '.', $filename_parts );
 
                                if ( $new_filename != $filename ) {
@@ -2295,8 +2296,20 @@ function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) {
                                $wp_filetype = wp_check_filetype( $new_filename, $mimes );
                                $ext = $wp_filetype['ext'];
                                $type = $wp_filetype['type'];
+                       } else {
+                               $type = $ext = false;
                        }
                }
+       } elseif ( function_exists( 'finfo_file' ) ) {
+               // Use finfo_file if available to validate non-image files.
+               $finfo = finfo_open( FILEINFO_MIME_TYPE );
+               $real_mime = finfo_file( $finfo, $file );
+               finfo_close( $finfo );
+
+               // If the extension does not match the file's real type, return false.
+               if ( $real_mime !== $type ) {
+                       $type = $ext = false;
+               }
        }
 
        /**
@@ -2314,6 +2327,38 @@ function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) {
        return apply_filters( 'wp_check_filetype_and_ext', compact( 'ext', 'type', 'proper_filename' ), $file, $filename, $mimes );
 }
 
+/**
+ * Returns the real mime type of an image file.
+ *
+ * This depends on exif_imagetype() or getimagesize() to determine real mime types.
+ *
+ * @since 4.7.1
+ *
+ * @param string $file Full path to the file.
+ * @return string|false The actual mime type or false if the type cannot be determined.
+ */
+function wp_get_image_mime( $file ) {
+       /*
+        * Use exif_imagetype() to check the mimetype if available or fall back to
+        * getimagesize() if exif isn't avaialbe. If either function throws an Exception
+        * we assume the file could not be validated.
+        */
+       try {
+               if ( is_callable( 'exif_imagetype' ) ) {
+                       $mime = image_type_to_mime_type( exif_imagetype( $file ) );
+               } elseif ( function_exists( 'getimagesize' ) ) {
+                       $imagesize = getimagesize( $file );
+                       $mime = ( isset( $imagesize['mime'] ) ) ? $imagesize['mime'] : false;
+               } else {
+                       $mime = false;
+               }
+       } catch ( Exception $e ) {
+               $mime = false;
+       }
+
+       return $mime;
+}
+
 /**
  * Retrieve list of mime types and file extensions.
  *
index a253a61dac97f1ccd9b6020e217e9e64d67d0496..3f5ee2c92a88482febebfbc23dbc61b5651de45d 100644 (file)
@@ -669,7 +669,7 @@ function wpmu_validate_blog_signup( $blogname, $blog_title, $user = '' ) {
 function wpmu_signup_blog( $domain, $path, $title, $user, $user_email, $meta = array() )  {
        global $wpdb;
 
-       $key = substr( md5( time() . rand() . $domain ), 0, 16 );
+       $key = substr( md5( time() . wp_rand() . $domain ), 0, 16 );
        $meta = serialize($meta);
 
        $wpdb->insert( $wpdb->signups, array(
@@ -719,7 +719,7 @@ function wpmu_signup_user( $user, $user_email, $meta = array() ) {
        // Format data
        $user = preg_replace( '/\s+/', '', sanitize_user( $user, true ) );
        $user_email = sanitize_email( $user_email );
-       $key = substr( md5( time() . rand() . $user_email ), 0, 16 );
+       $key = substr( md5( time() . wp_rand() . $user_email ), 0, 16 );
        $meta = serialize($meta);
 
        $wpdb->insert( $wpdb->signups, array(
index 1517156c5d0b21435e691a44f5d7769c0ea8917a..8c11d3ea4b556ee250085532b80f51f06a9bc2d2 100644 (file)
@@ -4,7 +4,7 @@
  *
  * @global string $wp_version
  */
-$wp_version = '4.6.1';
+$wp_version = '4.6.2';
 
 /**
  * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
index 8ebee4c40e2042a5b279e24a0fd03d40fad06a3a..8057bcc04e7aa2df533283ea471d02491da19faf 100644 (file)
@@ -779,6 +779,11 @@ class wpdb {
                        $charset = 'utf8mb4';
                }
 
+               if ( 'utf8mb4' === $charset && ! $this->has_cap( 'utf8mb4' ) ) {
+                       $charset = 'utf8';
+                       $collate = str_replace( 'utf8mb4_', 'utf8_', $collate );
+               }
+
                if ( 'utf8mb4' === $charset ) {
                        // _general_ is outdated, so we can upgrade it to _unicode_, instead.
                        if ( ! $collate || 'utf8_general_ci' === $collate ) {
index 62c9a119033a996f87b018cd4f75e9552145b8ac..b5af05abf9300f24a80781c4fc2e12a161a8c7ee 100644 (file)
@@ -14,6 +14,12 @@ require(dirname(__FILE__) . '/wp-load.php');
 if ( ! apply_filters( 'enable_post_by_email_configuration', true ) )
        wp_die( __( 'This action has been disabled by the administrator.' ) );
 
+$mailserver_url = get_option( 'mailserver_url' );
+
+if ( 'mail.example.com' === $mailserver_url || empty( $mailserver_url ) ) {
+       wp_die( __( 'This action has been disabled by the administrator.' ), 403 );
+}
+
 /**
  * Fires to allow a plugin to do a complete takeover of Post by Email.
  *