ZF-11869: Zend_File_Transfer_Adapter_Abstract::_detectMimeType should not check existence of file by its name

Description

I'm using Zend_File_Transfer to handle POSTed file uploads and ran into a nasty edge case.

Zend_File_Transfer_Adapter_Abstract line 1283 is checking the existence of the posted file by its name parameter before checking its existence by its tmp_name parameter. The problem is that the name parameter is not a path, so it's checking for its existence in the current working directory, which is my application's root directory. In my application's root dir, I have a CMakeLists.txt file. When I tried to upload a file to my application that was also named CMakeLists.txt, I got the following warning:

Warning: finfo_file() [function.finfo-file]: File or path not found 'CMakeLists.txt'

on line 1302 in file C:\xampp\htdocs\Midas3\library\Zend\File\Transfer\Adapter\Abstract.php

file_exists was returning true for the name parameter, which screwed up the rest of the method. Why do you check if the file exists by its name? The tmp_name param is the one that refers to the actual file, it seems to me that's the only one that should be used.

Thanks!

Comments

Your assumption is not correct. Files exist only as "tmp_name" as long as they have not been downloaded. As soon as you download the file only the "name" param can be found.

So it depends on when you call this method... before downloading the file or afterwards. But the method itself does not know if you already downloaded the file or not. Therefor it checks if the given file exists or not to decide which action to use.

Then this is only a bug if we call this method before downloading the file (which is my use case). Is there a precondition on calling receive() that the file must already have been downloaded, or is my use case supposed to be supported?

This is how I call the transfer:

  $upload = new Zend_File_Transfer('HttpFixed');
  $upload->receive();
  $path = $upload->getFileName();
  $filesize =  filesize($path);
  $filename = $upload->getFilename(null, false);

Then, I call a method that copies the posted file into a path corresponding to its md5sum, so no file exists by its original uploaded name.

Ignore the 'HttpFixed', that was my workaround subclass adapter.

In my opinion this can not work.

You are creating a file transfer according to the given $_FILES variable from a form. Then you say "download this files" by calling receive()... but then you say that !afterwards! you copy the file into another path... and the class should know that changed path before you set it???

You eighter set the name and path before you receive the file (with the rename filter) or you set it manually.

The problem is happening in the very first line.

$upload = new Zend_File_Transfer();

It's actually the very first line of my controller.

Everything after that is actually working fine. The only thing failing is the mime type check. The constructor calls _prepareFiles, which is calling _detectMimeType, which is failing because it's checking if the file exists by name (in the current working directory, which is my application root dir) before it checks the existence of the tmp_name file. If we just switched the order of checking that existence, it would actually work for me. To reproduce this bug, just create a minimal zend application, place a dummy.txt file in the root directory of it, create a controller that just calls that one line of code, and then attempt to upload a different file called dummy.txt.

This block of code is the culprit:

protected function _detectMimeType($value) { if (file_exists($value['name'])) { $file = $value['name']; } else if (file_exists($value['tmp_name'])) { $file = $value['tmp_name']; }

I think that is meant to be equivalent to:

if(file_already_moved_from_tmp_name)
      $file= $value['name'];
else if(file_exists($value['tmp_name']))
      $file = $value['tmp_name'];

But they are not equivalent, because file_exists($value['name']) does not represent the condition that the file has already been downloaded; especially since this is happening in the constructor, so we know the file has not already been received.

Any status update on this issue?

Thanks,

-Zach

Are there plans to fix this in the next release?