未发送PHP邮件图像附件


PHP Mail Image attachment not being sent

需要明确的是,我没有写这段代码,这是以前的开发人员写的。无论如何,我的客户在通过他们的表单上传时没有收到图像,只是一个带有错误消息的红框。

根据请求,这里是完整的代码:

<?php
function sendMail() {
  if (!isset ($_POST['to_email'])) { //Oops, forgot your email addy!
    die ("<p>Oops!  You forgot to fill out the email address! Click on the back arrow to go back</p>");
  }
  else {
    $to_name = stripslashes($_POST['to_name']);
    $from_name = stripslashes($_POST['from_name']);
    $from_telephone = stripslashes($_POST['from_telephone']);
    $subject = stripslashes($_POST['subject']);
    $body = stripslashes($_POST['body']);
    $address = stripslashes($_POST['address']);
    $to_email = $_POST['to_email'];
    $attachment = $_FILES['attachment']['tmp_name'];
    $attachment_name = $_FILES['attachment']['name']; 
    if (is_uploaded_file($attachment)) { //Do we have a file uploaded?
      $fp = fopen($attachment, "rb"); //Open it
      $data = fread($fp, filesize($attachment)); //Read it
      $data = chunk_split(base64_encode($data)); //Chunk it up and encode it as base64 so it can emailed
      fclose($fp);
    }
    //Let's start our headers
    $headers = "From: $from_name<" . $_POST['from_email'] . ">'n";
    $headers .= "Reply-To: <" . $_POST['from_email'] . ">'n"; 
    $headers .= "MIME-Version: 1.0'n";
    $headers .= "Content-Type: multipart/related; type='"multipart/alternative'"; boundary='"----=MIME_BOUNDRY_main_message'"'n"; 
    $headers .= "X-Sender: $from_name<" . $_POST['from_email'] . ">'n";
    $headers .= "X-Mailer: PHP4'n";
    $headers .= "X-Priority: 3'n"; //1 = Urgent, 3 = Normal
    $headers .= "Return-Path: <" . $_POST['from_email'] . ">'n"; 
    $headers .= "This is a multi-part message in MIME format.'n";
    $headers .= "------=MIME_BOUNDRY_main_message 'n"; 
    $headers .= "Content-Type: multipart/alternative; boundary='"----=MIME_BOUNDRY_message_parts'"'n"; 
    $message = "------=MIME_BOUNDRY_message_parts'n";
    $message .= "Content-Type: text/plain; charset='"iso-8859-1'"'n"; 
    $message .= "Content-Transfer-Encoding: quoted-printable'n"; 
    $message .= "'n"; 
    /* Add our message, in this case it's plain text.  You could also add HTML by changing the Content-Type to text/html */
    $message .= "Return call on: $from_telephone'n'n";
    $message .= "$address'n'n";
    $message .= "$body'n";
    $message .= "'n"; 
    $message .= "------=MIME_BOUNDRY_message_parts--'n"; 
    $message .= "'n"; 
    $message .= "------=MIME_BOUNDRY_main_message'n"; 
    $message .= "Content-Type: application/octet-stream;'n'tname='"" . $attachment_name . "'"'n";
    $message .= "Content-Transfer-Encoding: base64'n";
    $message .= "Content-Disposition: attachment;'n'tfilename='"" . $attachment_name . "'"'n'n";
    $message .= $data; //The base64 encoded message
    $message .= "'n"; 
    $message .= "------=MIME_BOUNDRY_main_message--'n"; 
    // send the message
    mail("$to_name<$to_email>", $subject, $message, $headers); 
    print "<p align='"center'">Thank you for your email.</p>";
  }
}
switch ($action) {
  case "send":
    showForm();
    sendMail();
    break;
  default:
    showForm();
}
?>

我完全被这段代码弄糊涂了,因为我没有写它,也无法解密为什么"$attachment_name"answers"$attachement_name"是单独的字符串,如果我把"attachmentname"改为"attachment",我的问题会得到解决吗?

您的代码似乎对我有效,但也存在一些潜在的问题。我认为最重要的一点可能是图像是使用不正确的Content-Type:发送的,但下面还详细介绍了一些其他问题。

图像类型

$message .= "Content-Type: application/octet-stream;'n'tname='"" . $attachment_name . "'"'n";

当没有合适的内容类型或内容类型未知时,application/octet-stream被用作发送任意二进制数据的最后手段。您应该使用正确的图像类型:

$message .= "Content-Type: " . $_FILES['attachement']['type']
            . ";'n'tname='"" . $attachment_name . "'"'n";

如果你想防止用户邮寄任意文件,你可以使用白名单:

if (is_uploaded_file($attachment) &&
    in_array ($attachment_type, array ('image/gif', 'image/png', 'image/jpg', 'image/jpeg'))) {
  $fp = fopen($attachment, "rb"); //Open it
  $data = fread($fp, filesize($attachment)); //Read it
  $data = chunk_split(base64_encode($data)); //Chunk it up and encode it as base64 so it can emailed
  fclose ($fp); 
} else {
  echo "<p>Useful error message'n";
  exit;
}

MIME语法

$headers .= "X-Priority: 3'n"; //1 = Urgent, 3 = Normal
$headers .= "Return-Path: <" . $_POST['from_email'] . ">'n"; 
$headers .= "This is a multi-part message in MIME format.'n";

Return-Path:是您的最后一个标头。下一行是消息正文的一部分。您需要一个空行来分隔邮件正文和邮件头。例如:

$headers .= "Return-Path: <" . $_POST['from_email'] . ">'n"; 
$headers .= "'n";
$headers .= "This is a multi-part message in MIME format.'n";

就我个人而言,我会将消息正文添加到$message中。mail()函数并不在意,它只是用换行符连接头和消息。请参阅下面关于行尾的更多信息。


$headers .= "------=MIME_BOUNDRY_main_message 'n"; 
$headers .= "Content-Type: multipart/alternative; boundary='"----=MIME_BOUNDRY_message_parts'"'n"; 
$message = "------=MIME_BOUNDRY_message_parts'n";

请注意,如果确实将上面的一些行移动到$message,则需要在Content-Type:标头之后插入一个额外的换行符。


$attachment = $_FILES['attachment']['tmp_name'];
$attachment_name = $_FILES['attachment']['name']; 
...
$message .= "Content-Disposition: attachment;'n'tfilename='"" . $attachment_name . "'"'n'n";

$attachment_name由浏览器发送,通常是用户上传的文件的原始名称。$attachment是将图像存储在服务器上的临时文件的名称。两者完全不同,不能互换。

您可能希望从这些变量中去掉控制字符(如换行符)和双引号,以防止恶意用户破坏标头的语法。

行尾

根据Mail语法,行应该以CRLF"'r'n")序列结尾,但不清楚在调用mail()函数时应该使用哪一行结尾。PHP文档中写道:

如果未收到消息,请尝试仅使用LF'n)。一些Unix邮件传输代理(最著名的是»qmail)会自动将LF替换为CRLF(如果使用CRLF,则会导致CR加倍)。这应该是最后的手段,因为它不符合»RFC 2822。

$_POST[]数据

您不应该在邮件头中使用来自$_POST[]的原始数据。恶意用户可以很容易地插入自己的标头(如Bcc:),将垃圾邮件发送到任意地址。您至少应该过滤掉控制字符(如换行符),还可以根据使用情况过滤或转义尖括号和双引号。