PHP mail() 错误:在 additional_header 中发现多个或格式不正确的换行符


Error with PHP mail(): Multiple or malformed newlines found in additional_header

突然开始收到上述错误,而没有对脚本进行任何更改。

主人是1和1(我知道...

该脚本在不同的服务器上仍然可以正常工作,所以我怀疑一定是有一些服务器配置更改导致了这种情况,尽管主机表示无知。

我在谷歌中找不到关于上述错误的信息 - 有人有任何想法吗? 服务器正在运行Apache,如果有帮助的话。

也有类似的问题。
它突然出现。没有更改 PHP 代码。

更改内容:PHP 已从 5.5.25-1 升级到 5.5.26。

PHP mail() 函数中的安全风险已得到修复,additional_headers中不再允许额外的换行符。因为额外的换行符意味着:现在开始电子邮件(我们当然不希望有人通过标题注入一些换行符,然后是恶意消息)。

以前工作正常的东西,例如,只是在标题后有额外的换行符,甚至将整个消息传递给additional_headers,将不再起作用。

解决方案

  • 清理标题。additional_headers参数中没有多个换行符。这些计为"多个或格式错误的换行符":'r'r, 'r'0, 'r'n'r'n, 'n'n, 'n'0
  • 仅对标头使用 additional_headers。电子邮件(多部分或非多部分,带有不带附件的 ir 等)属于message参数,而不是标头。

PHP 安全漏洞报告:https://bugs.php.net/bug.php?id=68776
C 代码如何解决:http://git.php.net/?p=php-src.git;a=blobdiff;f=ext/standard/mail.c;h=448013a472a3466245e64b1cb37a9d1b0f7c007e;hp=1ebc8fecb7ef4c266a341cdc701f0686d6482242;hb=9d168b863e007c4e15ebe4d2eecabdf8b0582e30;hpb=eee8b6c33fc968ef8c496db8fb54e8c9d9d5a8f9

以上答案都没有为我解决这个问题。 因此,我将搜索范围扩大到"带有附件和HTML邮件问题的邮件"。 从几个不同的帖子中拼凑信息,我想出了这个。 它允许HTML电子邮件和附件。

我的原始标头代码:

$header = "From: ".$from_name." <".$from_mail.">'r'n";
$header .= "Reply-To: ".$replyto."'r'n";
$header .= "MIME-Version: 1.0'r'n";
$header .= "Content-Type: multipart/mixed; boundary='"".$uid."'"'r'n";
$header .= "--".$uid."'r'n";
$header .= "Content-Type: text/html; charset=ISO-8859-1'r'n";
$header .= "Content-Transfer-Encoding: 8bit'r'n";
$header .= $body."'r'n";
$header .= "--".$uid."'r'n";
$header .= "Content-Type: application/pdf; name='"".$filename."'"'r'n"; 
$header .= "Content-Transfer-Encoding: base64'r'n";
$header .= "Content-Disposition: attachment; filename='"".$filename."'"'r'n";
$header .= $content."'r'n";
$header .= "--".$uid."--";
if (mail($mail_to, $subject, "", $header))
{
    return "mail_success";
}
else
{
    return "mail_error";
}

我的新代码(完整):请注意,$body是由不同函数组装的 HTML。

$file = $path.$filename;
$file_size = filesize($file);
$handle = fopen($file, "r");
$content = fread($handle, $file_size);
fclose($handle);
$content = chunk_split(base64_encode($content));
$uid = md5(uniqid(time()));
$name = basename($file);
$eol = PHP_EOL;
// Basic headers
$header = "From: ".$from_name." <".$from_mail.">".$eol;
$header .= "Reply-To: ".$replyto.$eol;
$header .= "MIME-Version: 1.0'r'n";
$header .= "Content-Type: multipart/mixed; boundary='"".$uid."'"";
// Put everything else in $message
$message = "--".$uid.$eol;
$message .= "Content-Type: text/html; charset=ISO-8859-1".$eol;
$message .= "Content-Transfer-Encoding: 8bit".$eol.$eol;
$message .= $body.$eol;
$message .= "--".$uid.$eol;
$message .= "Content-Type: application/pdf; name='"".$filename."'"".$eol;
$message .= "Content-Transfer-Encoding: base64".$eol;
$message .= "Content-Disposition: attachment; filename='"".$filename."'"".$eol;
$message .= $content.$eol;
$message .= "--".$uid."--";
if (mail($mail_to, $subject, $message, $header))
{
    return "mail_success";
}
else
{
    return "mail_error";
}

这里有两个关键变化。(1) 将所有多部分内容从标题中删除到$message。 (2)删除了所有"''r'"的东西,并在代码中添加了$eol = PHP_EOL;

总之,这些更改使我能够再次发送带有附件的HTML电子邮件。

有同样的问题:从标头中删除了 MIME 边界和消息,并且全部有效。

    $header = "From: ".$from_name." <".$from_mail.">'n";
    $header .= "Reply-To: ".$replyto."'n";
    $header .= "MIME-Version: 1.0'n";
    $header .= "Content-Type: multipart/mixed; boundary='"".$uid."'"'n'n";
    $emessage= "--".$uid."'n";
    $emessage.= "Content-type:text/plain; charset=iso-8859-1'n";
    $emessage.= "Content-Transfer-Encoding: 7bit'n'n";
    $emessage .= $message."'n'n";
    $emessage.= "--".$uid."'n";
    $emessage .= "Content-Type: application/octet-stream; name='"".$filename."'"'n"; // use different content types here
    $emessage .= "Content-Transfer-Encoding: base64'n";
    $emessage .= "Content-Disposition: attachment; filename='"".$filename."'"'n'n";
    $emessage .= $content."'n'n";
    $emessage .= "--".$uid."--";
    mail($mailto,$subject,$emessage,$header);

以上都没有为我修复它 - 主要问题是您不得在标题中放置标题定义以外的任何内容。旧脚本在那里搞砸了任何东西。因此,将填充到标题的任何文本或附件移动到邮件正文中。意义。。

这有一个解释
(我想这与上面的弗兰克和戴维斯卡的"没有双新行"的解决方案相同 - 但你需要为附件加倍新行)

这将解决您的问题。我更改了一点弗兰克的代码。此代码将支持附件和 html。

 <?php
$filename  = "certificate.jpg";
$path      = "/home/omnibl/subdomains/test/certificate/certimage/";
$file      = $path . $filename;
$file_size = filesize($file);
$handle    = fopen($file, "r");
$content   = fread($handle, $file_size);
fclose($handle);
$content = chunk_split(base64_encode($content));
$uid     = md5(uniqid(time()));
$name    = basename($file);
$eol     = PHP_EOL;
$subject = "Mail Out Certificate";
$message = '<h1>Hi i m mashpy</h1>';
$from_name = "mail@example.com";
$from_mail = "mail@example.com";
$replyto   = "mail@example.com";
$mailto    = "mail@example.com";
$header    = "From: " . $from_name . " <" . $from_mail . ">'n";
$header .= "Reply-To: " . $replyto . "'n";
$header .= "MIME-Version: 1.0'n";
$header .= "Content-Type: multipart/mixed; boundary='"" . $uid . "'"'n'n";
$emessage = "--" . $uid . "'n";
$emessage .= "Content-type:text/html; charset=iso-8859-1'n";
$emessage .= "Content-Transfer-Encoding: 7bit'n'n";
$emessage .= $message . "'n'n";
$emessage .= "--" . $uid . "'n";
$emessage .= "Content-Type: application/octet-stream; name='"" . $filename . "'"'n"; // use different content types here
$emessage .= "Content-Transfer-Encoding: base64'n";
$emessage .= "Content-Disposition: attachment; filename='"" . $filename . "'"'n'n";
$emessage .= $content . "'n'n";
$emessage .= "--" . $uid . "--";
mail($mailto, $subject, $emessage, $header);

带来相同新错误的另一种情况是,如果您没有向"mail"命令发送任何标头。它过去只使用默认值,现在给出误导性错误:"在additional_header中找到多个或格式错误的换行符"。

可以通过添加以下内容来修复:

$header = "From: ".$from_name." <".$from_mail.">'n";
$header .= "Reply-To: ".$replyto."'n";
$header .= "MIME-Version: 1.0'n";
...
mail($mailto,$subject,$emessage,$header);

我的PHP版本 - 5.4.43,可能包含修复的错误 #68776。

谷歌搜索相同的错误显示[http://fossies.org/diffs/php/5.4.42_vs_5.4.43/ext/standard/mail.c-diff.html]

=> 我不能使用空字符串作为 mail() 参数。

我的旧代码:

$headers = 'From: ' . $frm . "'r'n";
$headers .= 'To: ' . $contactEmail . "'r'n";
if ( $flag ) {
  $headers .= 'To: ' . $contactEmail2 . "'r'n";
}
$headers .= 'Cc: ' . $contactEmailCc . "'r'n";
$headers .= 'Bcc: ' . $contactEmailBcc . "'r'n";
$headers .= 'Return-Path: ' . $frm . "'r'n";
$headers .= 'MIME-Version: 1.0' ."'r'n";
$headers .= 'Content-Type: text/HTML; charset=ISO-8859-1' . "'r'n";
$headers .= 'Content-Transfer-Encoding: 8bit'. "'n'r'n";
$headers .= $htmlText . "'r'n";
if (!mail('', $strSubject, '', $headers)) {    // !!! note the empty parameters.

我的新代码:

$headers = 'From: ' . $frm . "'r'n";
// note: no "To: " !!!
$headers .= 'Cc: ' . $contactEmailCc . "'r'n";
$headers .= 'Bcc: ' . $contactEmailBcc . "'r'n";
$headers .= 'Return-Path: ' . $frm . "'r'n";
$headers .= 'MIME-Version: 1.0' ."'r'n";   
$headers .= 'Content-Type: text/HTML; charset=ISO-8859-1' . "'r'n";
$headers .= 'Content-Transfer-Encoding: 8bit'. "'n'r'n";
// note: no $htmlText !!!
// note: new parameters:  
$mTo = $contactEmail;
if ( $flag ) {
  $mTo .= ', ' . $contactEmail2;
}
$mMessage .= $htmlText . "'r'n";
if (!mail($mTo, $strSubject, $mMessage, $headers)) {
您可能会

遇到错误 #69874 如果您没有做任何愚蠢的事情(即忘记清理标头),则无法为 mail() 设置空additional_headers。

测试错误

$ php -d display_errors=1 -d display_startup_errors=1 -d error_reporting=30719 -r 'mail("test@email.com","Subject Here", "Message Here",NULL);'
Warning: mail(): Multiple or malformed newlines found in additional_header in Command line code on line 1

或者,如果您知道您的 PHP 版本(提示:php -v),您可以检查错误编号 (69874) 的更新日志,以查看是否已对您的版本应用修复。

一个短期的解决方法是像这样替换对 mail() 的调用

 function fix_mail(  $to ,  $subject ,  $message , $additional_headers =NULL,  $additional_parameters=NULL ) {
            $to=filter_var($to, FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES| FILTER_FLAG_STRIP_LOW| FILTER_FLAG_STRIP_HIGH);
            $subject=filter_var($subject, FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES| FILTER_FLAG_STRIP_LOW| FILTER_FLAG_STRIP_HIGH);             
            if (!$additional_headers)
                    return mail(  $to ,  $subject ,  $message );
            if (!$additional_parameters)
                     return mail(  $to ,  $subject ,  $message , $additional_headers );
            return mail(  $to ,  $subject ,  $message , $additional_headers, $additional_parameters );
    }

如果这对任何人有帮助,我正在使用 PHP 5.6 和一个旧的代码点火器 v1 电子邮件库

电子邮件.php:第 1510 行 - 我添加了这个:

     $this->_header_str = str_replace("'r'r","",$this->_header_str);
                    $this->_header_str = str_replace("'r'0","",$this->_header_str);
                    $this->_header_str = str_replace("'r'n'r'n","",$this->_header_str);
                    $this->_header_str = str_replace("'n'n","",$this->_header_str);
                    $this->_header_str = str_replace("'n'0","",$this->_header_str);

在此行上方:

 if ( ! mail($this->_recipients, $this->_subject, $this->_finalbody, $this->_header_str, "-f ".$this->clean_email($this->_headers['Return-Path'])))
                            return FALSE;
                    else
                            return TRUE;

这是成功清理电子邮件标题并解决我收到的错误(与此问题的原始海报相同)

这很可能是有人试图利用您的代码来注入电子邮件标头。

http://resources.infosecinstitute.com/email-injection/

我建议您检查访问日志等并查找异常活动。您收到错误消息的事实希望意味着您的脚本没有受到损害,而是出错了。不过你需要确保。