Changeset 39646
- Timestamp:
- 12/29/2016 02:59:24 AM (8 years ago)
- Location:
- branches/4.7
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/4.7
-
branches/4.7/src/wp-includes/class-phpmailer.php
r38470 r39646 32 32 * @var string 33 33 */ 34 public $Version = '5.2. 14';34 public $Version = '5.2.21'; 35 35 36 36 /** … … 202 202 * An ID to be used in the Message-ID header. 203 203 * If empty, a unique id will be generated. 204 * You can set your own, but it must be in the format "<id@domain>", 205 * as defined in RFC5322 section 3.6.4 or it will be ignored. 206 * @see https://tools.ietf.org/html/rfc5322#section-3.6.4 204 207 * @var string 205 208 */ … … 286 289 /** 287 290 * SMTP auth type. 288 * Options are LOGIN (default), PLAIN, NTLM, CRAM-MD5291 * Options are CRAM-MD5, LOGIN, PLAIN, attempted in that order if not specified 289 292 * @var string 290 293 */ … … 353 356 * Whether to split multiple to addresses into multiple messages 354 357 * or send them all in one message. 358 * Only supported in `mail` and `sendmail` transports, not in SMTP. 355 359 * @var boolean 356 360 */ … … 395 399 /** 396 400 * DKIM Identity. 397 * Usually the email address used as the source of the email 401 * Usually the email address used as the source of the email. 398 402 * @var string 399 403 */ … … 419 423 */ 420 424 public $DKIM_private = ''; 425 426 /** 427 * DKIM private key string. 428 * If set, takes precedence over `$DKIM_private`. 429 * @var string 430 */ 431 public $DKIM_private_string = ''; 421 432 422 433 /** … … 448 459 449 460 /** 461 * Which validator to use by default when validating email addresses. 462 * May be a callable to inject your own validator, but there are several built-in validators. 463 * @see PHPMailer::validateAddress() 464 * @var string|callable 465 * @static 466 */ 467 public static $validator = 'auto'; 468 469 /** 450 470 * An instance of the SMTP sender class. 451 471 * @var SMTP … … 635 655 * @param boolean $exceptions Should we throw external exceptions? 636 656 */ 637 public function __construct($exceptions = false) 638 { 639 $this->exceptions = (boolean)$exceptions; 657 public function __construct($exceptions = null) 658 { 659 if ($exceptions !== null) { 660 $this->exceptions = (boolean)$exceptions; 661 } 640 662 } 641 663 … … 646 668 { 647 669 //Close any open SMTP connection nicely 648 if ($this->Mailer == 'smtp') { 649 $this->smtpClose(); 650 } 670 $this->smtpClose(); 651 671 } 652 672 … … 672 692 $subject = $this->encodeHeader($this->secureHeader($subject)); 673 693 } 674 if (ini_get('safe_mode') || !($this->UseSendmailOptions)) { 694 695 //Can't use additional_parameters in safe_mode, calling mail() with null params breaks 696 //@link http://php.net/manual/en/function.mail.php 697 if (ini_get('safe_mode') or !$this->UseSendmailOptions or is_null($params)) { 675 698 $result = @mail($to, $subject, $body, $header); 676 699 } else { … … 679 702 return $result; 680 703 } 681 682 704 /** 683 705 * Output debugging info via user-defined method. … … 714 736 default: 715 737 //Normalize line breaks 716 $str = preg_replace('/ (\r\n|\r|\n)/ms', "\n", $str);738 $str = preg_replace('/\r\n?/ms', "\n", $str); 717 739 echo gmdate('Y-m-d H:i:s') . "\t" . str_replace( 718 740 "\n", … … 851 873 if (($pos = strrpos($address, '@')) === false) { 852 874 // At-sign is misssing. 853 $error_message = $this->lang('invalid_address') . $address;875 $error_message = $this->lang('invalid_address') . " (addAnAddress $kind): $address"; 854 876 $this->setError($error_message); 855 877 $this->edebug($error_message); … … 901 923 } 902 924 if (!$this->validateAddress($address)) { 903 $error_message = $this->lang('invalid_address') . $address;925 $error_message = $this->lang('invalid_address') . " (addAnAddress $kind): $address"; 904 926 $this->setError($error_message); 905 927 $this->edebug($error_message); … … 922 944 } 923 945 return false; 946 } 947 948 /** 949 * Parse and validate a string containing one or more RFC822-style comma-separated email addresses 950 * of the form "display name <address>" into an array of name/address pairs. 951 * Uses the imap_rfc822_parse_adrlist function if the IMAP extension is available. 952 * Note that quotes in the name part are removed. 953 * @param string $addrstr The address list string 954 * @param bool $useimap Whether to use the IMAP extension to parse the list 955 * @return array 956 * @link http://www.andrew.cmu.edu/user/agreen1/testing/mrbs/web/Mail/RFC822.php A more careful implementation 957 */ 958 public function parseAddresses($addrstr, $useimap = true) 959 { 960 $addresses = array(); 961 if ($useimap and function_exists('imap_rfc822_parse_adrlist')) { 962 //Use this built-in parser if it's available 963 $list = imap_rfc822_parse_adrlist($addrstr, ''); 964 foreach ($list as $address) { 965 if ($address->host != '.SYNTAX-ERROR.') { 966 if ($this->validateAddress($address->mailbox . '@' . $address->host)) { 967 $addresses[] = array( 968 'name' => (property_exists($address, 'personal') ? $address->personal : ''), 969 'address' => $address->mailbox . '@' . $address->host 970 ); 971 } 972 } 973 } 974 } else { 975 //Use this simpler parser 976 $list = explode(',', $addrstr); 977 foreach ($list as $address) { 978 $address = trim($address); 979 //Is there a separate name part? 980 if (strpos($address, '<') === false) { 981 //No separate name, just use the whole thing 982 if ($this->validateAddress($address)) { 983 $addresses[] = array( 984 'name' => '', 985 'address' => $address 986 ); 987 } 988 } else { 989 list($name, $email) = explode('<', $address); 990 $email = trim(str_replace('>', '', $email)); 991 if ($this->validateAddress($email)) { 992 $addresses[] = array( 993 'name' => trim(str_replace(array('"', "'"), '', $name)), 994 'address' => $email 995 ); 996 } 997 } 998 } 999 } 1000 return $addresses; 924 1001 } 925 1002 … … 940 1017 (!$this->has8bitChars(substr($address, ++$pos)) or !$this->idnSupported()) and 941 1018 !$this->validateAddress($address)) { 942 $error_message = $this->lang('invalid_address') . $address;1019 $error_message = $this->lang('invalid_address') . " (setFrom) $address"; 943 1020 $this->setError($error_message); 944 1021 $this->edebug($error_message); … … 973 1050 * Check that a string looks like an email address. 974 1051 * @param string $address The email address to check 975 * @param string $patternselect A selector for the validation pattern to use :1052 * @param string|callable $patternselect A selector for the validation pattern to use : 976 1053 * * `auto` Pick best pattern automatically; 977 1054 * * `pcre8` Use the squiloople.com pattern, requires PCRE > 8.0, PHP >= 5.3.2, 5.2.14; … … 980 1057 * * `html5` Use the pattern given by the HTML5 spec for 'email' type form input elements. 981 1058 * * `noregex` Don't use a regex: super fast, really dumb. 1059 * Alternatively you may pass in a callable to inject your own validator, for example: 1060 * PHPMailer::validateAddress('user@example.com', function($address) { 1061 * return (strpos($address, '@') !== false); 1062 * }); 1063 * You can also set the PHPMailer::$validator static to a callable, allowing built-in methods to use your validator. 982 1064 * @return boolean 983 1065 * @static 984 1066 * @access public 985 1067 */ 986 public static function validateAddress($address, $patternselect = 'auto') 987 { 1068 public static function validateAddress($address, $patternselect = null) 1069 { 1070 if (is_null($patternselect)) { 1071 $patternselect = self::$validator; 1072 } 1073 if (is_callable($patternselect)) { 1074 return call_user_func($patternselect, $address); 1075 } 988 1076 //Reject line breaks in addresses; it's valid RFC5322, but not RFC5321 989 1077 if (strpos($address, "\n") !== false or strpos($address, "\r") !== false) { … … 1162 1250 $this->$address_kind = $this->punyencodeAddress($this->$address_kind); 1163 1251 if (!$this->validateAddress($this->$address_kind)) { 1164 $error_message = $this->lang('invalid_address') . $this->$address_kind;1252 $error_message = $this->lang('invalid_address') . ' (punyEncode) ' . $this->$address_kind; 1165 1253 $this->setError($error_message); 1166 1254 $this->edebug($error_message); … … 1173 1261 1174 1262 // Set whether the message is multipart/alternative 1175 if ( !empty($this->AltBody)) {1263 if ($this->alternativeExists()) { 1176 1264 $this->ContentType = 'multipart/alternative'; 1177 1265 } … … 1207 1295 // Sign with DKIM if enabled 1208 1296 if (!empty($this->DKIM_domain) 1209 && !empty($this->DKIM_private)1210 1297 && !empty($this->DKIM_selector) 1211 && file_exists($this->DKIM_private)) { 1298 && (!empty($this->DKIM_private_string) 1299 || (!empty($this->DKIM_private) && file_exists($this->DKIM_private)) 1300 ) 1301 ) { 1212 1302 $header_dkim = $this->DKIM_Add( 1213 1303 $this->MIMEHeader . $this->mailHeader, … … 1275 1365 protected function sendmailSend($header, $body) 1276 1366 { 1277 if ($this->Sender != '') { 1367 // CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped. 1368 if (!empty($this->Sender) and self::isShellSafe($this->Sender)) { 1278 1369 if ($this->Mailer == 'qmail') { 1279 $sendmail = sprintf('%s -f%s', escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));1370 $sendmailFmt = '%s -f%s'; 1280 1371 } else { 1281 $sendmail = sprintf('%s -oi -f%s -t', escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));1372 $sendmailFmt = '%s -oi -f%s -t'; 1282 1373 } 1283 1374 } else { 1284 1375 if ($this->Mailer == 'qmail') { 1285 $sendmail = sprintf('%s', escapeshellcmd($this->Sendmail));1376 $sendmailFmt = '%s'; 1286 1377 } else { 1287 $sendmail = sprintf('%s -oi -t', escapeshellcmd($this->Sendmail)); 1288 } 1289 } 1378 $sendmailFmt = '%s -oi -t'; 1379 } 1380 } 1381 1382 // TODO: If possible, this should be changed to escapeshellarg. Needs thorough testing. 1383 $sendmail = sprintf($sendmailFmt, escapeshellcmd($this->Sendmail), $this->Sender); 1384 1290 1385 if ($this->SingleTo) { 1291 1386 foreach ($this->SingleToArray as $toAddr) { … … 1334 1429 1335 1430 /** 1431 * Fix CVE-2016-10033 and CVE-2016-10045 by disallowing potentially unsafe shell characters. 1432 * 1433 * Note that escapeshellarg and escapeshellcmd are inadequate for our purposes, especially on Windows. 1434 * @param string $string The string to be validated 1435 * @see https://github.com/PHPMailer/PHPMailer/issues/924 CVE-2016-10045 bug report 1436 * @access protected 1437 * @return boolean 1438 */ 1439 protected static function isShellSafe($string) 1440 { 1441 // Future-proof 1442 if (escapeshellcmd($string) !== $string 1443 or !in_array(escapeshellarg($string), array("'$string'", "\"$string\"")) 1444 ) { 1445 return false; 1446 } 1447 1448 $length = strlen($string); 1449 1450 for ($i = 0; $i < $length; $i++) { 1451 $c = $string[$i]; 1452 1453 // All other characters have a special meaning in at least one common shell, including = and +. 1454 // Full stop (.) has a special meaning in cmd.exe, but its impact should be negligible here. 1455 // Note that this does permit non-Latin alphanumeric characters based on the current locale. 1456 if (!ctype_alnum($c) && strpos('@_-.', $c) === false) { 1457 return false; 1458 } 1459 } 1460 1461 return true; 1462 } 1463 1464 /** 1336 1465 * Send mail using the PHP mail() function. 1337 1466 * @param string $header The message headers … … 1350 1479 $to = implode(', ', $toArr); 1351 1480 1352 if (empty($this->Sender)) { 1353 $params = ' '; 1354 } else { 1355 $params = sprintf('-f%s', $this->Sender); 1356 } 1357 if ($this->Sender != '' and !ini_get('safe_mode')) { 1481 $params = null; 1482 //This sets the SMTP envelope sender which gets turned into a return-path header by the receiver 1483 if (!empty($this->Sender) and $this->validateAddress($this->Sender)) { 1484 // CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped. 1485 if (self::isShellSafe($this->Sender)) { 1486 $params = sprintf('-f%s', $this->Sender); 1487 } 1488 } 1489 if (!empty($this->Sender) and !ini_get('safe_mode') and $this->validateAddress($this->Sender)) { 1358 1490 $old_from = ini_get('sendmail_from'); 1359 1491 ini_set('sendmail_from', $this->Sender); 1360 1492 } 1361 1493 $result = false; 1362 if ($this->SingleTo &&count($toArr) > 1) {1494 if ($this->SingleTo and count($toArr) > 1) { 1363 1495 foreach ($toArr as $toAddr) { 1364 1496 $result = $this->mailPassthru($toAddr, $this->Subject, $body, $header, $params); … … 1410 1542 throw new phpmailerException($this->lang('smtp_connect_failed'), self::STOP_CRITICAL); 1411 1543 } 1412 if ('' == $this->Sender) { 1544 if (!empty($this->Sender) and $this->validateAddress($this->Sender)) { 1545 $smtp_from = $this->Sender; 1546 } else { 1413 1547 $smtp_from = $this->From; 1414 } else {1415 $smtp_from = $this->Sender;1416 1548 } 1417 1549 if (!$this->smtp->mail($smtp_from)) { … … 1467 1599 * @return boolean 1468 1600 */ 1469 public function smtpConnect($options = array())1601 public function smtpConnect($options = null) 1470 1602 { 1471 1603 if (is_null($this->smtp)) { 1472 1604 $this->smtp = $this->getSMTPInstance(); 1605 } 1606 1607 //If no options are provided, use whatever is set in the instance 1608 if (is_null($options)) { 1609 $options = $this->SMTPOptions; 1473 1610 } 1474 1611 … … 1542 1679 throw new phpmailerException($this->lang('connect_host')); 1543 1680 } 1544 // We must resend HELO after tlsnegotiation1681 // We must resend EHLO after TLS negotiation 1545 1682 $this->smtp->hello($hello); 1546 1683 } … … 1581 1718 public function smtpClose() 1582 1719 { 1583 if ( $this->smtp !== null) {1720 if (is_a($this->smtp, 'SMTP')) { 1584 1721 if ($this->smtp->connected()) { 1585 1722 $this->smtp->quit(); … … 1600 1737 public function setLanguage($langcode = 'en', $lang_path = '') 1601 1738 { 1739 // Backwards compatibility for renamed language codes 1740 $renamed_langcodes = array( 1741 'br' => 'pt_br', 1742 'cz' => 'cs', 1743 'dk' => 'da', 1744 'no' => 'nb', 1745 'se' => 'sv', 1746 ); 1747 1748 if (isset($renamed_langcodes[$langcode])) { 1749 $langcode = $renamed_langcodes[$langcode]; 1750 } 1751 1602 1752 // Define full set of translatable strings in English 1603 1753 $PHPMAILER_LANG = array( … … 1625 1775 // Calculate an absolute path so it can work if CWD is not here 1626 1776 $lang_path = dirname(__FILE__). DIRECTORY_SEPARATOR . 'language'. DIRECTORY_SEPARATOR; 1777 } 1778 //Validate $langcode 1779 if (!preg_match('/^[a-z]{2}(?:_[a-zA-Z]{2})?$/', $langcode)) { 1780 $langcode = 'en'; 1627 1781 } 1628 1782 $foundlang = true; … … 1919 2073 } 1920 2074 1921 if ($this->MessageID != '') { 2075 // Only allow a custom message ID if it conforms to RFC 5322 section 3.6.4 2076 // https://tools.ietf.org/html/rfc5322#section-3.6.4 2077 if ('' != $this->MessageID and preg_match('/^<.*@.*>$/', $this->MessageID)) { 1922 2078 $this->lastMessageID = $this->MessageID; 1923 2079 } else { … … 2021 2177 public function getSentMIMEMessage() 2022 2178 { 2023 return $this->MIMEHeader . $this->mailHeader . self::CRLF . $this->MIMEBody; 2179 return rtrim($this->MIMEHeader . $this->mailHeader, "\n\r") . self::CRLF . self::CRLF . $this->MIMEBody; 2180 } 2181 2182 /** 2183 * Create unique ID 2184 * @return string 2185 */ 2186 protected function generateId() { 2187 return md5(uniqid(time())); 2024 2188 } 2025 2189 … … 2035 2199 $body = ''; 2036 2200 //Create unique IDs and preset boundaries 2037 $this->uniqueid = md5(uniqid(time()));2201 $this->uniqueid = $this->generateId(); 2038 2202 $this->boundary[1] = 'b1_' . $this->uniqueid; 2039 2203 $this->boundary[2] = 'b2_' . $this->uniqueid; … … 2051 2215 if ($bodyEncoding == '8bit' and !$this->has8bitChars($this->Body)) { 2052 2216 $bodyEncoding = '7bit'; 2217 //All ISO 8859, Windows codepage and UTF-8 charsets are ascii compatible up to 7-bit 2053 2218 $bodyCharSet = 'us-ascii'; 2054 2219 } 2055 //If lines are too long, change to quoted-printable transfer encoding2056 if (self::hasLineLongerThanMax($this->Body)) {2057 $this->Encoding = 'quoted-printable';2220 //If lines are too long, and we're not already using an encoding that will shorten them, 2221 //change to quoted-printable transfer encoding for the body part only 2222 if ('base64' != $this->Encoding and self::hasLineLongerThanMax($this->Body)) { 2058 2223 $bodyEncoding = 'quoted-printable'; 2059 2224 } … … 2064 2229 if ($altBodyEncoding == '8bit' and !$this->has8bitChars($this->AltBody)) { 2065 2230 $altBodyEncoding = '7bit'; 2231 //All ISO 8859, Windows codepage and UTF-8 charsets are ascii compatible up to 7-bit 2066 2232 $altBodyCharSet = 'us-ascii'; 2067 2233 } 2068 //If lines are too long, change to quoted-printable transfer encoding 2069 if (self::hasLineLongerThanMax($this->AltBody)) { 2234 //If lines are too long, and we're not already using an encoding that will shorten them, 2235 //change to quoted-printable transfer encoding for the alt body part only 2236 if ('base64' != $altBodyEncoding and self::hasLineLongerThanMax($this->AltBody)) { 2070 2237 $altBodyEncoding = 'quoted-printable'; 2071 2238 } … … 2170 2337 break; 2171 2338 default: 2172 // catch case 'plain' and case '' 2173 $body .= $this->encodeString($this->Body, $bodyEncoding); 2339 // Catch case 'plain' and case '', applies to simple `text/plain` and `text/html` body content types 2340 //Reset the `Encoding` property in case we changed it for line length reasons 2341 $this->Encoding = $bodyEncoding; 2342 $body .= $this->encodeString($this->Body, $this->Encoding); 2174 2343 break; 2175 2344 } … … 2277 2446 /** 2278 2447 * Set the message type. 2279 * PHPMailer only supports some preset message types, 2280 * not arbitrary MIME structures. 2448 * PHPMailer only supports some preset message types, not arbitrary MIME structures. 2281 2449 * @access protected 2282 2450 * @return void … … 2296 2464 $this->message_type = implode('_', $type); 2297 2465 if ($this->message_type == '') { 2466 //The 'plain' message_type refers to the message having a single body element, not that it is plain-text 2298 2467 $this->message_type = 'plain'; 2299 2468 } … … 3210 3379 3211 3380 /** 3212 * Create a message from an HTML string. 3213 * Automatically makes modifications for inline images and backgrounds 3214 * and creates a plain-text version by converting the HTML. 3215 * Overwrites any existing values in $this->Body and $this->AltBody 3381 * Create a message body from an HTML string. 3382 * Automatically inlines images and creates a plain-text version by converting the HTML, 3383 * overwriting any existing values in Body and AltBody. 3384 * $basedir is used when handling relative image paths, e.g. <img src="images/a.png"> 3385 * will look for an image file in $basedir/images/a.png and convert it to inline. 3386 * If you don't want to apply these transformations to your HTML, just set Body and AltBody yourself. 3216 3387 * @access public 3217 3388 * @param string $message HTML message string 3218 * @param string $basedir base line directory for path3389 * @param string $basedir base directory for relative paths to images 3219 3390 * @param boolean|callable $advanced Whether to use the internal HTML to text converter 3220 3391 * or your own custom converter @see PHPMailer::html2text() 3221 * @return string $message 3392 * @return string $message The transformed message Body 3222 3393 */ 3223 3394 public function msgHTML($message, $basedir = '', $advanced = false) … … 3242 3413 ); 3243 3414 } 3244 } elseif (substr($url, 0, 4) !== 'cid:' && !preg_match('#^[ A-z]+://#', $url)) {3415 } elseif (substr($url, 0, 4) !== 'cid:' && !preg_match('#^[a-z][a-z0-9+.-]*://#i', $url)) { 3245 3416 // Do not change urls for absolute images (thanks to corvuscorax) 3246 3417 // Do not change urls that are already inline images … … 3278 3449 $this->Body = $this->normalizeBreaks($message); 3279 3450 $this->AltBody = $this->normalizeBreaks($this->html2text($message, $advanced)); 3280 if ( empty($this->AltBody)) {3451 if (!$this->alternativeExists()) { 3281 3452 $this->AltBody = 'To view this email message, open it in a program that understands HTML!' . 3282 3453 self::CRLF . self::CRLF; … … 3289 3460 * This is used by msgHTML(). 3290 3461 * Note - older versions of this function used a bundled advanced converter 3291 * which was been removed for license reasons in #232 3462 * which was been removed for license reasons in #232. 3292 3463 * Example usage: 3293 3464 * <code> … … 3589 3760 * @param string $signHeader 3590 3761 * @throws phpmailerException 3591 * @return string 3762 * @return string The DKIM signature value 3592 3763 */ 3593 3764 public function DKIM_Sign($signHeader) … … 3599 3770 return ''; 3600 3771 } 3601 $privKeyStr = file_get_contents($this->DKIM_private);3602 if ( $this->DKIM_passphrase != '') {3772 $privKeyStr = !empty($this->DKIM_private_string) ? $this->DKIM_private_string : file_get_contents($this->DKIM_private); 3773 if ('' != $this->DKIM_passphrase) { 3603 3774 $privKey = openssl_pkey_get_private($privKeyStr, $this->DKIM_passphrase); 3604 3775 } else { 3605 $privKey = $privKeyStr; 3606 } 3607 if (openssl_sign($signHeader, $signature, $privKey)) { 3608 return base64_encode($signature); 3609 } 3776 $privKey = openssl_pkey_get_private($privKeyStr); 3777 } 3778 //Workaround for missing digest algorithms in old PHP & OpenSSL versions 3779 //@link http://stackoverflow.com/a/11117338/333340 3780 if (version_compare(PHP_VERSION, '5.3.0') >= 0 and 3781 in_array('sha256WithRSAEncryption', openssl_get_md_methods(true))) { 3782 if (openssl_sign($signHeader, $signature, $privKey, 'sha256WithRSAEncryption')) { 3783 openssl_pkey_free($privKey); 3784 return base64_encode($signature); 3785 } 3786 } else { 3787 $pinfo = openssl_pkey_get_details($privKey); 3788 $hash = hash('sha256', $signHeader); 3789 //'Magic' constant for SHA256 from RFC3447 3790 //@link https://tools.ietf.org/html/rfc3447#page-43 3791 $t = '3031300d060960864801650304020105000420' . $hash; 3792 $pslen = $pinfo['bits'] / 8 - (strlen($t) / 2 + 3); 3793 $eb = pack('H*', '0001' . str_repeat('FF', $pslen) . '00' . $t); 3794 3795 if (openssl_private_encrypt($eb, $signature, $privKey, OPENSSL_NO_PADDING)) { 3796 openssl_pkey_free($privKey); 3797 return base64_encode($signature); 3798 } 3799 } 3800 openssl_pkey_free($privKey); 3610 3801 return ''; 3611 3802 } … … 3624 3815 list($heading, $value) = explode(':', $line, 2); 3625 3816 $heading = strtolower($heading); 3626 $value = preg_replace('/\s +/', ' ', $value); // Compress useless spaces3817 $value = preg_replace('/\s{2,}/', ' ', $value); // Compress useless spaces 3627 3818 $lines[$key] = $heading . ':' . trim($value); // Don't forget to remove WSP around the value 3628 3819 } … … 3662 3853 public function DKIM_Add($headers_line, $subject, $body) 3663 3854 { 3664 $DKIMsignatureType = 'rsa-sha 1'; // Signature & hash algorithms3855 $DKIMsignatureType = 'rsa-sha256'; // Signature & hash algorithms 3665 3856 $DKIMcanonicalization = 'relaxed/simple'; // Canonicalization of header/body 3666 3857 $DKIMquery = 'dns/txt'; // Query method … … 3670 3861 $from_header = ''; 3671 3862 $to_header = ''; 3863 $date_header = ''; 3672 3864 $current = ''; 3673 3865 foreach ($headers as $header) { … … 3678 3870 $to_header = $header; 3679 3871 $current = 'to_header'; 3872 } elseif (strpos($header, 'Date:') === 0) { 3873 $date_header = $header; 3874 $current = 'date_header'; 3680 3875 } else { 3681 3876 if (!empty($$current) && strpos($header, ' =?') === 0) { … … 3688 3883 $from = str_replace('|', '=7C', $this->DKIM_QP($from_header)); 3689 3884 $to = str_replace('|', '=7C', $this->DKIM_QP($to_header)); 3885 $date = str_replace('|', '=7C', $this->DKIM_QP($date_header)); 3690 3886 $subject = str_replace( 3691 3887 '|', … … 3695 3891 $body = $this->DKIM_BodyC($body); 3696 3892 $DKIMlen = strlen($body); // Length of body 3697 $DKIMb64 = base64_encode(pack('H*', sha1($body))); // Base64 of packed binary SHA-1hash of body3893 $DKIMb64 = base64_encode(pack('H*', hash('sha256', $body))); // Base64 of packed binary SHA-256 hash of body 3698 3894 if ('' == $this->DKIM_identity) { 3699 3895 $ident = ''; … … 3708 3904 ";\r\n" . 3709 3905 "\tt=" . $DKIMtime . '; c=' . $DKIMcanonicalization . ";\r\n" . 3710 "\th=From:To: Subject;\r\n" .3906 "\th=From:To:Date:Subject;\r\n" . 3711 3907 "\td=" . $this->DKIM_domain . ';' . $ident . "\r\n" . 3712 3908 "\tz=$from\r\n" . 3713 3909 "\t|$to\r\n" . 3910 "\t|$date\r\n" . 3714 3911 "\t|$subject;\r\n" . 3715 3912 "\tbh=" . $DKIMb64 . ";\r\n" . … … 3718 3915 $from_header . "\r\n" . 3719 3916 $to_header . "\r\n" . 3917 $date_header . "\r\n" . 3720 3918 $subject_header . "\r\n" . 3721 3919 $dkimhdrs -
branches/4.7/src/wp-includes/class-smtp.php
r36083 r39646 31 31 * @var string 32 32 */ 33 const VERSION = '5.2. 14';33 const VERSION = '5.2.21'; 34 34 35 35 /** … … 82 82 * @see SMTP::VERSION 83 83 */ 84 public $Version = '5.2. 14';84 public $Version = '5.2.21'; 85 85 86 86 /** … … 151 151 public $Timelimit = 300; 152 152 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 ); 163 153 164 /** 154 165 * The socket for the server connection. … … 207 218 //Avoid clash with built-in function names 208 219 if (!in_array($this->Debugoutput, array('error_log', 'html', 'echo')) and is_callable($this->Debugoutput)) { 209 call_user_func($this->Debugoutput, $str, $ this->do_debug);220 call_user_func($this->Debugoutput, $str, $level); 210 221 return; 211 222 } … … 273 284 if ($streamok) { 274 285 $socket_context = stream_context_create($options); 275 //Suppress errors; connection failures are handled at a higher level276 $this->smtp_conn = @stream_socket_client(286 set_error_handler(array($this, 'errorHandler')); 287 $this->smtp_conn = stream_socket_client( 277 288 $host . ":" . $port, 278 289 $errno, … … 282 293 $socket_context 283 294 ); 295 restore_error_handler(); 284 296 } else { 285 297 //Fall back to fsockopen which should work in more places, but is missing some features … … 288 300 self::DEBUG_CONNECTION 289 301 ); 302 set_error_handler(array($this, 'errorHandler')); 290 303 $this->smtp_conn = fsockopen( 291 304 $host, … … 295 308 $timeout 296 309 ); 310 restore_error_handler(); 297 311 } 298 312 // Verify we connected properly … … 337 351 return false; 338 352 } 353 354 //Allow the best TLS version(s) we can 355 $crypto_method = STREAM_CRYPTO_METHOD_TLS_CLIENT; 356 357 //PHP 5.6.7 dropped inclusion of TLS 1.1 and 1.2 in STREAM_CRYPTO_METHOD_TLS_CLIENT 358 //so add them back in manually if we can 359 if (defined('STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT')) { 360 $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT; 361 $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT; 362 } 363 339 364 // Begin encrypted connection 340 365 if (!stream_socket_enable_crypto( 341 366 $this->smtp_conn, 342 367 true, 343 STREAM_CRYPTO_METHOD_TLS_CLIENT368 $crypto_method 344 369 )) { 345 370 return false; … … 354 379 * @param string $username The user name 355 380 * @param string $password The password 356 * @param string $authtype The auth type (PLAIN, LOGIN, NTLM, CRAM-MD5, XOAUTH2)381 * @param string $authtype The auth type (PLAIN, LOGIN, CRAM-MD5) 357 382 * @param string $realm The auth realm for NTLM 358 383 * @param string $workstation The auth workstation for NTLM … … 390 415 391 416 if (empty($authtype)) { 392 foreach (array(' LOGIN', 'CRAM-MD5', 'PLAIN') as $method) {417 foreach (array('CRAM-MD5', 'LOGIN', 'PLAIN') as $method) { 393 418 if (in_array($method, $this->server_caps['AUTH'])) { 394 419 $authtype = $method; … … 674 699 { 675 700 $this->server_caps = array(); 676 $lines = explode("\n", $this-> last_reply);701 $lines = explode("\n", $this->helo_rply); 677 702 678 703 foreach ($lines as $n => $s) { … … 1116 1141 return $this->Timeout; 1117 1142 } 1143 1144 /** 1145 * Reports an error number and string. 1146 * @param integer $errno The error number returned by PHP. 1147 * @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.'; 1152 $this->setError( 1153 $notice, 1154 $errno, 1155 $errmsg 1156 ); 1157 $this->edebug( 1158 $notice . ' Error number ' . $errno . '. "Error notice: ' . $errmsg, 1159 self::DEBUG_CONNECTION 1160 ); 1161 } 1162 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; 1185 } 1118 1186 }
Note: See TracChangeset
for help on using the changeset viewer.