zend-frameworkfile-uploadzend-file

Zend_File_Transfer w/multiple files does not upload equally


Weird title, yes, but the problem is simple; simply aggrevating. I have a form, that I built without using Zend_Form, and it has two file uploads:

<input name="image" type="file" />
<input name="file" type="file" />

Here is the chunk of code from my controller that is handling the upload. There's actually a little more, but this is the relevant piece:

$data['image'] = (isset($_FILES["image"]) && $_FILES["image"]["name"] ? $_FILES["image"]["name"] : NULL);
$data['file'] = (isset($_FILES["file"]) && $_FILES["file"]["name"] ? $_FILES["file"]["name"] : NULL);

$options = array('ignoreNoFile' => TRUE);
$upload = new Zend_File_Transfer();

$upload->setOptions($options)
       ->addFilter('Rename', array('target' => RESOURCES_IMG . $data['image'], 'overwrite' => TRUE), 'image')
       ->addFilter('Rename', array('target' => RESOURCES_FILES . $data['file'], 'overwrite' => TRUE), 'file')
       ->addValidator('ImageSize', false, array('minwidth'  => 100,
                                                'maxwidth'  => 100,
                                                'minheight' => 100,
                                                'maxheight' => 100), 'image')
       ->addValidator('Extension', false, 'jpg', 'image');

if (!$upload->isValid())
{
 echo '<h1>Oops</h1><p>Please correct the following errors: <hr /></p>';

 foreach ($upload->getMessages() as $key => $val)
 {
  echo '<p><strong>' . $key . '</strong><br />' . $val . '</p>';
 }
 die;
}
else
{
 $upload->receive();
} // if (!$upload->isValid())

It's pretty straight forward. The $data stuff is just me grabbing the filename if it's there or setting the variable to NULL. I have my addFilter() and addValidator() segmented out to only affect their relevant files in this case "image" or "file" - the names of the form fields.

The "file" upload always works! However, the "image" upload doesn't and what's more it puts the temporary file into the RESOURCES_FILES directory which makes no sense at all. So that directory has PDFs and whatever else in addition to files like php8TJT13, phpXmOzQM, etc.

I have been staring at this code and searching through Stack Overflow and whatever Google will turn up and I can't find anyone having this problem. Help!


Solution

  • Alright, so I did more digging and it turns out there may be an issue with the way I was chaining addFilter() so I decided to move in a different direction, trying to isolate each file and handle it's upload individually. So far it appears to be working. Here is the revised code:

    $data['image'] = (isset($_FILES["image"]) && $_FILES["image"]["name"] ? $_FILES["image"]["name"] : NULL);
    $data['file'] = (isset($_FILES["file"]) && $_FILES["file"]["name"] ? $_FILES["file"]["name"] : NULL);
    
    $upload = new Zend_File_Transfer();
    
    $files = $upload->getFileInfo();
    
    $options = array('ignoreNoFile' => TRUE);
    $upload->setOptions($options);
    
    foreach ($files as $field => $contents)
    {
     if(!strlen($contents["name"]))
     {
      continue;
     }
    
     // upload instructions for image
     if ($field == 'image')
     {
      $upload->addFilter('Rename', array('target' => RESOURCES_IMG . $data['image'], 'overwrite' => TRUE), 'image')
             ->addValidator('ImageSize', false, array('minwidth'  => 100,
                                                      'maxwidth'  => 100,
                                                      'minheight' => 100,
                                                      'maxheight' => 100), 'image')
             ->addValidator('Extension', false, 'jpg', 'image');
     }
    
     // upload instructions for file
     if ($field == 'file')
     {
      $upload->addFilter('Rename', array('target' => RESOURCES_FILES . $data['file'], 'overwrite' => TRUE), 'file');
     }
    
     if(!$upload->receive($field)) {
      echo '<h1>Oops</h1><p>Please correct the following errors: <hr /></p>';
    
      foreach ($upload->getMessages() as $key => $val)
      {
       echo '<p><strong>' . $key . '</strong><br />' . $val . '</p>';
      }
      die;
      //return;
     }
    } // foreach
    

    Pseudo Explanation

    I use the getFileInfo() to grab an array of the files available to me then I loop over each. At the beginning of my first for loop I check to see if this file has a name, if it doesn't have a name I assume that field was left blank and is NULL so I tell the loop to skip over that and continue.

    Once I'm in the loop I'm just matching my upload directives with the appropriate form field using a simple conditional. The rest should be fairly self-explanatory if you're into Zend stuff.

    Hopefully this helps someone else that was in my predicament. If you are a Zend guru maybe you can comment on my solution or fix the bug that's causing the issue. There may be a more "Zend" way of doing it, but it's working now and that feels damn good.

    References

    Why I thought it was the chaining of the addFilter() method, see the note under Example #3 (below):

    Note: Note that even though setting the same filter multiple times is allowed, doing so can lead to issues when using different options for the same filter.

    http://framework.zend.com/manual/1.11/en/zend.file.transfer.filters.html

    A random blog article that inspired me to try isolating each, I'm calling it, "upload directive" although I'm not sure if that's what it's called:

    http://www.pc-freak.net/blog/tag/uploading-multiple-files-from-a-form-with-zend-framework-zf-storing-uploaded-zf-files-with-unique-name/