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.
file_directory_path() is a thing of the past, dark times of Drupal. We need to remove it.
This is a spin-off of #874326: Invalid scheme fails to halt processing of a stream request
Comment | File | Size | Author |
---|---|---|---|
#4 | 895308-kill-file-directory-path.patch | 41.36 KB | Damien Tournoud |
#3 | 895308-kill-file-directory-path.patch | 41.3 KB | Damien Tournoud |
#2 | 895308-kill-file-directory-path.patch | 41.21 KB | Damien Tournoud |
#1 | 895308-kill-file-directory-path.patch | 40.56 KB | Damien Tournoud |
Comments
Comment #1
Damien Tournoud CreditAttribution: Damien Tournoud commentedLet's see what happens.
Comment #2
Damien Tournoud CreditAttribution: Damien Tournoud commentedThis one should pass a little bit better.
Comment #3
Damien Tournoud CreditAttribution: Damien Tournoud commentedEven better.
Comment #4
Damien Tournoud CreditAttribution: Damien Tournoud commentedAnd cURL doesn't support stream wrappers... fixing one of the last fails.
Comment #5
rfay+1 from me. I think we should go with this as soon as possible.
This is, of course, a major API breakage for existing contrib.
Comment #6
aaron CreditAttribution: aaron commentedlooks really good; thanks for taking the initiative to help clean up the api!
Comment #7
aaron CreditAttribution: aaron commentedto be clear, for contrib using it before, they would most likely want to use $wrapper->getDirectoryPath().
Comment #8
Damien Tournoud CreditAttribution: Damien Tournoud commentedActually, in the most common case, contrib modules wants to use
'public://'
orfile_default_wrapper() . '://'
as a replacement for file_directory_path().Some other legitimate use cases exists:
file_stream_wrapper_get_instance_by_scheme('public')->getDirectoryPath()
orvariable_get('file_public_path', conf_path() . '/files')
directly.file_stream_wrapper_get_instance_by_scheme($scheme)->getDirectoryPath()
Comment #9
aaron CreditAttribution: aaron commentedall seems good to me. applied the patch and did some basic testing, and nothing seems broken. let's get this thing going!
Comment #10
Dries CreditAttribution: Dries commentedLooks like a valuable clean-up to me. While we need to remove it, it is questionable as whether we need to remove it from D7. Any reason this can't wait to D8?
Comment #11
rfayThis needs to be done in D7 because (almost) every use of it went around the normal "public://" approach, leading to things like deleting things that shouldn't be deleted, etc. It's unfortunate that we discovered this so late, but the clear consensus is that it needs to be removed anyway.
We changed the API a year ago, but unfortunately didn't remove this then, and all usages of this function assume the D6 way of doing things, which just doesn't fly.
The full discussion and reasoning are in #874326: Invalid scheme fails to halt processing of a stream request, with strategy statement in #874326-36: Invalid scheme fails to halt processing of a stream request.
Comment #12
Dries CreditAttribution: Dries commentedOK, let's bite the bullet then. Committed to CVS HEAD.
Comment #13
mfbAnother (less verbose) replacement for contrib is to build the stream-wrapped URI and then use drupal_realpath().
I am using this to pass a filename into imagepng(), which apparently doesn't support stream wrappers. See _color_render_images() as an example.
Comment #14
solotandem CreditAttribution: solotandem commentedThis needs documentation at http://drupal.org/update/modules/6/7.
Comment #15
boombatower CreditAttribution: boombatower commentedLooking at pifr it does all kinds of local file operations in which the functions will not accept stream wrappers, such as chdir(). I would appreciate a replacement for file_directory_path() which is not verbose and silly like (best of Damien's examples) variable_get('file_public_path', conf_path() . '/files').
Having to repeat the default value and what not over a static function is not preferred.
Comment #16
boombatower CreditAttribution: boombatower commenteda) needs documentation, b) would be good to clarify what is a good simple replacement.
Comment #17
boombatower CreditAttribution: boombatower commentedIf drupal_realpath('public://') works then that would be by far the best replacement. Still kinda silly considering 99.9999% of contrib wants the public file directory. Is there no way we can have a special function for that?
file_stream_wrapper_get_instance_by_scheme('public')->getDirectoryPath() is a cumbersome replacement for file_directory_path().
Comment #18
Damien Tournoud CreditAttribution: Damien Tournoud commented@boombatower: in your case, you want
file_stream_wrapper_get_instance_by_scheme('public')->getDirectoryPath()
@mfb: in your case, you want to first check if the file wrapper is local
Comment #19
boombatower CreditAttribution: boombatower commentedThat's my point....lets make a file_directory_path() a wrapper function for that...waaaay to long.
or
Plus interestingly enough the patch doesn't use your final recommendation.
Comment #20
mfbIf you call
drupal_realpath('public://mymodule/images')
that's guaranteed to be local right? That has been my assumption after looking at core code like color.module...Comment #21
Damien Tournoud CreditAttribution: Damien Tournoud commented@mfb: public is always local. That said, public is *not* garanteed to be the "default stream-wrapper". So depending on your use case you might want to respect the default stream-wrapper, which is not guaranteed to be local.
@boombatower: no, we definitely don't need any wrapper for this. There was *a lot* of creative (and wrong) use of file_directory_path() in core, that's why the patch has different replacements depending on the various wrong uses. See #8 for details.
Comment #22
mfbMaybe best practice is to use temporary:// for operations that don't support stream wrappers and then move the file to the default scheme? For now I am just forcing public:// as e.g. color.module and locale.module do.
Comment #23
boombatower CreditAttribution: boombatower commented@Damien: you are missing the point...if core needs to use various versions of this code that's all well and good...I just want a simple way to get to files directory, nothing more.
Comment #24
Damien Tournoud CreditAttribution: Damien Tournoud commentedThat doesn't mean anything anymore. Either just use the variable or use
file_stream_wrapper_get_instance_by_scheme('public')->getDirectoryPath()
.Comment #25
ufku CreditAttribution: ufku commentedIn API change notification the alternate is declared as "public://".
AFAIK,
it is not accepted by functions such as drupal_add_js/css.I agree boombatower and think it would be nice to have file_directory_path(SCHEME) back, may be having a different name and documented that it returns the user-defined path.
Comment #26
boombatower CreditAttribution: boombatower commentedThe "files" directory = public directory...If I choose to assume it is local as my code requires it to be then it won't make a difference which function I use as it will blow up if the public directory is not configured to be local. I don't see what we gain from this...other then confusing people and making them ask the same question I am, "Why did they make this so darn complicated in Drupal 7?"
I mean for all the modules that don't need local files directory they get an easy way to reference the public directory (which everyone uses) and for the few modules that need it to be local they will need to check it on install regardless so forcing people to use some complicated call just because we can't assume the public files directory is local any more really doesn't help the situation in any way.
If we really want to make this slick (not sure how many modules needs this) we could add a flag in the .info file and check automatically in core just like any other dependency (or php version).
For most cases we should probably suggest that people put things in temporary:// directory if they need to use local functions that don't accept stream wrappers and then move the files to public:// or whatever after they are complete. Even then they still want an easy way to get temporary:// path. In my case that is probably what I should do...use temporary path and then either move or symbolic link the "checkout" directory in the public:// files directory, but still having a quick function to get temporary files directory.
So my code would look something like the following.
According to documentation as of PHP 5.0.0 rename() works with "some" url wrappers. At least that's better then nothing...not sure if there is a different move function that works will all.
Comment #27
mfb@boombatower according to #21 public is always local. So you can just use public://myfile public://mydir/myfile etc? Maybe you can point to particular lines of code if something seems problematic?
Comment #28
boombatower CreditAttribution: boombatower commentedchdir('public://'); does not work so we need public:// evaluated to real path.
Comment #29
rfayInteresting - I think streams in general have no idea of current directory, so the user must keep track of it.
Comment #30
mfbThe docs could list some commonly-used functions that require the drupal_realpath('public://...') notation. This would include chdir(), imagepng(), etc. (by the way many other image functions e.g. getimagesize() do work with stream wrappers).
Comment #31
mfb@ufku: I just tested with some sample files
and it appears that drupal_add_css() and drupal_add_js() do support public:// file paths.
Also, I added some documentation at http://drupal.org/update/modules/6/7#file_directory_path please review it.
Comment #32
sun(and elsewhere) The various Image module hunks in this patch are inconsistently using either 'public' or the default scheme. They should be consistently using one or the other (rather the default than a hard-coded public scheme).
?
Powered by Dreditor.
Comment #33
mfbOne thing about image.module, I don't think it will work if the default scheme is non-local and you're using the gd image toolkit, because image_gd_save() won't be able to save to a non-local location. But it could work if someone made an image toolkit that supports stream wrappers. Maybe we need to check if the default scheme is compatible with the toolkit..
Comment #34
boombatower CreditAttribution: boombatower commentedAnd/or as suggested provide a .info file flag or what not for requiring public:// to be local.
Comment #35
mfbpublic will always be local. the question is, if file_default_scheme is local. Image module should theoretically support non-local default schemes, it's just the image.gd.inc toolkit that cannot.
Comment #36
Damien Tournoud CreditAttribution: Damien Tournoud commentedThe toolkit needs to be fixed. On non local storage, we need to generate the file in a temporary directory and then push it to the remote storage. If we don't do that, we will never support storage on S3 and other blob storage with built-in CDN capabilities.
Comment #37
mfbFYI I just found an issue for the image.gd.inc remote stream bug: #696150: image_gd_save() does not support remote stream wrappers
Comment #38
jhodgdonchanging the tag to new tagging scheme.
What's the status of the update guide section added in #31 - does it need to be edited?
Comment #39
rfay@jhodgdon, #38, I think it's probably OK. I added a reference to the appropriate handbook page just now.
http://drupal.org/update/modules/6/7#file_directory_path