PHP电子邮件附件的问题

I have this PHP code which sends an email with an attachment along with form values that get passed through (I removed this section to make it easier to read). The code works but it submits a blank text file as an attachment if the user does not select an attachment.

Is there any way to have it just not attach anything if no attachment is selected?

php:

<?php

//if there is post
if(isset($_POST) && !empty($_POST) ) {
  // if thre is an attachment
  $_FILES['attachment']['name'];
  // store some variables
  $file_name = $_FILES['attachment']['name'];
  $temp_name = $_FILES['attachment']['tmp_name'];
  $file_type = $_FILES['attachment']['type'];

  // get the extension of the file
  $base = basename($file_name);
  $extension = substr($base, strlen($base)-4, strlen($base));

  // only allow these file types
  $allowed_extensions = array(".doc", "docx", ".pdf", ".zip", ".csv", ".xls", "xlsx", "");

  // check that this file type is allowed
  if(in_array($extension,$allowed_extensions)) {

    // mail essentials
    $from = $_POST['email'];

    // multiple recipients
    $to  = 'email@email.com,'.$_POST['email'];

    // subject
    $today_day=date("d") ;
    $today_month=date("m") ;
    $today_year=date("Y") ;

    $subject = 'Confirmation: '
             . " Date and Time: ".$_POST['ScheduledMonth']."/".$_POST['ScheduledDay']."/". $_POST['ScheduledYear']
             . ' at '. $_POST['ScheduledHour'].":".$_POST['ScheduledMin']." ".$_POST['AMPM']." ".$_POST['TimeZone'];

    // message
    $message = 'HTML message goes here';

    // things you need
    $file = $temp_name;
    $content = chunk_split(base64_encode(file_get_contents($file)));
    $uid = md5(uniqid(time()));

    //standard mail headers
    $header = "From: ".$from."
";
    $header .= "Reply-To: ".$replyto."
";
    $header .= "MIME-Version: 1.0
";

    // declaring we have multiple parts of email (i.e plain text and attachment)
    $header .= "Content-Type: multipart/mixed; boundary=\"".$uid."\"

";
    $header .= "This is a multi-part message in MIME format.
";

    // text part
    $header .= "--".$uid."
";
    $header .= 'Content-type: text/html; charset=iso-8859-1' . "
";
    $header .= "Content-Transfer-Encoding: 7bit

";
    $header .= $message."

";

    // file attachment
    $header .= "--".$uid."
";
    $header .= "Content-Type: ".$file_type."; name=\"".$file_name."\"
";
    $header .= "Content-Transfer-Encoding: base64
";
    $header .= "Content-Disposition: attachment filename=\"".$file_name."\"

";
    $header .= $content."

";

    //send the mail
    if (mail($to, $subject, "", $header)) {
      //redirect to the thank you page
      header('Location: http://www.somesite.com/thankyou.php');
    } else {
      echo "Fail";
    }

  } else {
    echo "file type not allowed";
  }

}
?>

Answer

You propably should use an email library as was mentioned in one of the comments, but if you must use mail(), your code should look something like this:

//standard mail headers
$header  = "From: $from
";
$header .= "Reply-To: $replyto
";
$header .= "MIME-Version: 1.0
";
$header .= "Content-Type: multipart/mixed; boundary=\"$uid\"

";

Stop right there! The double line-break () marks the end of the headers. I don't know if mail() allows you to send the body like this. Perhaps it does, but the rest of your message should go inside the message body.

You're also missing a close-delimiter. See the MIME syntax section below.

$body  = "This is a multi-part message in MIME format.
";

// text part
$body .= "--$uid
"; // dash-boundary
$body .= "Content-type: text/html; charset=iso-8859-1
";
$body .= "Content-Transfer-Encoding: 7bit

";
$body .= $message;

// file attachment
if (isset ($FILES['attachment'])) {
  $file_name = $_FILES['attachment']['name'];
  $temp_name = $_FILES['attachment']['tmp_name'];
  $file_type = $_FILES['attachment']['type'];
  $body .= "
--$uid
"; // delimiter
  $body .= "Content-Type: $file_type; name=\"$file_name\"
";
  $body .= "Content-Transfer-Encoding: base64
";
  $body .= "Content-Disposition: attachment filename=\"$file_name\"

";
  $body .= $content;
}
$body .= "
--$uid--
"; // close-delimiter

//send the mail
if (mail($to, $subject, $body, $header)) {
  /* ... */

Additional notes

$from = $_POST['email'];
$to  = 'email@email.com,'.$_POST['email'];

$header = "From: ".$from."
";
$header .= "Reply-To: ".$replyto."
";

if (mail($to, $subject, "", $header)) {

The code above allows the user to send spam or other unwanted email to arbitrary addresses, both through the $to variable and through the $from variable (by inserting line-breaks and a Bcc: header or similar). You should remove $_POST['email'] from $to, and strip out line-breaks from $from. I don't know about your Reply-To: header; $replyto is undefined.


// if thre is an attachment
$_FILES['attachment']['name'];

This code does nothing (except perhaps generate a notice if there is no attachment).


$extension = substr($base, strlen($base)-4, strlen($base));

This can be simplified as:

$extension = substr($base, -4);

MIME Syntax

This is an excerpt of what the structure of a multi-part message body looks like according to RFC 2046. (BNF syntax, somewhat simplified.)

multipart-body := [preamble CRLF]
                  dash-boundary CRLF
                  body-part *encapsulation
                  close-delimiter
                  [CRLF epilogue]

dash-boundary := "--" boundary

body-part := MIME-part-headers [CRLF *OCTET]

encapsulation := delimiter
                 CRLF body-part

delimiter := CRLF dash-boundary

close-delimiter := delimiter "--"

References