I have some web forms that contain several normal fields, and at least one upload field each. Upon submission, the contents of the form are e-mailed to the recipient. When I fill out the form without including a file for upload, it works correctly. I get an e-mail that, when opened, lists the field names and their values, like Field Name: value.

However, if I do include a file for upload, instead of getting an e-mail that contains the normal fields as "Field Name: fieldvalue" along with an attachment for the file I uploaded, I receive a blank e-mail that just contains an attachment. The attachment is always called noname (yes, there is no extension), and it contains the entire contents of the e-mail, including the Field Name: value pairs, and the still-encoded attached file.

I've never written PHP to send attachments with an e-mail before, so I'm not sure where the mistake is. Here is my code:

<?php
    $body = "
<ul>
    <li>Field name: value</li>
    <li>Field name: value</li>
</ul>
<!-- etc. -->
";

$hasFile = false;
// check if $_FILES superglobal has content
if( isset($_FILES['claim_upload']['tmp_name']) && !empty($_FILES['claim_upload']['tmp_name']) ) {
    $fileatt = $_FILES['claim_upload']['tmp_name'];     // get file's temp name
    $fileatt_type = $_FILES['claim_upload']['type'];    // get file's type
    $fileatt_name = $_FILES['claim_upload']['name'];    // get file's name
    if( is_uploaded_file($fileatt) ) {                  // check if file was uploaded
        $file = fopen($fileatt,'rb');                   // open file, read content, close
        $fileatt_data = fread( $file, filesize($fileatt) );
        fclose($file);
        $hasFile = true;                                // we have an uploaded file
    }
}

/*** Set up e-mail ***/
$to = "email@email.email";
$subject = "My Email Form";
$headers  = 'MIME-Version: 1.0' . "\n";

if($hasFile) {  
    $boundary_rand = md5(time());
    $mime_boundary = "==Multipart_Boundary_x{$boundary_rand}x";
    $body = "--".$mime_boundary
            ."\nContent-Type: text/plain;"
            ."charset=\"iso-8859-1\"\n"
            ."Content-Transfer-Encoding: 7bit\n\n"
            .$body."\n\n";
    $fileatt_data = chunk_split( base64_encode($fileatt_data) );
    $body .= "--{$mime_boundary}\n"
            ."Content-Type: {$fileatt_type};\n"
            ."name=\"{$fileatt_name}\"\n"
            ."Content-Disposition: attachment;\n"
            ." filename=\"{$fileatt_name}\"\n"
            ."Content-Transfer-Encoding: base64\n\n"
            .$fileatt_data."\n\n"
            ."--{$mime_boundary}--\n";
    $headers .= 'Content-type: multipart/mixed; \n boundary="'.$mime_boundary.'"\n';
} else
    $headers .= 'Content-type: text/html; charset=iso-8859-1' . "\r\n";

$headers .= "From: senderemail@email.email"."\r\n";

mail($to, $subject, $body, $headers);
?>
Member Avatar for diafol

Show your form code.

Hi

You are splitting your headerlines where it is not allowed:

> ."Content-Type: {$fileatt_type};\n"
                                                   ^^
>             ."name=\"{$fileatt_name}\"\n"
>             ."Content-Disposition: attachment;\n"
                                                                    ^^
>             ." filename=\"{$fileatt_name}\"\n"

Change to:

 ."Content-Type: {$fileatt_type}; name=\"{$fileatt_name}\"\n"
 ."Content-Disposition: attachment; filename=\"{$fileatt_name}\"\n"

Further

    > .$fileatt_data."\n\n"
                                 ^^
    >             ."--{$mime_boundary}--\n";

    try removing a "\n":



   .$fileatt_data."\n"
   ."--{$mime_boundary}--\n";

---- The code below works for me:

$to = "you@example.com";
$subject = "My Email Form";
$headers  = 'MIME-Version: 1.0' . "\n";
$headers .= "From: me@example.com"."\n";
if($hasFile) {
    $boundary_rand = md5(time());
    $mime_boundary = "==Multipart_Boundary_x{$boundary_rand}x";

    $headers .= 'Content-type: multipart/mixed; boundary="'.$mime_boundary.'"\n';
    $body = "--".$mime_boundary."\n"
            ."Content-Type: text/plain;"
            ."charset=\"iso-8859-1\"\n"
            ."Content-Transfer-Encoding: 7bit\n\n"
            .$body."\n\n";

    $body .= "--{$mime_boundary}\n"
            ."Content-Type: {$fileatt_type}; name=\"{$fileatt_name}\"\n"
            ."Content-Disposition: attachment; "
            ." filename=\"{$fileatt_name}\"\n"
            ."Content-Transfer-Encoding: base64\n\n"
            .$fileatt_data."\n"
            ."--{$mime_boundary}--";
commented: Got me pointed in the right direction, thanks! +4

Hi diafol,
I can certainly include form code, but I don't believe it's relevant. I've checked my form vars on the processing page and everything is coming through correctly. I will try dpste123's suggestion, if that doesn't work I will put up form code.

Hi dpste123,
I noticed you left out the chunk_split part. Is it not necessary?

Sorry, that's an error. It is necessary. I've moved the line out of the message composition, to get a clearer view.

OK I spent the past hour working on it, finally got it! Your advice helped, dpste123, but the e-mail was still just showing a jumble of characters and no attachment. There was one other issue that took me a while to pin down. I noticed when I looked at the original e-mail headers from Gmail:
Content-type: multipart/mixed; boundary="==Multipart_Boundary_x566fc481ca3d228140c753d3107c99b5x"\n
That \n at the end of course shouldn't be there, I don't know why it was popping up. For some reason, it wasn't getting escaped. In any case, I changed line 9 of your code to the following, and it worked like a charm!
$headers .= "Content-type: multipart/mixed; boundary=\"".$mime_boundary."\"\n";
I also modified the Content-Type on line 11 to text/html to format it correctly. Thanks a bunch for the help!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.