I get this error when uploading a file through the file api, and the upload fails:
warning: open_basedir restriction in effect. File is in wrong directory in...
This happens when open_basedir restriction is activated and the temporary directory is not in the allowed directories. There's a related bug in the profile.module: http://drupal.org/node/view/2648
FIX:
The solution is to upload files using php's 'move_uploaded_file' -which works even when open_basedir restriction is in effect.
This patch checks for the error conditions in 'file.inc::file_check_upload', and then uses move_uploaded_file to upload the file to the temporary folder with a random name. Otherwise -if the error conditions are not met-, does nothing.
RESTRICTIONS:
This patch introduces one additional restriction for the file api: Once you have called 'file_check_upload', you have to use the returned object when calling later 'file.api::file_save_upload'.
This shouldn't be a problem, as the right way to upload files should be -I think, please correct me if I'm wrong-:
- $file=file_check_upload();
- (Perform validations with $file)
- file_save_upload($file,.....)
I will post also a very simple patch for profile.module to work with this one.
Anyway, as mentioned above, if the error conditions are not met, the patch does nothing, so I think it should be applied first and then check for other modules (profile.module) to use the file api the right way and then be able to upload files when open_basedir restriction in effect.
Comment | File | Size | Author |
---|---|---|---|
#57 | 5961_constants.patch | 1.51 KB | dopry |
#52 | 5961_6.patch | 6.91 KB | dopry |
#50 | 5961_5.patch | 6.84 KB | dopry |
#49 | 5961_4.patch | 6.86 KB | dopry |
#46 | 5961_3.patch | 6.84 KB | dopry |
Comments
Comment #1
Junyor CreditAttribution: Junyor commentedComment #2
Gábor HojtsyThis seems to be an interesting alternate fix to my dump patch for locale.module, which is the very same issue... Moving the file out of the upload folder right away to the Drupal temp folder seems to be a good idea to me. The only caveat is that files in the upload folder get removed automatically, while one needs to remove the file from the Drupal temp folder, once it is not needed anymore!
Comment #3
Gábor HojtsyPlease look at this stuff. We need to solve open_basedir problems at least in core before the next point release. There are quite a few users trying to use Drupal on shared hosting here, where open_basedir is in effect.
Comment #4
ezheidtmann CreditAttribution: ezheidtmann commentedThis functionality gets a +1 from me, the user. We solved this problem by changing upload_tmp_dir in the server config, but a fix in Drupal would be more elegant.
Comment #5
killes@www.drop.org CreditAttribution: killes@www.drop.org commentedDoesn't apply anymore.
Comment #6
Jose Reyero CreditAttribution: Jose Reyero commentedJust resubmitted the patch.
The problem is, from the time I sent the first patch , I've moved all my sites, no shared webhosting anymore, so I don't have that upload trouble anymore, and also cannot test it myself. That's also why I'm unassigning this issue to me.
So please, somebody else test it.
Comment #7
mpd CreditAttribution: mpd commentedI gave your patch a try. It applies fine but doesn't address several issues, particularily with the image module.
The attached patch makes attachments work, along with image (from cvs). I haven't seen any ill effects yet, but I believe that file_delete must be used to avoid getting a build-up of dead files in the local temporary directory (set to getcwd().'/tmp'). This isn't a problem with my install, but it might be a problem with other modules.
In order for the patched code to work, $drupal/tmp must exist and be writable by the web server.
Comment #8
nedjo+1 for Jose's patch
(I've attached an updated version, which I've tested successfully. The new version uses $file->filepath rather than $file->path and cleans up the code a bit.)
While the larger patch suggested may have merit, I don't fully follow it (not knowing what the image module issues are). I'd like to see the identified problem fixed first, and quickly. Later cleanup and further patches can follow.
This is a significant issue, meaning many in hosted environments can't use Drupal's file uploading. This has come up at least twice in the help forums. Jose's solution is simple. Let's apply it!
This same changes work for 4.6.
Comment #9
mpd CreditAttribution: mpd commentedI'll describe the issue that I found with file.inc concerning image.module.
From what I've seen, image.module calls file_copy() directly from _image_insert(). file_copy() doesn't call file_check_upload(), so the open_basedir problem remains because file_copy() attempts to access the file while it's still in the restricted directory. I'm sure that there's a cleaner way to do it, but the patch that I submitted does the trick for my purposes by addressing problems with both file_copy() and file_check_upload().
I'll have a go at making a smaller patch that only addresses the issue with file_copy(), since Nedjo's patch neatly fixes file_check_upload().
Comment #10
nedjoIt seems likely that the image module issue - with using file_copy() directly - can be addressed by adding a file_check_upload() call in the file_copy() function by changing
to
I can't immediately test this. Do you want to, mpd?
Comment #11
Jose Reyero CreditAttribution: Jose Reyero commentedI wanted to forget about this but the patch bingo keeps bringing me here :-( , so...
I've enabled open_basedir, tested nedjo's revised patch, which still applies and it actually fixes the problem.
Sure there can be other solutions -like reworking the whole file api- but this one works and is simple enough and it only does something when the error conditions are met.
On top of that, the current file api fails to produce an error when this problem occurs, it just doesnt work without any clue of what is happening, which is really bad.
So please apply this one.
+ 1
Comment #12
Gábor HojtsyThis needs to get fixed for Drupal 4.7, or otherwise Drupal is not "hosted environment friendly". People cannot even start with importing a translation with open_basedir restrictions (which is quite common here in Hungary, because of security precautions).
Comment #13
joshricker CreditAttribution: joshricker commentedHow is it that I use this patch. There isn't very much code compared to the original file. Do i copy/paste over just a part of the text in the original file?
thanks!
Comment #14
banesto CreditAttribution: banesto commentedcan somebody explain how to apply this patch?
Comment #15
egfrith CreditAttribution: egfrith commented+1 for me too.
The only thing I would add would be to warn about files exceeding the PHP UPLOAD_ERR_INI_SIZE. Something like
else {
if ($_FILES["edit"]["error"][$source] == UPLOAD_ERR_INI_SIZE) {
print "The uploaded file exceeds the upload_max_filesize directive (".ini_get("upload_max_filesize").") in php.ini.";
}
// In case of previews return previous file object.
if (file_exists($_SESSION['file_uploads'][$source]->filepath)) {
return $_SESSION['file_uploads'][$source];
}
}
in the final clause of file_check_upload(). I don't know what the proper way of doing drupal error messages is, otherwise I would submit a patch.
Comment #16
Gábor HojtsyOur Hungarian users are coming in crowds because they cannot upload the translation on hosted environments. This is a mission critical patch IMHO, and it needs to get into 4.7.0. See the comments from those, who already tested, and test the patch if possible.
Comment #17
eTech CreditAttribution: eTech commentedSame problem here in Belgium, we need Dutch & French translations.
Comment #18
Gábor HojtsyOk, here I come. I said this is important, and since the guys who previously worked on it (Jose and Nedjo) are not following the route, I have set up a testing environment with a very restrictive open_basedir setting. I took Nedjo's latest patch and moved the code to the proper place and made some small modifications.
The problem with the current file API is that it thinks that the location where the file was uploaded is safe to work with (read from, write to). However, on most hosted environments, this is not the case, as open_basedir does not let you to tinker with folders outside of the allowed ones. The most useful function here is move_uploaded_file, which allows you to move stuff from the upload folder to a folder under the open_basedir umbrella. So before doing any tinkering with an uploaded file, if we smell open_basedir, we should move the file. The attached patch does just this.
Things to note:
This is a critical issue, and needs to be fixed. I tested this extensively tonight on Drupal HEAD with the locale import form on an open_basedir limited environment and it seems to be working just fine.
Comment #19
Gábor HojtsyAdditionaly to the locale import, I also tested the patch with the upload module (with AJAX file uploads and without AJAX file uploads with preview submits). It works perfectly. Before submitting the node the files are saved properly in the temp folder (with their readable names), after submitting the node, they get moved to the files folder.
I also went on to test the user picture upload, although user account editing is completely broken in todays HEAD version. For my test it was not needed however that the picture is properly saved in the datase (which did not happen). It was enough that the picture is properly saved in the file system and is handed over to the forms api handlers to save to the DB. The problem is in the forms API handlers, see the linked issue.
To make the picture uploading work however, I also needed a previous oneliner from Jose, since the picture moving was not done on the processed upload, so it would have worked improperly. The attached patch now includes this oneliner.
So I tested the patch with locale imports, upload module and picture uploads, and the files are all saved properly now even in a highly open_basedir restricted environment.
Please test, please apply. This is important.
Comment #20
Jose Reyero CreditAttribution: Jose Reyero commented+1
Patch applies, uploads work.
I hope now that Goba has set priority to 'critical' this gets in before the bug report is two years old :-)
Comment #21
chx CreditAttribution: chx commentedYes, we need this.
Comment #22
Nacho CreditAttribution: Nacho commentedHi,
i had a problem very simular to this one. When I tried to upload files I got an error ("The selected file ... could not be copied."), however open_basedir doesn't seem to be enabled on my server. I'm not sure whether it's caused by safe_mode or something else, but I've found out that the solution is the same, we have to use move_uploaded_file(). So I modified your patch a little bit to fix this case as well:
if (!is_readable($file->filepath) && ini_get('open_basedir'))
In fact, on my system, is_readable() returns true, ini_get('open_basedir') is an empty string, and yet move_uploaded_file() is neccessary. I believe the PHP manual says that that's the way uploads should be handled anyway, so it probably won't hurt even if it's not needed.
The reason is that on the first call, when the file is actually uploaded, it is checked for is_uploaded_file($_FILES["edit"]["tmp_name"][$source]) (line 144). However $_FILES["edit"]["tmp_name"][$source] is empty, the third case gets executed, and the function returns an empty string. Because of that, in file_save_upload(), line 395, the check fails, and the line where the session variable is supposed to be set is never reached. Kind of a vicious circle :-)
My solution is to manually set
$_SESSION['file_uploads'][$source] = $file;
in the second case. I'm not quite sure if that's the best way to do it. Maybe it would be better to have $_FILES["edit"]["tmp_name"][$source] set in the first place.I've attached a patch for file.inc only. It's made for 4.7.0 beta 2, not CVS, but it looks like the file hasn't changed much since then, so it should still work.
PS: Sorry if my post is confusing... It's late and I'm not used to writing English ;-)
Comment #23
Dries CreditAttribution: Dries commentedPatches need to be merged? It could do with some extra documentation/comments.
Comment #24
Gábor HojtsyCould someone please pick up this issue? I am seriously low on time having exams at the university, but think this should be in core for 4.7, or the prediction of Dries that Drupal is not going to cater for the small websites in 2006 immediately comes true.
Comment #25
Gábor HojtsyNacho, it would be nice to know what causes your problems, before doing "random" fixing. It might happen that your problem is actually easier to fix, or that it causes other problems elsewhere in Drupal.
Comment #26
dopry CreditAttribution: dopry commentedOk, I'll take up this one...
This patch addresses only the file.inc:file_check_upload(..) open_basedir restriction.
I dropped the special cases for if open_basedir is enabled or not, and just use move_uploaded_file to move all uploaded files to drupal's tmp dir for further processing... This is the recommended way to handle all php uploads.
The fileAPI is raw and not that intelligent. If modules are misusing it in its current state then bugs should be filed against those modules. It does not make sense that locale.module, or image.module issues be addressed in file.inc.. If all modules were affected I would say it is the proper location.
this patch was rolled against beta4 I can reroll against head if it is too far out of sync.
Comment #27
dopry CreditAttribution: dopry commentedhrm.. meant code needs review..
Comment #28
tangent CreditAttribution: tangent commentedI don't have open_basedir restriction on my host but I've tested file attachments with HEAD both before this patch and after.
Before:
1. Attaching a file with JS enabled fails. Script seems to time out and progress graphic does not move.
2. Attaching a file with JS disabled is successful. There is a file in 'files/tmp' called 'tmp_8PCgI7' after the edit is completed. The attached file is located in 'files'.
After:
1. Attaching a file with JS enabled fails. Same as above.
2. Attaching a file with JS disabled is successful. The file is placed in 'files' as expected but there is no leftover file in 'files/tmp'.
I also tested creating an image node with this patch applied and I get an error that I didn't get before, though it's likely a bug with image.module.
Comment #29
tangent CreditAttribution: tangent commentedThe lack of progress.gif animation is a problem in Firefox. I've double-checked the gif animation settings, deleted cache and history multiple times, and deleted and replaced progress.gif but cannot get it to animate. It animates if I load it locally (file > open) but not from that url. Anyway, can't blame Drupal for that. It doesn't animate from http://scratch.drupal.org/misc/progress.gif either. The strange thing is that it doesn't even look the same in Firefox as it does in IE. Can anyone else confirm or deny this?
The AJAX upload still doesn't work but I've taken that issue over to http://drupal.org/node/50366.
Comment #30
dopry CreditAttribution: dopry commentedI'll try to work out the JS stuff tonight.. If anyone can correlate I would appreciate it. Image module is probably trying to grab the files from session, but they've already been moved by the new check upload functionality and it should be using the node's file object instead. I'll try to verify that as well.
I really appreciate someone finally giving me some feedback on this...
.darrel.
Comment #31
Gábor HojtsyGuys, what if we concentrate on the open_basedir issue, which is the objective of this issue, and not progress gif and JS problems...
Comment #32
dopry CreditAttribution: dopry commentedGoba can you test against head? Do you get the same result?
Comment #33
dopry CreditAttribution: dopry commentedtesting note:
this only applies when upload_tmp_dir is set out side of the open_basedir...
So if you do setup open_basedir, make sure php's upload_tmp_dir is not inside the tree.
Comment #34
dopry CreditAttribution: dopry commentedRetested against HEAD.
I've tested with and without JS..
I do not experience the JS issues.
I do not have the left over file issues.
This is against head with only the single patch listed. No additional modules.
This patch changes the way file uploads are handled in core, and may break some contrib modules that handle file uploads.
The big change is, when file_check_upload is called, files are moved from php's upload_tmp_dir to drupal's tmp dir.
Comment #35
nedjoThanks dopry for working on this important issue.
(Note: patch should be generated from the drupal directory, and use original file names (not file.inc.orig).)
I applied the patch and did some basic testing on a hosted server with open_basedir restriction. Prior to the patch no uploads were working.
Result of testing:
1. js file upload works as expected :)
2. Tried to upload a new logo for a theme. No error message, but no file in /files and a file left in files/tmp.
So, it seems we're partway there but not all the way.
Comment #36
dopry CreditAttribution: dopry commentedOk so I discovered that this is related to the fact the file_check_load is called multiple times and expects the data to be in the _files array, so I added a cache to keep track of what has already been uploaded. The issues regarding undeleted files in the drupal tmp dir is still a factor. There may be a need for some garbage collection based cron code...
Comment #37
dopry CreditAttribution: dopry commentedHere is a patch with both the caching file_check_upload, and configurable cron driven garbage collection for drupal's file temp. There are further things that may need to done to prevent issues if drupal's tmp is the same as the PHP upload_tmp_dir. It may need a documentation upgrade that states that drupal needs its own tmp, not shared tmp directory if the ttl/file gc period in drupal is less that the file gc period for php.....
.darrel.
Comment #38
dopry CreditAttribution: dopry commentedHere's a cumulative patch...
Comment #39
nedjoDid a quick test with this new patch, again with open_basedir restriction in place, and everything I tried works now.
* js file uploads
* user picture uploads
* theme logo uploads
and no more files left in files/tmp.
Haven't found time to review the code yet. Offhand I'd say we probably don't need to include the _cron function here. Useful perhaps, but not needed to solve this issue. (And if the issue is successfully solved, cleanup shouldn't be needed.)
Comment #40
dopry CreditAttribution: dopry commentedHere is a patch with just the file.inc changes. There was a bug with the earlier patch with the cache checking coming before the is_object check. (Who would have thought that objects weren't valid array keys. ) This patch
also completes the error trap at the top so if a file object is passed and the filepath is incorrect file_check_upload will explicitly return false.
Comment #41
tangent CreditAttribution: tangent commentedI've tested the patch in comment #40. As mentioned previously, my host is not open_basedir restricted but all functionality seems to work correctly.
I see only a few formatting nags with the patch.
I agree that added cron cleanup logic is not, and should not be, necessary.
Comment #42
dopry CreditAttribution: dopry commentedNow the whitespacing ugliness is removed... please test...
Comment #43
dopry CreditAttribution: dopry commentedmore style clean up after the unrelated comment assault... ;)...
Comment #44
Dries CreditAttribution: Dries commentedThis patch needs to be re-rolled. It no longer applies due to the mime-type magic being removed.
Comment #45
Dries CreditAttribution: Dries commentedQuick review:
1. Code looks good.
2. The quality of the code comments could be better:
a. There is a lot of information captured in this issue. I think we can do a better job commenting the code.
b. We should also use proper punctuation.
c. Shouldn't we extend the PHPdoc above the function declaration?
3. The name
file_check_upload()
has a different meaning now. It no longer 'checks' your upload. It 'prepares' your upload.file_prepare_upload()
might be a better name.Comment #46
dopry CreditAttribution: dopry commentedI improve the documentation. (i hope, my puctuation isn't so good.)
I turned file_check_upload into a wrapper function for file_prepare_upload, for compatability with existing contribs and core modules.
I moved the upload error checking in file_save_upload to file_prepare_upload.
I think file_save_upload could be completely rolled into file_check_upload. I don't understand the need to have these be seperate functions. I'm not sure if that is a change that should wait for 4.8.
Comment #47
Dries CreditAttribution: Dries commentedPlease remove the wrapper functionality.
The code comments are still sloppy: inconsistent use of capital letters and space.
Comment #48
chx CreditAttribution: chx commentedindeed, one of the characteristics of drupal is "no backwards compatibility" "for compatability with existing contribs and core modules." equals bloat in drupalspeak.
Comment #49
dopry CreditAttribution: dopry commentedI changed the function name back to file_check_upload. I don't feel aesthetic changes this late in the game are appropriate. I'll do the renaming when HEAD reopens. File handling is going to see a lot of work for 4.8 I believe.
I cleaned up my Capitalization and spacing in my comments.
also removed an unneccessary rename... that got in there somehow...
Comment #50
dopry CreditAttribution: dopry commented-- more spacing and capitalization cleanups.
Comment #51
Dries CreditAttribution: Dries commentedLooks good. Two tiny details:
1. We write 'Drupal', not 'drupal'.
2. Maybe add a @TODO so we can rename the function later on.
We can commit this, after some final testing. Please report success/failure.
Comment #52
dopry CreditAttribution: dopry commentedWell I'm going to leave the reviewing up to others, but here are, hopefully, the last of the comment cleanups.
Comment #53
Dries CreditAttribution: Dries commentedSmall remark: Drupal 4.7 requires 4.3.3 or higher so we can use the constants now ...
Comment #54
nedjoThis patch, like the last version I tested, successfully fixes the open_basedir issue on my testing.
I applied the patch to today's CVS HEAD and tested on a server with open_basedir restriction.
Before the patch no file uploads worked. With the patch, all file uploads I tried worked as expected. Tested:
* js file uploads (via upload.module)
* user picture uploads
* theme logo uploads
Comment #55
chx CreditAttribution: chx commentednedjo,if that's so why you have not set the status? :)
Comment #56
Dries CreditAttribution: Dries commentedCommitted to HEAD. Marking this active as we can now use PHP's file constants. See my previous comment.
Comment #57
dopry CreditAttribution: dopry commentedHere is the switch to using constants available in php 4.3.3.
There is one additional constant for 4.x series we are not using, but it is only available in >= 4.3.10
Comment #58
dopry CreditAttribution: dopry commentedSetting to RTBC... I haven't had a problem locally and I've been running this patch on my test installation for wuite some time.
Comment #59
moshe weitzman CreditAttribution: moshe weitzman commentedI uploaded a few times using this code and no ill effects. It is hard to exercise each code branch though. IMO, this is RTBC
Comment #60
killes@www.drop.org CreditAttribution: killes@www.drop.org commentedapplied
Comment #61
(not verified) CreditAttribution: commented