Hi,

I'm in the process of converting the Avatar Selection module to Drupal 6.x. In it I want to use the file_save_upload() function but I'm having problems with the $dest parameter. The api documentation says:

file_save_upload($source, $validators = array(), $dest = FALSE, $replace = FILE_EXISTS_RENAME)
....
$dest A string containing the directory $source should be copied to. If this is not provided, the temporary directory will be used.

To me this sounds like I can set the $dest variable to be a path to a directory, so my code is :

$dest_dir = file_create_path('avatar_selection');
$validators = array(
  'file_validate_is_image' => array(),
  'file_validate_image_resolution' => array(variable_get('user_picture_dimensions', '85x85')),
  'file_validate_size' => array(variable_get('user_picture_file_size', '30') * 1024),
);

$file = file_save_upload('picture_upload', $validators, $dest_dir, FILE_EXISTS_RENAME);

However, this gives me the following errors:

* warning: move_uploaded_file(files/travel-with-me.eu/avatar_selection) [function.move-uploaded-file]: failed to open stream: Is a directory in /var/www/drupal_6.1_20070904/html/includes/file.inc on line 570.
* warning: move_uploaded_file() [function.move-uploaded-file]: Unable to move '/tmp/phpcaqh3S' to 'files/travel-with-me.eu/avatar_selection' in /var/www/drupal_6.1_20070904/html/includes/file.inc on line 570.
* File upload error. Could not move uploaded file.

I think this is because the move_uploaded_file() expects its destination param to be the path to a file, not a directory. The file_save_upload() function doesn't modify the dest param if it's already set and so this function only works if (a) no destination param is provided or (b) if the destination provided is a file, not a directory.

Whichever way you look at it, this is a bug. Either the file_save_upload() function should be changed so it can update the destination to be a path to the file (based on supplied $dest) or the documentation should be updated so it correctly defines the $dest param.

Cheers,
Stella

Comments

drewish’s picture

good point... i want to look around at how it's used before i want to weigh in on fixing the code or the docs.

stella’s picture

+1 for changing the code

Look at the way it's implemented by user.module (user_validate_picture() func). It calls file_save_upload() without a destination param. This causes the file to be saved to e.g. "files/picture-1.gif". The user module then has to make another call, this time to file_copy() to copy the file to "files/pictures/". This results in there being two copies of the same file, one in the "files/" directory the other in "files/pictures/".

One of the comments at this section of code says "The image was saved using file_save_upload() and was added to the files table as a temporary file. We'll make a copy and let the garbage collector delete the original upload." Does the garbage collector really delete uploaded files from the files directory? How does it know that the file was copied to the "files/pictures/" directory? What if other modules just put their uploaded files in the "files/" directory and not in a subdirectory - will they get deleted? Maybe the user module should be using file_move() instead, but it seems like a needless step if file_save_upload() could save the file to where you want it in the first place.

Just my two cents.

Cheers,
Stella

drewish’s picture

i think it's best to provide a directory rather than a filename.

snpower, in the example you point of the user.module it wouldn't work providing a filename because you don't know the correct extension until you've had a chance to examine the file. so you don't know if it should be picture-1.gif or picture-1.jpg.

and to answer your question about the cron deletion, yes it does delete the temporary file because its path is saved in the database.

drewish’s picture

Status: Active » Needs review
StatusFileSize
new3.08 KB

okay, this puts the PHPDoc comments in the right order and brings the code into line with them.

stella’s picture

I applied the patch to my system and used a call to file_save_upload() with the $dest param set to a directory and it worked perfectly.

Thanks!
Stella

drewish’s picture

cool well if we can get some more testing of the rest of core's uploads i think it'll be RTBC.

drewish’s picture

marked http://drupal.org/node/176876 as a duplicate

drewish’s picture

Priority: Normal » Critical

chx, wanted me to bump this to critical

jakeg’s picture

As per the duplicate of this thread, 'temporary files are not stored in temporary directory' due to this bug. I'd consider this a beta-2 blocker ( http://drupal.org/node/176876 )

drewish’s picture

jakeg, could you review this so we can get some RTBC action going?

drewish’s picture

Status: Needs review » Reviewed & tested by the community

I hate RTBCing my own patch but since the bug came from one of patches.

gábor hojtsy’s picture

Status: Reviewed & tested by the community » Needs review

I did no test the patch yet, but the comment is still not in line with how it works. If you provide a directory, but it is not writable, it falls back to the temp folder, which is not documented.

I think this needs some testing with the core upload forms.

drewish’s picture

StatusFileSize
new0 bytes

Gábor, this fixes the documentation. what sort of testing did you have in mind?

drewish’s picture

StatusFileSize
new1.01 KB

humm, that didn't seem to work.

DrupalTestbedBot tested drewish's patch (http://drupal.org/files/issues/file_172943.patch), the patch passed. For more information visit http://testing.drupal.org/node/102

DrupalTestbedBot tested drewish's patch (http://drupal.org/files/issues/file_172943_0.patch), the patch passed. For more information visit http://testing.drupal.org/node/103

dries’s picture

drewish: can you create one patch instead of two patches?

drewish’s picture

StatusFileSize
new3.13 KB

whoops, sorry. i guess the first patch didn't apply before i made the change for the second. that's why you shouldn't patch in a hurry ;)

chx’s picture

Status: Needs review » Reviewed & tested by the community

Docs seem to be in order and functionality was tested in #5.

gábor hojtsy’s picture

Status: Reviewed & tested by the community » Fixed

Looks good, thanks, committed.

Anonymous’s picture

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for two weeks with no activity.