Ticket #37210: 37210.diff
File 37210.diff, 22.1 KB (added by , 9 years ago) |
---|
-
src/wp-includes/class-phpmailer.php
31 31 * The PHPMailer Version number. 32 32 * @var string 33 33 */ 34 public $Version = '5.2.1 4';34 public $Version = '5.2.16'; 35 35 36 36 /** 37 37 * Email priority. … … 285 285 286 286 /** 287 287 * SMTP auth type. 288 * Options are LOGIN (default), PLAIN, NTLM, CRAM-MD5288 * Options are CRAM-MD5, LOGIN, PLAIN, NTLM, XOAUTH2, attempted in that order if not specified 289 289 * @var string 290 290 */ 291 291 public $AuthType = ''; … … 352 352 /** 353 353 * Whether to split multiple to addresses into multiple messages 354 354 * or send them all in one message. 355 * Only supported in `mail` and `sendmail` transports, not in SMTP. 355 356 * @var boolean 356 357 */ 357 358 public $SingleTo = false; … … 394 395 395 396 /** 396 397 * DKIM Identity. 397 * Usually the email address used as the source of the email 398 * Usually the email address used as the source of the email. 398 399 * @var string 399 400 */ 400 401 public $DKIM_identity = ''; … … 447 448 public $XMailer = ''; 448 449 449 450 /** 451 * Which validator to use by default when validating email addresses. 452 * May be a callable to inject your own validator, but there are several built-in validators. 453 * @see PHPMailer::validateAddress() 454 * @var string|callable 455 * @static 456 */ 457 public static $validator = 'auto'; 458 459 /** 450 460 * An instance of the SMTP sender class. 451 461 * @var SMTP 452 462 * @access protected … … 634 644 * Constructor. 635 645 * @param boolean $exceptions Should we throw external exceptions? 636 646 */ 637 public function __construct($exceptions = false)647 public function __construct($exceptions = null) 638 648 { 639 $this->exceptions = (boolean)$exceptions; 649 if ($exceptions !== null) { 650 $this->exceptions = (boolean)$exceptions; 651 } 640 652 } 641 653 642 654 /** … … 645 657 public function __destruct() 646 658 { 647 659 //Close any open SMTP connection nicely 648 if ($this->Mailer == 'smtp') { 649 $this->smtpClose(); 650 } 660 $this->smtpClose(); 651 661 } 652 662 653 663 /** … … 671 681 } else { 672 682 $subject = $this->encodeHeader($this->secureHeader($subject)); 673 683 } 674 if (ini_get('safe_mode') || !($this->UseSendmailOptions)) { 684 //Can't use additional_parameters in safe_mode 685 //@link http://php.net/manual/en/function.mail.php 686 if (ini_get('safe_mode') or !$this->UseSendmailOptions) { 675 687 $result = @mail($to, $subject, $body, $header); 676 688 } else { 677 689 $result = @mail($to, $subject, $body, $header, $params); … … 713 725 case 'echo': 714 726 default: 715 727 //Normalize line breaks 716 $str = preg_replace('/ (\r\n|\r|\n)/ms', "\n", $str);728 $str = preg_replace('/\r\n?/ms', "\n", $str); 717 729 echo gmdate('Y-m-d H:i:s') . "\t" . str_replace( 718 730 "\n", 719 731 "\n \t ", … … 850 862 $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim 851 863 if (($pos = strrpos($address, '@')) === false) { 852 864 // At-sign is misssing. 853 $error_message = $this->lang('invalid_address') . $address;865 $error_message = $this->lang('invalid_address') . " (addAnAddress $kind): $address"; 854 866 $this->setError($error_message); 855 867 $this->edebug($error_message); 856 868 if ($this->exceptions) { … … 900 912 return false; 901 913 } 902 914 if (!$this->validateAddress($address)) { 903 $error_message = $this->lang('invalid_address') . $address;915 $error_message = $this->lang('invalid_address') . " (addAnAddress $kind): $address"; 904 916 $this->setError($error_message); 905 917 $this->edebug($error_message); 906 918 if ($this->exceptions) { … … 924 936 } 925 937 926 938 /** 939 * Parse and validate a string containing one or more RFC822-style comma-separated email addresses 940 * of the form "display name <address>" into an array of name/address pairs. 941 * Uses the imap_rfc822_parse_adrlist function if the IMAP extension is available. 942 * Note that quotes in the name part are removed. 943 * @param string $addrstr The address list string 944 * @param bool $useimap Whether to use the IMAP extension to parse the list 945 * @return array 946 * @link http://www.andrew.cmu.edu/user/agreen1/testing/mrbs/web/Mail/RFC822.php A more careful implementation 947 */ 948 public function parseAddresses($addrstr, $useimap = true) 949 { 950 $addresses = array(); 951 if ($useimap and function_exists('imap_rfc822_parse_adrlist')) { 952 //Use this built-in parser if it's available 953 $list = imap_rfc822_parse_adrlist($addrstr, ''); 954 foreach ($list as $address) { 955 if ($address->host != '.SYNTAX-ERROR.') { 956 if ($this->validateAddress($address->mailbox . '@' . $address->host)) { 957 $addresses[] = array( 958 'name' => (property_exists($address, 'personal') ? $address->personal : ''), 959 'address' => $address->mailbox . '@' . $address->host 960 ); 961 } 962 } 963 } 964 } else { 965 //Use this simpler parser 966 $list = explode(',', $addrstr); 967 foreach ($list as $address) { 968 $address = trim($address); 969 //Is there a separate name part? 970 if (strpos($address, '<') === false) { 971 //No separate name, just use the whole thing 972 if ($this->validateAddress($address)) { 973 $addresses[] = array( 974 'name' => '', 975 'address' => $address 976 ); 977 } 978 } else { 979 list($name, $email) = explode('<', $address); 980 $email = trim(str_replace('>', '', $email)); 981 if ($this->validateAddress($email)) { 982 $addresses[] = array( 983 'name' => trim(str_replace(array('"', "'"), '', $name)), 984 'address' => $email 985 ); 986 } 987 } 988 } 989 } 990 return $addresses; 991 } 992 993 /** 927 994 * Set the From and FromName properties. 928 995 * @param string $address 929 996 * @param string $name … … 939 1006 if (($pos = strrpos($address, '@')) === false or 940 1007 (!$this->has8bitChars(substr($address, ++$pos)) or !$this->idnSupported()) and 941 1008 !$this->validateAddress($address)) { 942 $error_message = $this->lang('invalid_address') . $address;1009 $error_message = $this->lang('invalid_address') . " (setFrom) $address"; 943 1010 $this->setError($error_message); 944 1011 $this->edebug($error_message); 945 1012 if ($this->exceptions) { … … 972 1039 /** 973 1040 * Check that a string looks like an email address. 974 1041 * @param string $address The email address to check 975 * @param string $patternselect A selector for the validation pattern to use :1042 * @param string|callable $patternselect A selector for the validation pattern to use : 976 1043 * * `auto` Pick best pattern automatically; 977 1044 * * `pcre8` Use the squiloople.com pattern, requires PCRE > 8.0, PHP >= 5.3.2, 5.2.14; 978 1045 * * `pcre` Use old PCRE implementation; … … 979 1046 * * `php` Use PHP built-in FILTER_VALIDATE_EMAIL; 980 1047 * * `html5` Use the pattern given by the HTML5 spec for 'email' type form input elements. 981 1048 * * `noregex` Don't use a regex: super fast, really dumb. 1049 * Alternatively you may pass in a callable to inject your own validator, for example: 1050 * PHPMailer::validateAddress('user@example.com', function($address) { 1051 * return (strpos($address, '@') !== false); 1052 * }); 1053 * You can also set the PHPMailer::$validator static to a callable, allowing built-in methods to use your validator. 982 1054 * @return boolean 983 1055 * @static 984 1056 * @access public 985 1057 */ 986 public static function validateAddress($address, $patternselect = 'auto')1058 public static function validateAddress($address, $patternselect = null) 987 1059 { 1060 if (is_null($patternselect)) { 1061 $patternselect = self::$validator; 1062 } 1063 if (is_callable($patternselect)) { 1064 return call_user_func($patternselect, $address); 1065 } 988 1066 //Reject line breaks in addresses; it's valid RFC5322, but not RFC5321 989 1067 if (strpos($address, "\n") !== false or strpos($address, "\r") !== false) { 990 1068 return false; … … 1161 1239 } 1162 1240 $this->$address_kind = $this->punyencodeAddress($this->$address_kind); 1163 1241 if (!$this->validateAddress($this->$address_kind)) { 1164 $error_message = $this->lang('invalid_address') . $this->$address_kind;1242 $error_message = $this->lang('invalid_address') . ' (punyEncode) ' . $this->$address_kind; 1165 1243 $this->setError($error_message); 1166 1244 $this->edebug($error_message); 1167 1245 if ($this->exceptions) { … … 1172 1250 } 1173 1251 1174 1252 // Set whether the message is multipart/alternative 1175 if ( !empty($this->AltBody)) {1253 if ($this->alternativeExists()) { 1176 1254 $this->ContentType = 'multipart/alternative'; 1177 1255 } 1178 1256 … … 1349 1427 } 1350 1428 $to = implode(', ', $toArr); 1351 1429 1352 if (empty($this->Sender)) {1353 $params = ' ';1354 } else{1430 $params = null; 1431 //This sets the SMTP envelope sender which gets turned into a return-path header by the receiver 1432 if (!empty($this->Sender)) { 1355 1433 $params = sprintf('-f%s', $this->Sender); 1356 1434 } 1357 1435 if ($this->Sender != '' and !ini_get('safe_mode')) { … … 1359 1437 ini_set('sendmail_from', $this->Sender); 1360 1438 } 1361 1439 $result = false; 1362 if ($this->SingleTo &&count($toArr) > 1) {1440 if ($this->SingleTo and count($toArr) > 1) { 1363 1441 foreach ($toArr as $toAddr) { 1364 1442 $result = $this->mailPassthru($toAddr, $this->Subject, $body, $header, $params); 1365 1443 $this->doCallback($result, array($toAddr), $this->cc, $this->bcc, $this->Subject, $body, $this->From); … … 1466 1544 * @throws phpmailerException 1467 1545 * @return boolean 1468 1546 */ 1469 public function smtpConnect($options = array())1547 public function smtpConnect($options = null) 1470 1548 { 1471 1549 if (is_null($this->smtp)) { 1472 1550 $this->smtp = $this->getSMTPInstance(); 1473 1551 } 1474 1552 1553 //If no options are provided, use whatever is set in the instance 1554 if (is_null($options)) { 1555 $options = $this->SMTPOptions; 1556 } 1557 1475 1558 // Already connected? 1476 1559 if ($this->smtp->connected()) { 1477 1560 return true; … … 1541 1624 if (!$this->smtp->startTLS()) { 1542 1625 throw new phpmailerException($this->lang('connect_host')); 1543 1626 } 1544 // We must resend HELO after tlsnegotiation1627 // We must resend EHLO after TLS negotiation 1545 1628 $this->smtp->hello($hello); 1546 1629 } 1547 1630 if ($this->SMTPAuth) { … … 1580 1663 */ 1581 1664 public function smtpClose() 1582 1665 { 1583 if ( $this->smtp !== null) {1666 if (is_a($this->smtp, 'SMTP')) { 1584 1667 if ($this->smtp->connected()) { 1585 1668 $this->smtp->quit(); 1586 1669 $this->smtp->close(); … … 1918 2001 $result .= $this->headerLine('Subject', $this->encodeHeader($this->secureHeader($this->Subject))); 1919 2002 } 1920 2003 1921 if ( $this->MessageID != '') {2004 if ('' != $this->MessageID and preg_match('/^<.*@.*>$/', $this->MessageID)) { 1922 2005 $this->lastMessageID = $this->MessageID; 1923 2006 } else { 1924 2007 $this->lastMessageID = sprintf('<%s@%s>', $this->uniqueid, $this->serverHostname()); … … 2020 2103 */ 2021 2104 public function getSentMIMEMessage() 2022 2105 { 2023 return $this->MIMEHeader . $this->mailHeader. self::CRLF . $this->MIMEBody;2106 return rtrim($this->MIMEHeader . $this->mailHeader, "\n\r") . self::CRLF . self::CRLF . $this->MIMEBody; 2024 2107 } 2025 2108 2026 2109 /** … … 2050 2133 //Can we do a 7-bit downgrade? 2051 2134 if ($bodyEncoding == '8bit' and !$this->has8bitChars($this->Body)) { 2052 2135 $bodyEncoding = '7bit'; 2136 //All ISO 8859, Windows codepage and UTF-8 charsets are ascii compatible up to 7-bit 2053 2137 $bodyCharSet = 'us-ascii'; 2054 2138 } 2055 //If lines are too long, change to quoted-printable transfer encoding2056 if (self::hasLineLongerThanMax($this->Body)) {2057 $this->Encoding = 'quoted-printable';2139 //If lines are too long, and we're not already using an encoding that will shorten them, 2140 //change to quoted-printable transfer encoding for the body part only 2141 if ('base64' != $this->Encoding and self::hasLineLongerThanMax($this->Body)) { 2058 2142 $bodyEncoding = 'quoted-printable'; 2059 2143 } 2060 2144 … … 2063 2147 //Can we do a 7-bit downgrade? 2064 2148 if ($altBodyEncoding == '8bit' and !$this->has8bitChars($this->AltBody)) { 2065 2149 $altBodyEncoding = '7bit'; 2150 //All ISO 8859, Windows codepage and UTF-8 charsets are ascii compatible up to 7-bit 2066 2151 $altBodyCharSet = 'us-ascii'; 2067 2152 } 2068 //If lines are too long, change to quoted-printable transfer encoding 2069 if (self::hasLineLongerThanMax($this->AltBody)) { 2153 //If lines are too long, and we're not already using an encoding that will shorten them, 2154 //change to quoted-printable transfer encoding for the alt body part only 2155 if ('base64' != $altBodyEncoding and self::hasLineLongerThanMax($this->AltBody)) { 2070 2156 $altBodyEncoding = 'quoted-printable'; 2071 2157 } 2072 2158 //Use this as a preamble in all multipart message types … … 2169 2255 $body .= $this->attachAll('attachment', $this->boundary[1]); 2170 2256 break; 2171 2257 default: 2172 // catch case 'plain' and case '' 2173 $body .= $this->encodeString($this->Body, $bodyEncoding); 2258 // Catch case 'plain' and case '', applies to simple `text/plain` and `text/html` body content types 2259 //Reset the `Encoding` property in case we changed it for line length reasons 2260 $this->Encoding = $bodyEncoding; 2261 $body .= $this->encodeString($this->Body, $this->Encoding); 2174 2262 break; 2175 2263 } 2176 2264 … … 2276 2364 2277 2365 /** 2278 2366 * Set the message type. 2279 * PHPMailer only supports some preset message types, 2280 * not arbitrary MIME structures. 2367 * PHPMailer only supports some preset message types, not arbitrary MIME structures. 2281 2368 * @access protected 2282 2369 * @return void 2283 2370 */ … … 2295 2382 } 2296 2383 $this->message_type = implode('_', $type); 2297 2384 if ($this->message_type == '') { 2385 //The 'plain' message_type refers to the message having a single body element, not that it is plain-text 2298 2386 $this->message_type = 'plain'; 2299 2387 } 2300 2388 } … … 3241 3329 $message 3242 3330 ); 3243 3331 } 3244 } elseif (substr($url, 0, 4) !== 'cid:' && !preg_match('#^[ A-z]+://#', $url)) {3332 } elseif (substr($url, 0, 4) !== 'cid:' && !preg_match('#^[a-z][a-z0-9+.-]*://#i', $url)) { 3245 3333 // Do not change urls for absolute images (thanks to corvuscorax) 3246 3334 // Do not change urls that are already inline images 3247 3335 $filename = basename($url); … … 3277 3365 // Convert all message body line breaks to CRLF, makes quoted-printable encoding work much better 3278 3366 $this->Body = $this->normalizeBreaks($message); 3279 3367 $this->AltBody = $this->normalizeBreaks($this->html2text($message, $advanced)); 3280 if ( empty($this->AltBody)) {3368 if (!$this->alternativeExists()) { 3281 3369 $this->AltBody = 'To view this email message, open it in a program that understands HTML!' . 3282 3370 self::CRLF . self::CRLF; 3283 3371 } … … 3602 3690 if ($this->DKIM_passphrase != '') { 3603 3691 $privKey = openssl_pkey_get_private($privKeyStr, $this->DKIM_passphrase); 3604 3692 } else { 3605 $privKey = $privKeyStr;3693 $privKey = openssl_pkey_get_private($privKeyStr); 3606 3694 } 3607 if (openssl_sign($signHeader, $signature, $privKey)) { 3695 if (openssl_sign($signHeader, $signature, $privKey, 'sha256WithRSAEncryption')) { //sha1WithRSAEncryption 3696 openssl_pkey_free($privKey); 3608 3697 return base64_encode($signature); 3609 3698 } 3699 openssl_pkey_free($privKey); 3610 3700 return ''; 3611 3701 } 3612 3702 … … 3623 3713 foreach ($lines as $key => $line) { 3624 3714 list($heading, $value) = explode(':', $line, 2); 3625 3715 $heading = strtolower($heading); 3626 $value = preg_replace('/\s +/', ' ', $value); // Compress useless spaces3716 $value = preg_replace('/\s{2,}/', ' ', $value); // Compress useless spaces 3627 3717 $lines[$key] = $heading . ':' . trim($value); // Don't forget to remove WSP around the value 3628 3718 } 3629 3719 $signHeader = implode("\r\n", $lines); … … 3661 3751 */ 3662 3752 public function DKIM_Add($headers_line, $subject, $body) 3663 3753 { 3664 $DKIMsignatureType = 'rsa-sha 1'; // Signature & hash algorithms3754 $DKIMsignatureType = 'rsa-sha256'; // Signature & hash algorithms 3665 3755 $DKIMcanonicalization = 'relaxed/simple'; // Canonicalization of header/body 3666 3756 $DKIMquery = 'dns/txt'; // Query method 3667 3757 $DKIMtime = time(); // Signature Timestamp = seconds since 00:00:00 - Jan 1, 1970 (UTC time zone) … … 3669 3759 $headers = explode($this->LE, $headers_line); 3670 3760 $from_header = ''; 3671 3761 $to_header = ''; 3762 $date_header = ''; 3672 3763 $current = ''; 3673 3764 foreach ($headers as $header) { 3674 3765 if (strpos($header, 'From:') === 0) { … … 3677 3768 } elseif (strpos($header, 'To:') === 0) { 3678 3769 $to_header = $header; 3679 3770 $current = 'to_header'; 3771 } elseif (strpos($header, 'Date:') === 0) { 3772 $date_header = $header; 3773 $current = 'date_header'; 3680 3774 } else { 3681 3775 if (!empty($$current) && strpos($header, ' =?') === 0) { 3682 3776 $$current .= $header; … … 3687 3781 } 3688 3782 $from = str_replace('|', '=7C', $this->DKIM_QP($from_header)); 3689 3783 $to = str_replace('|', '=7C', $this->DKIM_QP($to_header)); 3784 $date = str_replace('|', '=7C', $this->DKIM_QP($date_header)); 3690 3785 $subject = str_replace( 3691 3786 '|', 3692 3787 '=7C', … … 3694 3789 ); // Copied header fields (dkim-quoted-printable) 3695 3790 $body = $this->DKIM_BodyC($body); 3696 3791 $DKIMlen = strlen($body); // Length of body 3697 $DKIMb64 = base64_encode(pack('H*', sha1($body))); // Base64 of packed binary SHA-1hash of body3792 $DKIMb64 = base64_encode(pack('H*', hash('sha256', $body))); // Base64 of packed binary SHA-256 hash of body 3698 3793 if ('' == $this->DKIM_identity) { 3699 3794 $ident = ''; 3700 3795 } else { … … 3707 3802 $this->DKIM_selector . 3708 3803 ";\r\n" . 3709 3804 "\tt=" . $DKIMtime . '; c=' . $DKIMcanonicalization . ";\r\n" . 3710 "\th=From:To: Subject;\r\n" .3805 "\th=From:To:Date:Subject;\r\n" . 3711 3806 "\td=" . $this->DKIM_domain . ';' . $ident . "\r\n" . 3712 3807 "\tz=$from\r\n" . 3713 3808 "\t|$to\r\n" . 3809 "\t|$date\r\n" . 3714 3810 "\t|$subject;\r\n" . 3715 3811 "\tbh=" . $DKIMb64 . ";\r\n" . 3716 3812 "\tb="; … … 3717 3813 $toSign = $this->DKIM_HeaderC( 3718 3814 $from_header . "\r\n" . 3719 3815 $to_header . "\r\n" . 3816 $date_header . "\r\n" . 3720 3817 $subject_header . "\r\n" . 3721 3818 $dkimhdrs 3722 3819 ); -
src/wp-includes/class-smtp.php
30 30 * The PHPMailer SMTP version number. 31 31 * @var string 32 32 */ 33 const VERSION = '5.2.1 4';33 const VERSION = '5.2.16'; 34 34 35 35 /** 36 36 * SMTP line break constant. … … 81 81 * @deprecated Use the `VERSION` constant instead 82 82 * @see SMTP::VERSION 83 83 */ 84 public $Version = '5.2.1 4';84 public $Version = '5.2.16'; 85 85 86 86 /** 87 87 * SMTP server port number. … … 336 336 if (!$this->sendCommand('STARTTLS', 'STARTTLS', 220)) { 337 337 return false; 338 338 } 339 340 //Allow the best TLS version(s) we can 341 $crypto_method = STREAM_CRYPTO_METHOD_TLS_CLIENT; 342 343 //PHP 5.6.7 dropped inclusion of TLS 1.1 and 1.2 in STREAM_CRYPTO_METHOD_TLS_CLIENT 344 //so add them back in manually if we can 345 if (defined('STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT')) { 346 $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT; 347 $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT; 348 } 349 339 350 // Begin encrypted connection 340 351 if (!stream_socket_enable_crypto( 341 352 $this->smtp_conn, 342 353 true, 343 STREAM_CRYPTO_METHOD_TLS_CLIENT354 $crypto_method 344 355 )) { 345 356 return false; 346 357 } … … 673 684 protected function parseHelloFields($type) 674 685 { 675 686 $this->server_caps = array(); 676 $lines = explode("\n", $this-> last_reply);687 $lines = explode("\n", $this->helo_rply); 677 688 678 689 foreach ($lines as $n => $s) { 679 690 //First 4 chars contain response code followed by - or space