Problem/Motivation
Drupal enforces creation of .htaccess files yet some environments don't use them and others create errors when they are present (eg. IIS + WebsitePanel).
Proposed resolution
When Apache is reported as the web server, automatically create .htaccess files. Otherwise, do not create them. Allow users to explicitly enable or disable the automatic creation of .htaccess files using a config setting (and hence clear any warning message).
Remaining tasks
- Decide whether to show a warning on the status report page.
User interface changes
New warning message in File System section of Status Report.
API changes
New config setting.
Original report by kbahey
Check for .htaccess, and creating .htaccess should only be done for Apache
We are currently doing this check for non-Apache servers too, and it causes errors to be displayed when using IIS and other servers.
So, this patch limits this checking and .htaccess creation to Apache only.
| Comment | File | Size | Author |
|---|---|---|---|
| #102 | Screenshot From 2025-06-30 13-16-52.png | 235.17 KB | larowlan |
Issue fork drupal-360057
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
- 360057-automatic-creation-of
changes, plain diff MR !11204
Comments
Comment #1
webchickSeems reasonable.
Can we replace the preg_match() with a strstr()?
Also, a test would be nice.
Comment #2
webchickActually, I think I remember reading that strpos() is faster than strstr(). But either is definitely faster than preg_match(), according to the docs: http://ca2.php.net/preg_match.
Comment #3
kbahey commentedYour wish is my command mi lady ...
Comment #4
webchickSee, this is why I'd like tests. :)
Because that code will fail to execute if "Apache" is in the first position (0) in the string. Need to compare to !== FALSE.
Comment #5
kbahey commentedIt is late, but here goes ...
Comment #6
kbahey commentedDearest webchick ...
I have learned the errors of my way, and included tests for Apache and he-who-shall-not-be-named.
With this repentance, I hope you accept my tithe, errr, patch ...
Comment #8
dave reidRequesting retest.
Comment #10
Akaoni commentedI don't think we can apply the blanket rule of Apache=.htaccess and non-Apache=no .htaccess.
There are, and will continue to be, exceptions to this rule (eg. IIS + ISAPI_Rewrite supports .htaccess).
Perhaps the best way forward is allowing people to opt-out of enforced .htaccess files.
Patch attached.
For info, I'm using Drupal on an IIS7.5 host with WebsitePanel and any form of .htaccess file breaks the website.
I've used this patch and the following in settings.php to fix the issue:
$conf['no_htaccess'] = TRUE;Comment #11
Akaoni commentedMoved to 8.
Comment #12
Akaoni commentedAdded "Needs tests" tag.
Comment #13
Akaoni commentedApplied Issue summary standards and renamed.
Comment #13.0
Akaoni commentedApplying Issue summary standards
Comment #13.1
Akaoni commentedAdded original title for ease of reference.
Comment #14
Akaoni commentedFeeling like a bit of a one man army on this one, but oh well. ;)
Test patch - should fail (for the right reason).
Comment #16
Akaoni commentedCombined patch.
Upgraded to major.
Comment #17
catchCan we make the variable a positive one, right now it's a double negative.
Like variable_get('automatically_generate_htaccess', TRUE);
Otherwise looks fine and using a configuration setting for this sounds seems better than trying to figure it out.
Comment #18
Akaoni commentedThanks catch!!
Rerolled to be a little more up-beat (positive).
First is test only and should fail twice (for the right reason).
Second is test and fix.
Comment #18.0
Akaoni commentedCleanup remaining tasks and add test path.
Comment #19
Akaoni commentedSweet!!
Issue summary updated.
Comment #20
catchSorry one more thing here:
+ // Don't create .htaccess files if 'auto_create_htaccess' variable is FALSE.This needs an explanatory note as to why you might want to disable it, although probably in the main function docblock.
Comment #20.0
catchNew positive patch.
Comment #21
Akaoni commentedAdding novice.
Removing cross post "Needs tests".
Comment #22
Akaoni commentedImproved comments as per catch's suggestion.
Comment #23
Paul Simard commentedComment #24
Paul Simard commentedAt the moment, I am unable to persuade either Drupal or Apache to create an .htaccess file in the public:// directory using the 8.x clean install. Status of test thus far:
I am trying to track down the problem. I am not sure if it's in the WAMP stack, or Drupal as yet.
Comment #25
Akaoni commented@Paul Simard: Thanks for giving testing this a crack!! ;) Perhaps the test path I wrote is a bit flawed? Will have a play and see.
Comment #25.0
Akaoni commentedImproved test path.
Comment #25.1
Akaoni commentedBetter test path.
Comment #26
Akaoni commentedYep. The test path was *completely* wrong. My bad.
In fact, you got further than I did - I don't even know how you installed Media 7.x onto Drupal 8.x. ;)
Updated it in issue summary.
Comment #27
catchThere's a nice automated test here that fails correctly without the fix applied, so no need for manual testing.
Comment #28
Paul Simard commentedThere was no need to install Media on 8.x until and unless the patch passed using only core in a standard install. I just added a file field to the Article content type, and uploaded files that way.
Since it didn't pass, i.e. no .htaccess was created, either with or without the patch...
@catch I don't know if the previous was aimed at my inbox (re: automated test). If so, thanks for the info. If not, ignore this line.
Paul
Comment #29
Akaoni commented@Paul Simard: Ah. I must admit, I wasn't aware that there was a way of uploading files with just core - I'm still only relatively new to Drupal. Good to know. ;)
Turns out uploading files doesn't "prepare" the directory anyways which is why you didn't get a .htaccess file. Oddly enough, changing colour scheme does so I've updated the test path accordingly.
Up to you whether you test this any further or not as catch reckons it's good to go as is. Thanks again!! ;)
Comment #30
Paul Simard commentedAkaoni,
In all fairness, it was catch who reminded me of 'File' module's presence in core. I merely added the extra field. I'll bow to catch's greater experience and Drupal expertise, as far as continued testing goes, as he is far higher on the food chain than I. I may spend a bit of time in the code trying to ferret out its secrets, though, in my quest to learn Drupal myself. (I'm still very low on the food chain, myself.)
Let me know if I can help any further, as time permits, I'd be interested.
Paul
Comment #31
dries commentedInstead of a global killswitch variable, wouldn't it be better to check for the existence of Apache and make this behavior automatic?
I understand there are exceptions to this rule (e.g. some IIS configurations support
.htaccessfiles), but does that really hold up as an argument against automatic behavior? Let's brainstorm about it a bit more ...I'd think that the automatic behavior avoids errors/problems, whereas the global killswitch variable doesn't. Because the variable defaults to generating
.htaccessfiles (i.e.variable_get('auto_create_htaccess', TRUE)), it still causes problems on installations that don't support.htaccessfiles. Hence, it requires people to research the problem, and to find out about the existence of the global killswitch variable. That is non-trivial and most people might have given up by the time they learn about the global killswitch variable ... in other words, I find the variable kind of a poor solution.Comment #32
yoroy commentedSounds like this needs some more work then
Comment #33
catchAutomatic detection with no killswitch is going to break things for those IIS installs, all I can think of as a compromise is this:
Automatically create the .htaccess if it's Apache.
Don't create it automatically for anything else, however, warn in system_requirements() if the .htaccess doesn't exist. For sites that really don't want it, keep the killswitch which will mainly function to disable the system_requirements() warning.
Comment #34
Akaoni commented@Dries: Good point on automation being much better for users. I agree with catch though, in that we still need a killswitch/override. There's so much variation out there on how web servers and even web applications handle .htaccess files. As such, let's automate what we know and allow people to override for the edge cases.
New test only patch as described by catch (should fail twice for the right reason).
Comment #35
Akaoni commentedNew test and fix patch as described by catch.
Comment #36
catchThis and the next check:
The different arguments to variable_get() can make things harder to debug, as well as likely being incompatible as soon as CMI comes on - since we'll no longer pass defaults every time we check a variable (at least I hope so).
1 days to next Drupal core point release.
Comment #37
Akaoni commentedNew patch fixes different variable_get() arguments and cleans things up a bit.
Test code hasn't changed.
Comment #38
Akaoni commentedMade it more better after IRC chat with catch.
Please let this be the last one... ;)
Comment #39
catchOK this looks good to me. It's hard to explain what's going on here, but the alternative is completely failing out on people and/or risking a security issue on sites that aren't using apache but are relying on .htaccess.
Comment #40
chx commentedone, the variable_get is repeated needlessly. Two, I think the api.drupal.org link needs to be file_save_htaccess not file_create_htaccess otherwise we are good here.
Comment #41
Akaoni commented@catch, chx Thanks, guys!!
chx, another patch, just for you. ;)
Comment #42
Akaoni commentedComment #43
chx commentedGood to go.
Comment #44
sunThis is potentially one of the first messages/warnings/errors that users are going to see when installing Drupal.
It's unlikely that users are going to (be able to) switch to another web server when reading this, so the entire drama about "Apache" is information clutter.
"Files on this web server may not be stored securely. Configure your server securely."
Give or take grammar errors. ;)
We also need to link to a handbook page, not api.d.o.
-2 days to next Drupal core point release.
Comment #44.0
sunLink to new patch.
Comment #44.1
Akaoni commentedNew fix.
Comment #45
Akaoni commentedIssue summary updated.
In **further** IRC discussions with sun we could:
*sigh* The rabbit hole gets deeper...
Comment #46
yoroy commentedGlad to see sun pick up on this very wordy warning message. I think it would be useful to use the ".htaccess file" keyword somewhere in this message. Maybe the link in suns' example could be "Secure your server with .htaccess" or similar:
Comment #47
dries commentedThis approach looks good.
Instead of checking this over and over again, why don't we set
variable_get('auto_create_htaccess')at install time? Then, we can streamline this code to just checkvariable_get('auto_create_htaccess'). I think that would streamline the code a bit.Comment #48
rbayliss commentedJust a reroll of Akaoni's patch from above to apply to the /core directory structure. Still needs changes based on comments from Sun in 44.
Comment #49
Akaoni commentedThanks, rbayliss.
Unfortunately I can't commit anymore time to this one. :(
Hopefully someone can pick it up or we settle for a less ideal, but implementable now solution.
Comment #50
synth3tk commentedIncludes the suggestions in #44 (sun), #45 (Akaoni), and #46 (yoroy).
("Files on this web server may not be stored securely. Secure your server with .htaccess files.")
Comment #51
synth3tk commentedComment #52
oriol_e9gI think that the message is fine in #50 but we still need to apply/discuss #47
Comment #53
gddHere is a new patch, which sets the variable in file.install per #47.
Comment #54
catch0 byte patch.
Comment #55
gddOops. We should make the bot complain about that maybe. New patch attached. Note that I did not add a hook_uninstall() because so far as I can tell, File module can not be uninstalled.
Comment #56
David_Rothstein commentedDoing that in hook_install() seems like it would cause problems if you ever move your site to a different server. I think it's better to just check the server software each time (like in the earlier patches). It's not like this is code which runs often...
***
Overall, I'm somewhat concerned about the security implications of this patch. Currently, Drupal guarantees that if your server is configured to support .htaccess, it will provide this protection in the files directory. But this patch is going to make this security feature "opt-in" for anyone who isn't running Apache. I don't think that's a good change.
I think we need to go back to something like #22, which forces you to opt-out if you are having problems. The concern with that was that it's not discoverable, but couldn't we use a status report message to make it discoverable (i.e. combine the two approaches)? If someone is running into trouble with their site, they'll probably go to the status report page eventually, and if the warning there links to somewhere which tells them how to turn off .htaccess protection, we get the best of both worlds.
Although... that all depends on the person being able to make it to the status report page in the first place :) This issue refers to "errors" caused by .htaccess when using IIS + WebsitePanel, but I don't see any explanation of what the errors are. That seems like useful information for this issue. I did a little searching and came up with http://forum.arvixe.com/smf/general/installed-drupal-dotnetpanel-iis-mod... but I'm not even sure that's the same problem; it refers to a conflict between Drupal's .htaccess and one which is automatically created by the control panel software. If that's the problem then the solution may be different also.
Comment #57
NROTC_Webmaster commentedInstead of saying that anything not apache gets a .htaccess file created why not instead list the known exceptions? I did not do this because I'm not sure which ones will create the error.
I also updated this to default to creating the .htaccess file and assume that admin can turn it off if they need to.
Fix a typo in the install function.
Comment #58
NROTC_Webmaster commentedComment #60
randomtide commentedPatch in #57 doesn't even apply anymore to current D8 (2013-03-09).
Can we remove the "novice" tag from this issue in the meantime?
Comment #61
heddnRemoving novice tag until its decided what approach will be used.
Comment #61.0
heddnNot RTbC.
Comment #61.1
heddnUpdated issue summary.
Comment #61.2
heddnUpdated issue summary.
Comment #61.3
heddnUpdated issue summary.
Comment #62
Anonymous (not verified) commentedIf the goal is to put .htaccess in place if and only if it would be used by the webserver, would a possible be test be to generate a file and an .htaccess that would disallow access to the file? At that point, if the Drupal made a request to itself, it seems that it would be able to discover if .htaccess files are honored or not by whether it got an error or the file it requested.
If my understanding of the problem is correct, it seems that that would give us the knowledge of whether to create a file or whether to give some form of notification.
Comment #62.0
Anonymous (not verified) commentedUpdated issue summary.
Comment #63
jhedstromMoving to 8.1 for now. It might be accepted into 8.0 since it is classified as a bug if somebody wants to pick this back up.
Comment #64
catchThere's no new API here, so it could feasibly be done in a patch release, moving back for now.
Comment #67
20th commentedComment #70
rjzaar commentedThis little patch just adds Options +FollowSymLinks to .htaccess for those who want to add it using composer patch.
EDIT: Mike Potter has a working solution to this issue: https://github.com/acquia/blt/issues/1135#issuecomment-285404408
Here is my application of his advice: https://github.com/rjzaar/opencourse/blob/8.6.x/composer.json
and the patch: https://github.com/rjzaar/opencourse/blob/8.6.x/scripts/Add-FollowSymLin...
Comment #73
kim.pepperComment #74
kim.pepperHere's a patch that builds on #2620304: htaccess functions should be a service to add a settings check to see if auto create is enabled/disabled.
Comment #79
dwwThis came up as a daily #bugsmash triage target.
The filename of the latest patch is "360057-combined-74.patch" and the comment says:
So I think that includes all of what was committed for #2620304 plus the additional stuff to satisfy the needs of this issue. If @kim.pepper still has the Git branches lying around and can untangle that from what's already committed, great. Otherwise, someone will have to do that manually (which will probably be interesting / fun). 😉
Comment #80
kim.pepperRe-wrote this for Drupal 9.4.x so there's no real useful interdiff.
Comment #81
kim.pepperFixes incorrect comment.
Comment #82
kim.pepperFix wrong service in constructor.
Comment #83
quietone commented@kim.pepper, thanks for updating the patch.
Some things I noticed
I did some testing with ddev.
I installed the patch, removed sites/default/files/.htaccess, and then installed Drupal. After the install that .htaccess file existed.
I tried again, I added dded
$settings['auto_create_htaccess'] = FALSE;to settings.local.php, removed sites/default/files/.htaccess, and then installed Drupal. After the install that .htaccess file did not exist. There is no warning in the logs. And the Status report has an error that the public directory is not fully protected.Setting to NW for the above.
Comment #84
kim.pepperComment #85
kostyashupenkoNo need for reroll
Comment #87
acbramley commentedDo we need both warnings in ensure and write functions? Also, should it really be a warning?
Comment #92
smustgrave commentedSo this one is coming as the "One" for bugsmash so thought I'd give it a quick look.
Took the patch in #82 and only slightly fixed up with today's checks: Constructor promotion, return types, deprecation version.
#87 I agree and changed that to an error()
Also tweaked the CR some but it was pretty straight forward.
Still NW for
Comment #93
kim.pepperRebased on 11.x and added docs to
default.settings.phpComment #94
smustgrave commentedSettings read well to me.
16 years and this one may be good
Comment #95
kim.pepperBack to NR for the feedback from @acbramley
Comment #96
acbramley commentedComment #97
poker10 commentedI reviewed the MR and added some comments.
I think this needs an issue summary update, because these parts from IS are not implemented:
When manually tested this, I was unable to find the warning entry in the log (
Auto-creating htaccess disabled.), as the file creation is blocked in the parent function (HtaccessWriter::ensure()), so if theauto_create_htaccessconfig is set to FALSE, it will never reach the code inHtaccessWriter::write(). Not sure it was the intent. Personally I think that we do not need this logging at all and it will be sufficient to create a follow-up to sort-out the errors in the status report, which are displayed if .htaccess files are missing and theauto_create_htaccessconfig is set to FALSE:I think it does not make sense to have it as errors anymore, when you use this new switch and disable it's creation on purpose.
Moving to NW for these.
Thanks!
Comment #98
kim.pepperAddressed feedback and updated the IS.
I think we can create a new requirements check for the config setting. However, there was some pushback (#44_) on showing warnings on a standard install, so we need to be sure this is considered.
Comment #99
poker10 commentedYes, I was thinking more about adjusting the existing error messages, which are displayed when .htaccess files are missing, so that these have a different wording when the
auto_create_htaccessconfig is set to FALSE, or hide these messages entirely. But I think that is not in scope of this issue, thus I mentioned the potential follow-up. I agree that adding a new requirements check with another warning or so is not ideal.Comment #100
smustgrave commentedBelieve feedback has been addressed here.
If we need a follow up ping me and I’ll happily do that
Comment #101
kim.pepperAdded a CR about the new setting.
Comment #102
larowlanUpdating issue credits.
I recreated @quietone's testing from #83 and yielded the same result.
Steps to test
sudo touch sites/default/files/.htaccessso that the webserver cannot write to it$settings['auto_create_htaccess'] = FALSE;in settings.phpsystem_requirements- I think we need that code to be skipped if this flag is set to FALSE
Comment #103
kim.pepperAdded a check for the setting in
system_requirements().Comment #104
kim.pepperFixed conflict with #3493718: Convert system_requirements() into OOP hooks and install time class and added check for setting in
SystemRequirements::checkRequirements()instead ofsystem_requirements().Comment #105
quietone commentedMade some changes to the CR, https://www.drupal.org/node/3525119
Comment #106
smustgrave commentedBelieve feedback has been addressed regarding system_requirements
Comment #107
larowlanCommitted to 11.x - congrats folks, this was the oldest open bug in Drupal core, AKA 'the one ⭕️' in #bugsmash parlance
Published change record.