I have working rewrite rule in /.htaccess file:
RewriteCond %{REQUEST_URI} ^/wp-content/uploads/sites/[0-9] /xxx_uploads/ [NC]
RewriteRule wp-content/uploads/sites/[0-9] /xxx_uploads/(.*) wp-content/files.php?file=xxx_uploads/$1 [R=302,L]
which disallows unauthorized users viewing files in specific directories.
It works as long as there is nothing in /wp-content/uploads/.htaccess
If I put at least RewriteEngine On
there, the rule from root .htaccess stops working.
It seems there is nothing with inheritance as RewriteOptions Inherit
doesn't change anything.
The question is: how to make the rule from root .htaccess work with rules in subdirectory .htaccess?
Apache 2.4.38
CodePudding user response:
What you describe is expected behaviour. mod_rewrite directives are not inherited by default. So if you enable (or disable) the rewrite engine in a child config it completely overrides mod_rewrite directives in the parent config.
It seems there is nothing with inheritance as
RewriteOptions Inherit
doesn't change anything.
It should, however...
RewriteOptions Inherit
would need to go in the /wp-content/uploads/.htaccess
file, not in the root /.htaccess
file. However, mod_rewrite "inheritance" works by virtually copying the directives in-place. So this will not help in this instance since the RewriteRule
directive as posted will not match when "inherited", ie. when virtually copied to the /wp-content/uploads/.htaccess
file.
To resolve this, you can enable mod_rewrite inheritance in the parent (root) .htaccess
file using RewriteOptions InheritDownBefore
(requires Apache 2.4.8) and modify the rule so that it would work in both the root and child .htaccess
files (in fact, anywhere).
For example:
# /.htaccess
RewriteEngine On
RewriteOptions InheritDownBefore
RewriteCond %{REQUEST_URI} ^/wp-content/uploads/sites/[0-9] /xxx_uploads/(.*) [NC]
RewriteRule . /wp-content/files.php?file=xxx_uploads/%1 [R=302,L]
This rule will now work regardless of where the .htaccess
file is located (or where it is inherited). Note that %1
(as opposed to $1
) is a backreference to the preceding CondPattern instead.
Note the slash prefix on the substitution string to make it a root-relative URL-path.
However, this may not work if you have other directives in the root .htaccess
file, as these will also be "inherited".
Alternatively, you put your rule(s) in a server or virtualhost context (not inside a <Directory>
container) and they will always run before the directives in any child .htaccess
files.
Aside:
RewriteCond %{REQUEST_URI} ^/wp-content/uploads/sites/[0-9] /xxx_uploads/ [NC] RewriteRule wp-content/uploads/sites/[0-9] /xxx_uploads/(.*) wp-content/files.php?file=xxx_uploads/$1 [R=302,L]
As written, the RewriteCond
directive is entirely superfluous. (Providing the RewriteRule
pattern is anchored, ie. ^wp-content/....
)