phpMailer attachment
Asked Answered
B

7

2

I'm using this to attach files to an mail after uploading them to my server:

for ($i = 0; $i <= 2; $i++)
{
    $mail->AddAttachment($locatie.$_FILES['uploaded'.$i]['name'], $_FILES['uploaded'.$i]['name']);
}

Adding attachments is optional, but when the are no files uploaded it gives an error: Could not access file

How can I prevent this error of showing?

Belvia answered 12/6, 2011 at 14:58 Comment(3)
What does $locatie stand for?Landel
@Landel $locatie = 'uploads/';Belvia
Do you move uploaded files into there or are they still within the temporary upload folder?Landel
B
1

I have been able to solve this problem with using an counter:

$locatie = 'uploads/';
$upload_count = -1;

    for ($i = 0; $i <= 2; $i++)
    {
        if($_FILES['uploaded'.$i]['type'] != 'application/octet-stream')  // Geen php files
        {
            $folder = $locatie.basename($_FILES['uploaded'.$i]['name']) ;           
            if(move_uploaded_file($_FILES['uploaded'.$i]['tmp_name'], $folder))
            {
                $upload_count ++;
            }
        }

Loop for the attachment:

for ($i = 0; $i <= $upload_count; $i++)
{
    $mail->AddAttachment($locatie.$_FILES['uploaded'.$i]['name'], $_FILES['uploaded'.$i]['name']);
}
Belvia answered 13/6, 2011 at 9:55 Comment(0)
L
6

See here how to deal with file uploads first:

Handling file uploads

You need to refer to the temporary filename. That's needed to get the actual filename, not only the name of the file.

$_FILES['userfile']['tmp_name']

So access $_FILES['userfile']['name'] for the written filename of the attachment and $_FILES['userfile']['tmp_name'] to specify the actual file (the data) of the upload.

Roughly put into your code, incl. a validation you should do as well to verify it's actually a file-upload:

for ($i = 0; $i <= 2; $i++)
{
    # ignore file that have not been uploaded
    if (empty($_FILES['uploaded'.$i])) continue;

    # get the data of the file
    $fileName = $_FILES['uploaded'.$i]['name'];
    $filePath = $_FILES['uploaded'.$i]['tmpname'];

    # add only if the file is an upload
    is_uploaded_file($filePath) 
      && $mail->AddAttachment($filePath, $fileName)
      ;
}

A word of caution

Your code mixes two jobs with each other. That makes it hard for you to debug and improve - and to take care of things like file/system issues and security.

I suggest you a little different approach: Do one step after the other. In your case namely, 1.) process the file uploads and gather the data you need, 2.) add these attachments.

You can improve the first part by taking a look into the PHP Manual. If you want to support the upload of multiple files, I suggest you orient yourself on the suggestions given in the page Uploading multiple files. Then process the file uploads and form an array that contains the filename on the client computer and the path on the server system per entry.

// see PHP Manual for multi file uploads, this is based on it
$validAttachments = array();
foreach($_FILES['userfile']['name'] as $index => $fileName)
{
    $filePath = $_FILES['userfile']['tmp_name'][$index];
    if(is_uploaded_file($filePath))
    {
        $attachment = new stdClass;
        $attachment->fileName = $fileName;
        $attachment->filePath = $filePath;
        $validAttachments[] = $attachment;
    }        
}

If there is an error already in that part, you know that it's related to the file upload procedure. This is untested code, so just illustrating a direction.

In the second step you can then just iterate over such an array and add the attachments:

foreach($validAttachments as $attachment)
{
    $mail->AddAttachment($attachment->filePath, $attachment->fileName);
}

You can then better check for errors in the different parts without mixing one problem with the other.

Landel answered 12/6, 2011 at 15:7 Comment(4)
I have applied this to my script but it overloads the server. I have added this to my loop in the uploading part: $temp_name.$i = $_FILES['uploaded'.$i]['tmp_name']; and then for the attachment if(is_uploaded_file($temp_name.$i))Belvia
Muiter, do it this way: First rewrite your script for the file upload part. PHP has support for multiple file uploads build in, check the manual how to do that better than you do. Then after you have aquired a list of all valid files (and you have verified the program flow), you can then easily add the attachments.Landel
I added some more example code to better illustrate my last comment. Hopefully this is of use to, I know it's sometimes hard when oneself is stuck into problems.Landel
Good job @hakre, that is an new challenge for me!Belvia
S
1

Before adding an attachment, you should check if the uploaded file exists, e.g. with fopen.

Sweatbox answered 12/6, 2011 at 15:3 Comment(1)
I have tried with if(file_exists($locatie.$_FILES['uploaded'.$i]['name'])) but still the errors.Belvia
C
1

Solution

for ($i = 0; $i <= 2; $i++)
{
    if (file_exists($locatie.$_FILES['uploaded'.$i]['tmp_name'])) {
        $mail->AddAttachment($locatie.$_FILES['uploaded'.$i]['tmp_name'], $_FILES['uploaded'.$i]['name']);
    }
}

Update

You were using $locatie.$_FILES['uploaded'.$i]['name'] instead of $locatie.$_FILES['uploaded'.$i]['tmp_name'] as the file to load. When a file is uploaded it is renamed with a temporary name and placed on the temporary folder. That's where you will get it, and that's why you need to reference it with $locatie.$_FILES['uploaded'.$i]['tmp_name']

Chopper answered 12/6, 2011 at 15:6 Comment(0)
B
1

I have been able to solve this problem with using an counter:

$locatie = 'uploads/';
$upload_count = -1;

    for ($i = 0; $i <= 2; $i++)
    {
        if($_FILES['uploaded'.$i]['type'] != 'application/octet-stream')  // Geen php files
        {
            $folder = $locatie.basename($_FILES['uploaded'.$i]['name']) ;           
            if(move_uploaded_file($_FILES['uploaded'.$i]['tmp_name'], $folder))
            {
                $upload_count ++;
            }
        }

Loop for the attachment:

for ($i = 0; $i <= $upload_count; $i++)
{
    $mail->AddAttachment($locatie.$_FILES['uploaded'.$i]['name'], $_FILES['uploaded'.$i]['name']);
}
Belvia answered 13/6, 2011 at 9:55 Comment(0)
V
0

Agreeing with @patapizza, but before you check on the filesystem (which you should do anyway), you can also just check for $_FILES like

for ($i = 0; $i < count($_FILES); $i++){
    // only iterate over the number of files you actually have
}
Variate answered 12/6, 2011 at 15:6 Comment(4)
What if there is only one file uploaded to be attached.Belvia
I'm sorry I wasn't more precise, but your for loop should obviously only iterate over item's you've got. I'll update the answer accordingly.Variate
Can you update the question and show the complete code you've got so far?Variate
@Variate see the solution I have added in this topic.Belvia
L
0

You need to check if that file was actually uploaded/exists before adding the attachment. Something like

for ($i = 0; $i <= 2; $i++)
{
    if (file_exists($locatie.$_FILES['uploaded'.$i]['tmp_name'])) {
        $mail->AddAttachment($locatie.$_FILES['uploaded'.$i]['tmp_name'], $_FILES['uploaded'.$i]['name']);
    }
}
Luca answered 12/6, 2011 at 15:6 Comment(4)
Look at the hakre answer -- try $locatie.$_FILES['uploaded'.$i]['tmp_name']. I have updated the answer -- please check.Luca
In any case -- have a look at this if you have not done it already.Luca
Sorry, made a mess by editing your answer unintentionally. :/Chopper
@Shef, no worries, below 2000 reputation and your edits go into a suggested edits queue. Even if it was committed, there's always the ability to rollback a post to an earlier version. :)Threephase
E
0

Not sure if this does exactly what you want but this is how I attached multiple uploaded files and kept original filenames from a webform. Error handling/messaging for user will not give error for UPLOAD_ERR_NO_FILE because file uploads were optional fields but still processes each input field in the foreach loop.

foreach ($_FILES["userfile"]["error"] as $key => $error) 
    {
      if ($error == UPLOAD_ERR_OK) {
        $tmp_name = $_FILES["userfile"]["tmp_name"][$key];
        $name = $_FILES["userfile"]["name"][$key];
        $mailer->AddAttachment($tmp_name, $name);
        }

      $name = $_FILES["userfile"]["name"][$key];
      switch($error){
      case UPLOAD_ERR_INI_SIZE: echo $errmsg1.$name.$errmsg2;
break;
      case UPLOAD_ERR_FORM_SIZE: echo $errmsg1.$name.$errmsg2;
break;     
      case UPLOAD_ERR_PARTIAL:  echo $errmsg1.$name.$errmsg2; 
break;
      case UPLOAD_ERR_NO_FILE: 
      break; 
      case UPLOAD_ERR_NO_TMP_DIR: echo $errmsg1.$name.$errmsg2;
break; 
      case UPLOAD_ERR_CANT_WRITE: echo $errmsg1.$name.$errmsg2;
break;
      case UPLOAD_ERR_EXTENSION: echo $errmsg1.$name.$errmsg2;
break;
      } 
}
Endospore answered 25/1, 2013 at 0:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.