Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
The error messages in file_unmanaged_copy have been horrible as long as I can remember. They're at their worst when the $destination parameter is omitted (which is probably more often than not.) What is worse is that these error messages are very common for new users who do not know how to set the permissions correctly on the sites/default/files directory, so the very confusing messages cause even more difficulty.
Some example code, with the results as changed by the attached patch:
file_unmanaged_copy("/tmp/bad_file.txt"); // File does not exist
file_unmanaged_copy("/tmp/good_file.txt"); // files directory perms bad
file_unmanaged_copy("/tmp/good_file.txt","/tmp/nonexistent/good_file.txt"); // Nonexistent dir
file_unmanaged_copy("/tmp/good_file.txt", "/tmp/directory_with_bad_perms/good_file.txt");
Old Messages:
* The specified file could not be copied, because no file by that name exists. Please check that you supplied the correct filename.
* The specified file /tmp/good_file.txt could not be copied, because the destination sites/default/files is not properly configured.
* The specified file /tmp/good_file.txt could not be copied, because the destination is not properly configured.
* The specified file /tmp/good_file.txt could not be copied, because the destination /tmp/directory_with_bad_perms/good_file.txt is not properly configured.
New Messages:
* The specified file /tmp/bad_file.txt could not be copied, because no file by that name exists. Please check that you supplied the correct filename
* The specified file /tmp/good_file.txt could not be copied, because the destination sites/default/files is not properly configured. This is often a permissions problem.
* The specified file /tmp/good_file.txt could not be copied, because the destination /tmp/nonexistent/good_file.txt is not properly configured. This is often a permissions problem.
* The specified file /tmp/good_file.txt could not be copied, because the destination /tmp/directory_with_bad_perms/good_file.txt is not properly configured. This is often a permissions problem.
Let's consider this the simplest usability patch we can do!
Comment | File | Size | Author |
---|---|---|---|
#16 | file_unmanaged_copy_error_messages_511760_d7_06.patch | 1.71 KB | rfay |
#14 | file_unmanaged_copy_error_messages_511760_d7_05.patch | 1.7 KB | rfay |
#11 | file_copy_error_message_d6_01.patch | 3.17 KB | rfay |
#7 | file_unmanaged_copy_error_messages_04.patch | 2.56 KB | rfay |
#4 | file_unmanaged_copy_error_messages_03.patch | 2.56 KB | rfay |
Comments
Comment #1
drewish CreditAttribution: drewish commentedi think this would be great but my only concern is renaming the parameters. since we need a copy of the original paths for the error messages i'd suggest making a copy of them at the beginning of the function ($original_source and $original_destination) and letting $source and $destination continue to be modified.
Comment #2
rfayRerolled the patch with parameters unchanged. Thanks for the review.
Comment #3
drewish CreditAttribution: drewish commentedwe typically try to avoid abbreviating so orig should be original. can we avoid adding $proposed_destination and just use $destination?
Comment #4
rfayI changed orig -> original.
However, $destination is reused so often here that something has to be used to keep the state of what we're trying to do so we can report it. Basically, the code always does things like $destination = dosomething($destination), and that's the reason for this.
So I kept $proposed_destination.
Comment #5
Dries CreditAttribution: Dries commentedLooks good to me but it would be great if drewish could sign off on it.
Comment #6
drewish CreditAttribution: drewish commentedthat looks great, i'd be happy with that committed but if i'm nit picking i'd suggest that
!empty($original_destination) ? $original_destination : $proposed_destination))
be changed to:
empty($original_destination) ? $proposed_destination : $original_destination))
Comment #7
rfayYour nitpick is my command.
Comment #8
drewish CreditAttribution: drewish commentedsince dries was happy with it before and the test bot is happy, i think we can call this RTBC.
Comment #9
drewish CreditAttribution: drewish commentedi'd actually consider back porting this to 6 as well.
Comment #10
Dries CreditAttribution: Dries commentedCommitted to CVS HEAD for inclusing in Drupal 7. Updating version and status. Thanks all.
Comment #11
rfayHere is a D6 version of the patch
Comment #12
drewish CreditAttribution: drewish commentedI tested all the changes in this patch by hand and noticed that it was a big improvement in all cases except for this:
This case gives two error messages:
One from file_copy() and one from file_destination(). I'd suggest that we fix the message in file_destination() and replace the message in file_copy() with a comment that file_destination() will take care of the error message.
Comment #13
drewish CreditAttribution: drewish commentedI should have checked this earlier but it's actually still a problem in HEAD too. Bumping this back there for a followup.
Comment #14
rfayHere's a patch to fix the duplicate error messages.
After reviewing where the messages ought to go, I decided that file_destination() was probably not ever intended to emit error messages; it seems to be more of a probing function, returning info to the caller. Also, file_destination did not have adequate information to emit a good message and of course it would have required a signature change to get the info to it. So I removed the error message from file_destination().
There are two (known) callers of file_destination(), file_unmanaged_copy() and file_save_upload(). I fixed the error message in both of the callers.
Comment #15
drewish CreditAttribution: drewish commentedIn file_unmanaged_copy(), going from:
'The specified file %file could not be copied because a file by that name already exists in the destination %directory.'
To:
'The specified file %file could not be copied because a file in the destination already exists. See %directory.'
Seems like a step back. I like the new message in file_save_upload():
'The file %source could not be uploaded because a file by that name already exists in the destination %directory.'
So how about a combo?:
'The file %source could not be copied because a file by that name already exists in the destination %directory.'
Comment #16
rfayOK, I changed that one, with a slight variation on your wording.
The two types of error messages now emitted by this line are:
Comment #17
drewish CreditAttribution: drewish commentedthat seems odd that it's trying to put the file into sites/default/files//tmp/existing_file.txt rather than sites/default/files/existing_file.txt
Comment #18
rfay@drewish, I'm glad you're paying attention.
This is actually at *least* a discrepancy between the documentation of the various functions and their behavior.
file_unmanaged_copy() claims that the destination can be a "string containing the destination that $source should be copied to. This can be a complete file path, a directory path or, if this value is omitted, Drupal's 'files' directory will be used."
However, it calls file_create_path() on the $destination, which returns "A string containing the path to file, with file system directory appended if necessary, or FALSE if the path is invalid (i.e. outside the configured 'files' or temp directories)."
There are a number of problems here:
The call that exposes this line of code is
(both files exist)
I just had a look in the tests, and it appears that there is no test case where the destination directory is outside the system files directory.
Comment #19
rfayI will take a look today and see if this was introduced in D7, or if it's a documentation problem inherited in the code.
Comment #20
rfay@drewish, it turns out you caught a bug with your sharp eye (#17)
#528114: file_unmanaged_copy() will not write into $destination directory; it always goes into system 'files' or 'tmp' directory
Probably we can continue with this one and fix that separately.
Comment #22
rfayLooks like this was the dreaded "Failed to install head"
Comment #23
rfay@drewish, All the issues with this have been resolved - it turned out that it is in fact just an additional error message change. Due to the fact that we discovered another problem/issue (#528114: file_unmanaged_copy() will not write into $destination directory; it always goes into system 'files' or 'tmp' directory) we kind of got derailed. But I'd like to get this one done and get back to D6 and see if we can get that committed. What's your opinion?
Comment #24
drewish CreditAttribution: drewish commentedrfay, yeah i think we should just get this wrapped up in D7 and then backported to D6. the last patch in #16 looks like it's okay by the test bot. lets get this in.
Comment #25
webchickThanks, committed to HEAD.
It looks like this will need a re-roll for 6.x. We normally don't break strings in a stable release, but I see that Dries already marked this for 6.x once.
Comment #26
rfay