Author |
|
csdude55
Joined: 22 Jan 2023 Posts: 23 Location: USA, Wilkesboro
|
Posted: Sun 22 Jan '23 22:54 Post subject: Using IF-ELSE with ENV variables |
|
|
Hi all! Long time coder, first time poster to this board.
I'm not sure how Apache handles the order, but when I set an ENV prior to the IF-ELSE it doesn't appear to be read. Or maybe I'm reading it wrong. More below.
Also, when I run a regex in the IF, the %1 isn't being carried into the results.
Example:
Code: | # www.example.com sets %{ENV:linker} = example
RewriteCond %{HTTP_HOST} ^(?:www\.)?([^.]+)\. [NC]
RewriteRule ^ - [E=linker:${lc:%1}]
# expecting %{ENV:tester} = ex
<If "%{ENV:linker} =~ /(ex)ample/i">
RewriteRule ^ - [E=tester:%1]
</If> |
I print all of the $_SERVER variables in PHP for testing. I can see that $_SERVER['linker'] is properly set to "example", but there's no $_SERVER['tester'];
Then I tried this modification:
Code: | RewriteCond %{HTTP_HOST} ^(?:www\.)?([^.]+)\. [NC]
RewriteRule ^ - [E=linker:${lc:%1}]
<If "%{HTTP_HOST} =~ m#^(?:www\.)?(ex)ample\.#i">
RewriteRule ^ - [E=tester:%1]
</If> |
This time $_SERVER['tester'] is set so the IF is true, but tester is empty so %1 has no value.
I tried every variation of reqenv() and env() that I could think of from the docs, but nothing worked like I thought.
Any suggestions?[/code] |
|
Back to top |
|
James Blond Moderator
Joined: 19 Jan 2006 Posts: 7371 Location: Germany, Next to Hamburg
|
|
Back to top |
|
csdude55
Joined: 22 Jan 2023 Posts: 23 Location: USA, Wilkesboro
|
Posted: Mon 23 Jan '23 22:07 Post subject: |
|
|
Thanks, James. I'm afraid it doesn't help, though; it just confirms that nested IF-ELSE is OK, but doesn't say anything about using ENV variables or backreferences.
I should have stated before that I'm using 2.4.55
The saga has gotten even more confusing, though. It looks like the IF will actually delete previously assigned ENV? I discovered that if I remove the IF statement then I'll get a value for $_SERVER['linker'], but when I have the IF statement then $_SERVER['linker'] is gone; not empty, but appears to have never been set. |
|
Back to top |
|
tangent Moderator
Joined: 16 Aug 2020 Posts: 348 Location: UK
|
Posted: Mon 23 Jan '23 22:12 Post subject: |
|
|
Re your attempt to use regex backreferences to help set environment variables:
The Apache documentation for expr https://httpd.apache.org/docs/current/expr.html says:
The strings $0 ... $9 allow to reference the capture groups from a previously executed, successfully matching regular expressions. They can normally only be used in the same expression as the matching regex, but some modules allow special uses.
So your "RewriteRule ^ - [E=tester:%1] " won't find %1 (nor $1) from expr.
What you can do though, is use SetEnvIfExpr, e.g.
Code: |
SetEnvIfExpr "%{HTTP_HOST} =~ m#^(?:www\.)?(ex)ample\.#i" tester=$1 |
This construct does set environment variables based on expr regex backreferences.
Hope this helps. |
|
Back to top |
|
csdude55
Joined: 22 Jan 2023 Posts: 23 Location: USA, Wilkesboro
|
Posted: Mon 23 Jan '23 22:20 Post subject: |
|
|
I see. So it'd have to duplicate the regex.
Code: | <If "%{HTTP_HOST} =~ m#^(?:www\.)?(ex)ample\.#i">
SetEnvIfExpr "%{HTTP_HOST} =~ m#^(?:www\.)?(ex)ample\.#i" tester=$1
</If> |
Not exactly fast or logical, but maybe it'll improve in a future release
If I can't read the ENV variable inside of the IF, though, then I think I'm going to have to redo a LOT of my config! |
|
Back to top |
|
tangent Moderator
Joined: 16 Aug 2020 Posts: 348 Location: UK
|
Posted: Mon 23 Jan '23 22:38 Post subject: |
|
|
Reading established ENV variables within subsequent IF statements should be fine.
I sort of agree with your concern, but think the issue here is you can't reasonably expect regex back references from expr logic in an IF match statement, to be available to (or be honoured by) other module code enclosed within said logical blocks.
If you look at all the expr builtin functions, you'll see they're all read or lookup related, and don't write anything outside the expr scope.
Maybe that's why the developers came up with SetEnvIfExpr. |
|
Back to top |
|
tangent Moderator
Joined: 16 Aug 2020 Posts: 348 Location: UK
|
Posted: Mon 23 Jan '23 23:05 Post subject: |
|
|
I've just read your last post more carefully, and wondered, why you've duplicated the regex?
You don't need the initial IF condition, since that's covered by the SetEnvIfExpr statement, or am I missing something? |
|
Back to top |
|
csdude55
Joined: 22 Jan 2023 Posts: 23 Location: USA, Wilkesboro
|
Posted: Tue 24 Jan '23 0:32 Post subject: |
|
|
Quote: | Reading established ENV variables within subsequent IF statements should be fine. |
Any suggestions on why this fails, then?
Code: | RewriteRule ^ - [E=foo:bar]
<If "-n %{ENV:foo}">
RewriteRule ^ - [E=lorem:ipsum]
</If> |
I've tried with reqenv('foo'), env(), and every other option listed in the docs, but they all fail.
Using -z matches, though, which means that either the IF doesn't recognize the ENV, or I'm referring to it incorrectly.
Quote: | I've just read your last post more carefully, and wondered, why you've duplicated the regex? |
What I'm posting here has been super simplified, just trying to figure out the format. The final config would be more complex, running several RewriteRules when the IF succeeds and then several alternatives when it fails.
It's also for my own education. In production I have 82kb of data in the config files, and perfecting this style might help me cut that down quite a bit. Which, in theory, would result in faster processing.
It's starting to look like I might have to have a RewriteCond for each of those rules, though, instead of a single all-encompassing IF :-/[/quote] |
|
Back to top |
|
csdude55
Joined: 22 Jan 2023 Posts: 23 Location: USA, Wilkesboro
|
Posted: Tue 24 Jan '23 8:09 Post subject: |
|
|
Somewhat of an update...
I found that this will kinda work:
Code: | RewriteRule ^ - [E=foo:bar]
<FilesMatch "\.php$">
<If "-n %{ENV:foo}">
RewriteRule ^ - [E=lorem:ipsum]
</If>
RewriteRule ^ - [E=this:that]
</FilesMatch> |
This will print $_SERVER['foo'] and $_SERVER['lorem']...
... but not $_SERVER['this'] :-/
Thoughts? |
|
Back to top |
|
James Blond Moderator
Joined: 19 Jan 2006 Posts: 7371 Location: Germany, Next to Hamburg
|
Posted: Tue 24 Jan '23 10:21 Post subject: |
|
|
it might be easier to set the env inside the vhost config
Code: |
<VirtualHost *:80>
ServerName example.com
# ... other stuff
SetEnv vhostname example.com
Header add X-Server-Name %{vhostname}e
</virtualhost>
<VirtualHost *:80>
ServerName example.lan
# ... other stuff
SetEnv vhostname example.lan
Header add X-Server-Name %{vhostname}e
</virtualhost>
|
|
|
Back to top |
|
tangent Moderator
Joined: 16 Aug 2020 Posts: 348 Location: UK
|
Posted: Tue 24 Jan '23 22:04 Post subject: |
|
|
@csdude55 - further to your latest post (and James reply), which I've only just been able to respond to.
Through testing, I agree there are some inconsistencies with IF statements seeing Apache defined environment variables, depending on whether they are at a global level, or within a virtual host. Indeed, an IF env test within a vhost seems to circumvent an IF env test that otherwise works at the global level.
The expr documentation does have a section on "Environment variable ordering" which along with your findings suggests this approach is somewhat of a minefield.
Historically, I've stuck to mod_rewrite logic for environment variable manipulation, using rewrite conditions with appropriate flags, accepting you can't create configuration logic that reads as elegantly as IF-ELSE blocks, but at least it works as expected. |
|
Back to top |
|
James Blond Moderator
Joined: 19 Jan 2006 Posts: 7371 Location: Germany, Next to Hamburg
|
Posted: Fri 27 Jan '23 22:02 Post subject: |
|
|
I haven't tested it with the IF statements, but with all other things in apache: .htaccess overrides vhost that overrides global.
.htaccess
vhost
global |
|
Back to top |
|