Forum Moderators: phranque
SetEnv this that
ReWriteRule ^ - [E=foo:bar]
SetEnvIf ^ ^ lorem=ipsum On Apache 2.x, module execution order is controlled by an internal priority scheme, and can't be changed unless you modify the Apache source and re-compile it.
To be very clear about all of the above: Each Apache module parses your .htaccess file(s) in turn, looking for directives that it understands and handles. So directives handled by any one specific module are executed in the order they appear in your .htaccess file. But you cannot control the order in which different module's directives execute by specifying their order in .htaccess -- The module execution order determines that.
The internal environment variables set by this directive are set after most early request processing directives are run, such as access control and URI-to-filename mapping. If the environment variable you're setting is meant as input into this early phase of processing such as the RewriteRule directive, you should instead set the environment variable with SetEnvIf.
The SetEnvIf directive defines environment variables based on attributes of the request.
mod_rewrite (eg, RewriteRule) runs in the order it's presented. mod_setenv (eg, SetEnvIf) runs before everything else, and mod_env (eg, SetEnv) runs after everything elseThis is a little misleading, but I can’t tell if it is an artifact of posting, or a bona fide misunderstanding.
module execution order is controlled by an internal priority scheme, and can't be changed unless you modify the Apache source and re-compile it.
This is a little misleading, but I can’t tell if it is an artifact of posting, or a bona fide misunderstanding.
I know that you're thinking the docs explain the answer perfectly wellNuh-uh, not me, you must be thinking of someone else ;)
Meaning, had mod_env been named mod_zenv then SetEnv would always run first?It's probably more accurate to say that, if Apache's developers had wanted mod_env directives to run before all other mods, they would have named it mod_zenv. Similarly, if words like Access and Authentication had not happened to start with the letter A, the relevant modules might have been named something less intuitive.
I'm looking at replacing about 700 RewriteRulesCriminy, that's a lot of RewriteRules. I think this is the point where we pull out the boilerplate answer, deployed quite often in the Apache subforum: Start by laying out, in English (which is a different language from Apache) exactly what it is you want to do. From there, we proceed to working out how best to accomplish it.
I think this is the point where we pull out the boilerplate answer, deployed quite often in the Apache subforum: Start by laying out, in English (which is a different language from Apache) exactly what it is you want to do. From there, we proceed to working out how best to accomplish it.
if ($default == 'example') {
$foo = "bar";
$this = "that";
} RewriteCond %{ENV:default} ^example$
RewriteRule ^ - [E=foo:bar,E=this:that] SetEnvIf default ^example$ foo=bar this=that
and so on. But depending on circumstances it may be possible to set them all at once: SetEnvIf attribute RegEx default=example foo=bar this=that
and, again, so on. module execution order is controlled by an internal priority scheme, and can't be changed unless you modify the Apache source and re-compile it.
Might as well be in Latin :-O LOL
httpd -M
apachectl -M Loaded Modules:
core_module (static)
so_module (static)
watchdog_module (static)
http_module (static)
log_config_module (static)
logio_module (static)
version_module (static)
unixd_module (static)
access_compat_module (shared)
alias_module (shared)
auth_basic_module (shared)
authn_core_module (shared)
authn_file_module (shared)
authz_core_module (shared)
authz_host_module (shared)
authz_user_module (shared)
autoindex_module (shared)
cgi_module (shared)
deflate_module (shared)
dir_module (shared)
env_module (shared)
filter_module (shared)
mime_module (shared)
mpm_event_module (shared)
negotiation_module (shared)
reqtimeout_module (shared)
rewrite_module (shared)
setenvif_module (shared)
status_module (shared)
module execution order is controlled by an internal priority scheme, and can't be changed unless you modify the Apache source and re-compile it.
a super pretentious way of saying
# "foo" and "second" do not exist
# I get "first" first, then "this"
SetEnvIf ^ ^ this=that
<If "-n %{QUERY_STRING}">
RewriteRule ^ - [E=first:1]
</If>
<Files "test.php">
RewriteRule ^ - [E=second:2]
</Files>
RewriteRule ^ - [E=foo:bar]
# "foo" and "second" do not exist
# I get "first" first, then "this"
RewriteRule ^ - [E=foo:bar]
<If "-n %{QUERY_STRING}">
RewriteRule ^ - [E=first:1]
</If>
SetEnvIf ^ ^ this=that
# "foo" does not exist
# I get "second", then "this"
RewriteRule ^ - [E=foo:bar]
SetEnvIf ^ ^ this=that
<Files "test.php">
RewriteRule ^ - [E=second:2]
</Files>
# "foo" does not exist
# "first" then "this"
RewriteRule ^ - [E=foo:bar]
<Files "test.php">
RewriteRule ^ - [E=first:1]
</Files>
SetEnvIf ^ ^ this=that
# "foo" then "this"
RewriteRule ^ - [E=foo:bar]
SetEnvIf ^ ^ this=that
# "foo" then "this"
SetEnvIf ^ ^ this=that
RewriteRule ^ - [E=foo:bar]
# "foo" does not exist
# "second" then "this"
SetEnvIf ^ ^ this=that
<Files "test.php">
RewriteRule ^ - [E=second:2]
</Files>
RewriteRule ^ - [E=foo:bar] When using a <Files> envelope, make sure there's a fresh "RewriteEngine on" inside the envelope, along with the one outside it.
What were you seeing before that made you add it? Was it an actual error, or something just not working right?Years ago when I had some of my RewriteRules inside a <Files> envelope, I saw that they simply didn't execute if I didn't repeat the instruction. fwiw, I dug through my HD and found an old htaccess from 2016 which used the <Files>. There are separate "RewriteEngine on" declarations, but nothing about inheritance.
SetEnvIf blahblah
RewriteRule blahblahwill come out with identical results to RewriteRule blahblah
SetEnvIf blahblah <Files "test.php">
RewriteRule ^ - [E=second:2]
</Files>is, again, identical to RewriteRule test\.php - [E=second:2]
or, for that matter, SetEnvIf Request_URI test\.php second=2
Since each module is an island, and anything inside a <FIles> executes later, it makes no difference what order the directives are in.
I hope this kind of thing is just for experimental purposes
RewriteRule (.*) /detour.html?$1 [R=302,L]
takes you to https://example.com/detour.html?/full/physical/filepath/originally-requested-file.html https://example.com/detour.html?originally-requested-file.html
RewriteRule ^ - [E=zero:1]
SetEnvIf ^ ^ this=that
<Files "test.php">
RewriteCond %{ENV:this} .+
RewriteRule ^ - [E=first:1]
SetEnvIfExpr "-n %{ENV:this}" second=2
</Files>
<If "-n %{ENV:this}">
RewriteRule ^ - [E=third:3]
</If> SetEnvIf ^ ^ this=that
<Files "test.php">
RewriteCond %{ENV:this} .+
RewriteRule ^ - [E=first:1]
SetEnvIfExpr "-n %{ENV:this}" second=2
<If "-n %{ENV:this}">
RewriteRule ^ - [E=third:3]
</If>
</Files> SetEnvIf ^ ^ this=that
<Files "test.php">
RewriteCond %{ENV:this} .+
RewriteRule ^ - [E=first:1]
SetEnvIfExpr "-n %{ENV:this}" second=2
<If "-n %{HTTP_HOST}">
RewriteRule ^ - [E=third:3]
</If>
</Files> If this option is enabled, all child configurations will inherit the configuration of the current configuration. It is equivalent to specifying RewriteOptions Inherit in all child configurations.Only in 2.4.8 and later, if that matters.
I assumed that core directives (eg, <Files> and <If>) would run first, process everything inside of them (rewrite > setenvif > setenv), then go back and process RewriteRules that were outside of them (meaning, those outside RewriteRules would overwrite whatever was written inside).
it would also be useful to read this as well:
https://httpd.apache.org/docs/2.4/sections.html#merging
be sure to read the "How the sections are merged" and "Relationship between modules and configuration sections" sections of the document.
At runtime, the core of httpd iterates over the defined configuration sections in the order described above to determine which ones apply to the current request. When the first section matches, it is considered the current configuration for this request. If a subsequent section matches too, then each module with a directive in either of the sections is given a chance to merge its configuration between the two sections. The result is a third configuration, and the process goes on until all the configuration sections are evaluated.
After the above step, the "real" processing of the HTTP request begins: each module has a chance to run and perform whatever tasks they like. They can retrieve their own final merged configuration from the core of the httpd to determine how they should act.
I realize you've been simplifying for posting purposes, but in the real file do you have a
RewriteOptions Inherit
(or InheritBefore, or whatever works for you?)
inside each separate envelope that uses mod_rewrite?
<IfModule rewrite_module>
RewriteOptions Inherit
</IfModule> As always, I don't see the necessity for the <Files> with all its hideous complications, when both mod_rewrite and mod_setenvif can act according to the Request_URI.
in simpler terms, the actual mod_rewrite/mod_env/mod_setenvif directives aren't processed until all configuration (<If>/<Files>/etc) containers/sections are evaluated and merged into a final set of configuration directives.
When <If> is used in .htaccess, the enclosed directives in a parent directory will be merged after non-enclosed directives in a subdirectory.
<IfModule rewrite_module>Oh, them and their IfModule. Anyway, “Inherit” by itself is pretty pointless if it's in the config file and there's nothing further upstream to inherit. For things to be universally inherited, rather than repeating the directive in each <Directory> and <Files> and .htaccess, you have so say InheritDown somewhere along the line. (This is the part I intend to explore on the test site when I get the energy.)
RewriteOptions Inherit
</IfModule>
I use <FilesMatch "variables\.(php|lib)%">. I thought this would be better than setting them for every image, JS, and CSS file unnecessarily?Again, making this envelope and putting a bunch of RewriteRules inside it is identical in effect to saying
RewriteRule variables\.(php|lib)% blahblah
and then you don't have the execution-order complication. (But what's the % for? Did you mean to say $ I hope?) I don't know what it is, but there's just something about the way that the docs are written that makes it just impossible to sink in.It's not just you. The docs definitely do have their issues--I particularly dislike many of their Regular Expressions--which is why we need phranque with his particular ability to Find Stuff.
Again, making this envelope and putting a bunch of RewriteRules inside it is identical in effect to saying
But what's the % for? Did you mean to say $ I hope?
But I have to say I don't perfectly understand the connection between “every image, JS, and CSS file” and "variables\.(php|lib)". You didn't get <FilesMatch> mixed up with <If> somewhere along the line, did you?
It wouldn't make sense to have the same condition before each of them, would it?There's no need for any Condition. If you're matching files of a particular type--whether that be URLpath, filename or extension--that goes in the body of the rule.
RewriteRule ^dirname/ blahblah
RewriteRule \bexactfilename\b blahblah
RewriteRule \.xtn$ blahblah
Am I wrong?I think you may not fully appreciate the role of the pattern in a RewriteRule. I've said elsewhere that, as a general rule, don't put anything in a RewriteCond that can be put in the body of the RewriteRule. (There exist exceptions, but they don't apply here.)
RewriteRule !variables\.(php|lib)$ - [S=some-number]meaning “if the requested file is NOT variables.php or variables.lib then skip the next so-and-so-many rules. (Counting only the rules themselves, not Conditions or blank lines or comments.) This does require some attention to ensure you have an accurate count of rules-to-skip. Note that this same effect can be obtained using SetEnvIf. This technique is offered as an example, not as a recommendation.and this time I have to agree.
SetEnvIf Request_URI (\w+)\.(php|lib) jigsaw=$1
or SetEnvIf Host (\w+)\.com foobar=$1
and then use those jigsaw and foobar values for whatever murky and nefarious purpose you need them for.
If you're matching files of a particular type--whether that be URLpath, filename or extension--that goes in the body of the rule.
Now, you may find it appropriate to use the [S] flag with the rarely-used negative pattern:
SetEnvIf foo a lorem=1
SetEnvIf foo b lorem=2
SetEnvIf foo c lorem=3 SetEnvIf foo a lorem=1Yup, that's what I meant about captures. It would be a lot simpler if the rule could instead say
SetEnvIf foo b lorem=2
SetEnvIf foo c lorem=3
SetEnvIf foo (a|b|c) lorem=$1and then when you get to the code that uses “lorem” it works on a, b or c rather than 1, 2 or 3. But then we're back to the question of why it can’t simply use “foo” in the first place--dunno about perl, but pretty much all aspects of the request are available to php--though this may not be answerable without disclosing too much about the sites involved.