@@ -768,7 +768,7 @@ class PHPMailer
768768 *
769769 * @var string
770770 */
771- const VERSION = '7.0.0 ' ;
771+ const VERSION = '7.0.2 ' ;
772772
773773 /**
774774 * Error severity: message only, continue processing.
@@ -876,6 +876,7 @@ public function __destruct()
876876 private function mailPassthru ($ to , $ subject , $ body , $ header , $ params )
877877 {
878878 //Check overloading of mail function to avoid double-encoding
879+ // phpcs:ignore PHPCompatibility.IniDirectives.RemovedIniDirectives.mbstring_func_overloadDeprecatedRemoved
879880 if ((int )ini_get ('mbstring.func_overload ' ) & 1 ) {
880881 $ subject = $ this ->secureHeader ($ subject );
881882 } else {
@@ -987,6 +988,54 @@ public function isMail()
987988 $ this ->Mailer = 'mail ' ;
988989 }
989990
991+ /**
992+ * Extract sendmail path and parse to deal with known parameters.
993+ *
994+ * @param string $sendmailPath The sendmail path as set in php.ini
995+ *
996+ * @return string The sendmail path without the known parameters
997+ */
998+ private function parseSendmailPath ($ sendmailPath )
999+ {
1000+ $ sendmailPath = trim ((string )$ sendmailPath );
1001+ if ($ sendmailPath === '' ) {
1002+ return $ sendmailPath ;
1003+ }
1004+
1005+ $ parts = preg_split ('/\s+/ ' , $ sendmailPath );
1006+ if (empty ($ parts )) {
1007+ return $ sendmailPath ;
1008+ }
1009+
1010+ $ command = array_shift ($ parts );
1011+ $ remainder = [];
1012+
1013+ // Parse only -t, -i, -oi and -f parameters.
1014+ for ($ i = 0 ; $ i < count ($ parts ); ++$ i ) {
1015+ $ part = $ parts [$ i ];
1016+ if (preg_match ('/^-(i|oi|t)$/ ' , $ part , $ matches )) {
1017+ continue ;
1018+ }
1019+ if (preg_match ('/^-f(.*)$/ ' , $ part , $ matches )) {
1020+ $ address = $ matches [1 ];
1021+ if ($ address === '' && isset ($ parts [$ i + 1 ]) && strpos ($ parts [$ i + 1 ], '- ' ) !== 0 ) {
1022+ $ address = $ parts [++$ i ];
1023+ }
1024+ $ this ->Sender = $ address ;
1025+ continue ;
1026+ }
1027+
1028+ $ remainder [] = $ part ;
1029+ }
1030+
1031+ // The params that are not parsed are added back to the command.
1032+ if (!empty ($ remainder )) {
1033+ $ command .= ' ' . implode (' ' , $ remainder );
1034+ }
1035+
1036+ return $ command ;
1037+ }
1038+
9901039 /**
9911040 * Send messages using $Sendmail.
9921041 */
@@ -995,10 +1044,9 @@ public function isSendmail()
9951044 $ ini_sendmail_path = ini_get ('sendmail_path ' );
9961045
9971046 if (false === stripos ($ ini_sendmail_path , 'sendmail ' )) {
998- $ this ->Sendmail = '/usr/sbin/sendmail ' ;
999- } else {
1000- $ this ->Sendmail = $ ini_sendmail_path ;
1047+ $ ini_sendmail_path = '/usr/sbin/sendmail ' ;
10011048 }
1049+ $ this ->Sendmail = $ this ->parseSendmailPath ($ ini_sendmail_path );
10021050 $ this ->Mailer = 'sendmail ' ;
10031051 }
10041052
@@ -1010,10 +1058,9 @@ public function isQmail()
10101058 $ ini_sendmail_path = ini_get ('sendmail_path ' );
10111059
10121060 if (false === stripos ($ ini_sendmail_path , 'qmail ' )) {
1013- $ this ->Sendmail = '/var/qmail/bin/qmail-inject ' ;
1014- } else {
1015- $ this ->Sendmail = $ ini_sendmail_path ;
1061+ $ ini_sendmail_path = '/var/qmail/bin/qmail-inject ' ;
10161062 }
1063+ $ this ->Sendmail = $ this ->parseSendmailPath ($ ini_sendmail_path );
10171064 $ this ->Mailer = 'qmail ' ;
10181065 }
10191066
@@ -1242,21 +1289,25 @@ protected function addAnAddress($kind, $address, $name = '')
12421289 * @see https://www.andrew.cmu.edu/user/agreen1/testing/mrbs/web/Mail/RFC822.php A more careful implementation
12431290 *
12441291 * @param string $addrstr The address list string
1245- * @param null $useimap Deprecated argument since 6.11.0.
1292+ * @param null $useimap Unused. Argument has been deprecated in PHPMailer 6.11.0.
1293+ * Previously this argument determined whether to use
1294+ * the IMAP extension to parse the list and accepted a boolean value.
12461295 * @param string $charset The charset to use when decoding the address list string.
12471296 *
12481297 * @return array
12491298 */
12501299 public static function parseAddresses ($ addrstr , $ useimap = null , $ charset = self ::CHARSET_ISO88591 )
12511300 {
12521301 if ($ useimap !== null ) {
1253- trigger_error (self ::lang ('deprecated_argument ' ), E_USER_DEPRECATED );
1302+ trigger_error (self ::lang ('deprecated_argument ' ) . ' $useimap ' , E_USER_DEPRECATED );
12541303 }
12551304 $ addresses = [];
12561305 if (function_exists ('imap_rfc822_parse_adrlist ' )) {
12571306 //Use this built-in parser if it's available
1307+ // phpcs:ignore PHPCompatibility.FunctionUse.RemovedFunctions.imap_rfc822_parse_adrlistRemoved -- wrapped in function_exists()
12581308 $ list = imap_rfc822_parse_adrlist ($ addrstr , '' );
12591309 // Clear any potential IMAP errors to get rid of notices being thrown at end of script.
1310+ // phpcs:ignore PHPCompatibility.FunctionUse.RemovedFunctions.imap_errorsRemoved -- wrapped in function_exists()
12601311 imap_errors ();
12611312 foreach ($ list as $ address ) {
12621313 if (
@@ -1583,9 +1634,11 @@ public function punyencodeAddress($address)
15831634 );
15841635 } elseif (defined ('INTL_IDNA_VARIANT_2003 ' )) {
15851636 //Fall back to this old, deprecated/removed encoding
1637+ // phpcs:ignore PHPCompatibility.Constants.RemovedConstants.intl_idna_variant_2003DeprecatedRemoved
15861638 $ punycode = idn_to_ascii ($ domain , $ errorcode , \INTL_IDNA_VARIANT_2003 );
15871639 } else {
15881640 //Fall back to a default we don't know about
1641+ // phpcs:ignore PHPCompatibility.ParameterValues.NewIDNVariantDefault.NotSet
15891642 $ punycode = idn_to_ascii ($ domain , $ errorcode );
15901643 }
15911644 if (false !== $ punycode ) {
@@ -1853,25 +1906,27 @@ protected function sendmailSend($header, $body)
18531906 //PHP config has a sender address we can use
18541907 $ this ->Sender = ini_get ('sendmail_from ' );
18551908 }
1856- //CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
1909+
1910+ $ sendmailArgs = [];
1911+
1912+ // CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
1913+ // Also don't add the -f automatically unless it has been set either via Sender
1914+ // or sendmail_path. Otherwise it can introduce new problems.
1915+ // @see http://github.com/PHPMailer/PHPMailer/issues/2298
18571916 if (!empty ($ this ->Sender ) && static ::validateAddress ($ this ->Sender ) && self ::isShellSafe ($ this ->Sender )) {
1858- if ($ this ->Mailer === 'qmail ' ) {
1859- $ sendmailFmt = '%s -f%s ' ;
1860- } else {
1861- $ sendmailFmt = '%s -oi -f%s -t ' ;
1862- }
1863- } elseif ($ this ->Mailer === 'qmail ' ) {
1864- $ sendmailFmt = '%s ' ;
1865- } else {
1866- //Allow sendmail to choose a default envelope sender. It may
1867- //seem preferable to force it to use the From header as with
1868- //SMTP, but that introduces new problems (see
1869- //<https://github.com/PHPMailer/PHPMailer/issues/2298>), and
1870- //it has historically worked this way.
1871- $ sendmailFmt = '%s -oi -t ' ;
1917+ $ sendmailArgs [] = '-f ' . $ this ->Sender ;
1918+ }
1919+
1920+ // Qmail doesn't accept all the sendmail parameters
1921+ // @see https://github.com/PHPMailer/PHPMailer/issues/3189
1922+ if ($ this ->Mailer !== 'qmail ' ) {
1923+ $ sendmailArgs [] = '-i ' ;
1924+ $ sendmailArgs [] = '-t ' ;
18721925 }
18731926
1874- $ sendmail = sprintf ($ sendmailFmt , escapeshellcmd ($ this ->Sendmail ), $ this ->Sender );
1927+ $ resultArgs = (empty ($ sendmailArgs ) ? '' : ' ' . implode (' ' , $ sendmailArgs ));
1928+
1929+ $ sendmail = trim (escapeshellcmd ($ this ->Sendmail ) . $ resultArgs );
18751930 $ this ->edebug ('Sendmail path: ' . $ this ->Sendmail );
18761931 $ this ->edebug ('Sendmail command: ' . $ sendmail );
18771932 $ this ->edebug ('Envelope sender: ' . $ this ->Sender );
@@ -2055,7 +2110,8 @@ protected function mailSend($header, $body)
20552110 $ this ->Sender = ini_get ('sendmail_from ' );
20562111 }
20572112 if (!empty ($ this ->Sender ) && static ::validateAddress ($ this ->Sender )) {
2058- if (self ::isShellSafe ($ this ->Sender )) {
2113+ $ phpmailer_path = ini_get ('sendmail_path ' );
2114+ if (self ::isShellSafe ($ this ->Sender ) && strpos ($ phpmailer_path , ' -f ' ) === false ) {
20592115 $ params = sprintf ('-f%s ' , $ this ->Sender );
20602116 }
20612117 $ old_from = ini_get ('sendmail_from ' );
@@ -2482,7 +2538,7 @@ public static function setLanguage($langcode = 'en', $lang_path = '')
24822538 'no_smtputf8 ' => 'Server does not support SMTPUTF8 needed to send to Unicode addresses ' ,
24832539 'imap_recommended ' => 'Using simplified address parser is not recommended. ' .
24842540 'Install the PHP IMAP extension for full RFC822 parsing. ' ,
2485- 'deprecated_argument ' => 'Argument $useimap is deprecated ' ,
2541+ 'deprecated_argument ' => 'Deprecated Argument: ' ,
24862542 ];
24872543 if (empty ($ lang_path )) {
24882544 //Calculate an absolute path so it can work if CWD is not here
@@ -2956,6 +3012,7 @@ protected function generateId()
29563012 $ bytes = '' ;
29573013 if (function_exists ('random_bytes ' )) {
29583014 try {
3015+ // phpcs:ignore PHPCompatibility.FunctionUse.NewFunctions.random_bytesFound -- Wrapped in function_exists.
29593016 $ bytes = random_bytes ($ len );
29603017 } catch (\Exception $ e ) {
29613018 //Do nothing
@@ -4590,10 +4647,10 @@ public function getCustomHeaders()
45904647 * Converts data-uri images into embedded attachments.
45914648 * If you don't want to apply these transformations to your HTML, just set Body and AltBody directly.
45924649 *
4593- * @param string $message HTML message string
4594- * @param string $basedir Absolute path to a base directory to prepend to relative paths to images
4595- * @param bool|callable $advanced Whether to use the internal HTML to text converter
4596- * or your own custom converter
4650+ * @param string $message HTML message string
4651+ * @param string $basedir Absolute path to a base directory to prepend to relative paths to images
4652+ * @param bool|callable $advanced Whether to use the internal HTML to text converter
4653+ * or your own custom converter
45974654 * @return string The transformed message body
45984655 *
45994656 * @throws Exception
@@ -4602,6 +4659,12 @@ public function getCustomHeaders()
46024659 */
46034660 public function msgHTML ($ message , $ basedir = '' , $ advanced = false )
46044661 {
4662+ $ cid_domain = 'phpmailer.0 ' ;
4663+ if (filter_var ($ this ->From , FILTER_VALIDATE_EMAIL )) {
4664+ //prepend with a character to create valid RFC822 string in order to validate
4665+ $ cid_domain = substr ($ this ->From , strrpos ($ this ->From , '@ ' ) + 1 );
4666+ }
4667+
46054668 preg_match_all ('/(?<!-)(src|background)=[" \'](.*)[" \']/Ui ' , $ message , $ images );
46064669 if (array_key_exists (2 , $ images )) {
46074670 if (strlen ($ basedir ) > 1 && '/ ' !== substr ($ basedir , -1 )) {
@@ -4623,7 +4686,7 @@ public function msgHTML($message, $basedir = '', $advanced = false)
46234686 }
46244687 //Hash the decoded data, not the URL, so that the same data-URI image used in multiple places
46254688 //will only be embedded once, even if it used a different encoding
4626- $ cid = substr (hash ('sha256 ' , $ data ), 0 , 32 ) . '@phpmailer.0 ' ; //RFC2392 S 2
4689+ $ cid = substr (hash ('sha256 ' , $ data ), 0 , 32 ) . '@ ' . $ cid_domain ; //RFC2392 S 2
46274690
46284691 if (!$ this ->cidExists ($ cid )) {
46294692 $ this ->addStringEmbeddedImage (
@@ -4657,7 +4720,7 @@ public function msgHTML($message, $basedir = '', $advanced = false)
46574720 $ directory = '' ;
46584721 }
46594722 //RFC2392 S 2
4660- $ cid = substr (hash ('sha256 ' , $ url ), 0 , 32 ) . '@phpmailer.0 ' ;
4723+ $ cid = substr (hash ('sha256 ' , $ url ), 0 , 32 ) . '@ ' . $ cid_domain ;
46614724 if (strlen ($ basedir ) > 1 && '/ ' !== substr ($ basedir , -1 )) {
46624725 $ basedir .= '/ ' ;
46634726 }
@@ -5105,12 +5168,14 @@ public function DKIM_Sign($signHeader)
51055168 }
51065169 if (openssl_sign ($ signHeader , $ signature , $ privKey , 'sha256WithRSAEncryption ' )) {
51075170 if (\PHP_MAJOR_VERSION < 8 ) {
5171+ // phpcs:ignore PHPCompatibility.FunctionUse.RemovedFunctions.openssl_pkey_freeDeprecated
51085172 openssl_pkey_free ($ privKey );
51095173 }
51105174
51115175 return base64_encode ($ signature );
51125176 }
51135177 if (\PHP_MAJOR_VERSION < 8 ) {
5178+ // phpcs:ignore PHPCompatibility.FunctionUse.RemovedFunctions.openssl_pkey_freeDeprecated
51145179 openssl_pkey_free ($ privKey );
51155180 }
51165181
0 commit comments