17

I set an environment variable in httpd-vhosts.conf

SetEnv EARLY_VAR 1

I try setting special rules based on its value in .htaccess

<If "%{ENV:EARLY_VAR} == '1'">
   SetEnv TEST_VAR  if_branch
</If>
<Else>
    SetEnv TEST_VAR  else_branch
</Else>

I expect TEST_VAR environment var to equal if_branch. In PHP

var_dump(getenv('EARLY_VAR')); // string '1'
var_dump(getenv('TEST_VAR')); // string 'else_branch'

I also tried setting EARLY_VAR in .htaccess above the If/Else, both using SetEnv and SetEnvIf. Always the Else branch is executed.

Why is this?

Apache 2.4

hjpotter92
  • 78,589
  • 36
  • 144
  • 183
BeetleJuice
  • 39,516
  • 19
  • 105
  • 165
  • Not seeing `%{ENV:` as a valid expression here ~ http://httpd.apache.org/docs/2.4/expr.html. There is the `env` function though – Phil Sep 13 '16 at 04:10
  • 2
    @Phil Thanks for the tip. The documentation language on that page is difficult to understand but I think you put me on the right track – BeetleJuice Sep 13 '16 at 04:53
  • @Phil `%{ENV:` is also valid.and would be expanded as `"%{" funcname ":" funcargs "}"` – hjpotter92 Sep 13 '16 at 06:20
  • @hjpotter92 can you link to some documentation for that? – Phil Sep 13 '16 at 06:21
  • 1
    @Phil The link that you provided, under the section for Bachus Naur grammar, see the expansion of `variable`. The list of functions is also provided a little down the page. – hjpotter92 Sep 13 '16 at 06:24
  • I just tried to doc the risk of using envvars in conditions in the manual. – covener Sep 17 '16 at 20:44

4 Answers4

8

Without using expression i.e. if/else directives you can do this:

# set EARLY_VAR to 1
SetEnvIf Host ^ EARLY_VAR=1

# if EARLY_VAR is 1 then set TEST_VAR to if_branch
SetEnvIf EARLY_VAR ^1$ TEST_VAR=if_branch

# if EARLY_VAR is NOT 1 then set TEST_VAR to else_branch
SetEnvIf EARLY_VAR ^(?!1$) TEST_VAR=else_branch

This will work with even older Apache versions i.e. <2.4


EDIT:

In your Apache config or vhost config have this variable initialization:

SetEnvIf Host ^ EARLY_VAR=5

Then in your .htaccess you can use:

<If "env('EARLY_VAR') == '5'">
   SetEnv TEST_VAR if_branch
</If>
<Else>
   SetEnv TEST_VAR else_branch
</Else>

Reason why you need env variable declaration in Apache/vhost config because .htaccess is loaded after Apache/vhost config and env variables set in same .htaccess are not available for evaluation in if/else expressions.

Also, note that it is important to use SetEnvIf instead of SetEnv to make these variables available to if/else expressions.

anubhava
  • 761,203
  • 64
  • 569
  • 643
  • Thanks. I'm using `` and `` because I want to wrap a big block of many directives for two different environments. I used `SetEnv` within the blocks just as a quick way for me to check from my PHP script which branch was executed. I don't actually need to set that `TEST_VAR`. It's a placeholder for a group of directives. – BeetleJuice Sep 13 '16 at 04:31
  • 1
    Well explained. It worked on my dev machine but on the server I get error `/path/.htaccess: Invalid command 'SetEnv', perhaps misspelled or defined by a module not included in the server configuration` So to set `TEST_VAR` in htaccess I did `SetEnvIf Host ^ TEST_VAR=if_branch`. Thank you – BeetleJuice Sep 13 '16 at 10:11
  • 1
    The problem here is that variables referenced in the itself are resolved as close to immediately after htaccess files are parsed. Therefore any module which can be configured in htaccess invariable runs after . mod_setenvif is somewhat unique in that it can run its code early when you put it outside of any configuration section. Almost no other module does that. I think the best pattern here is to try to shoe-horn into directives that take expressions as conditionals – covener Sep 17 '16 at 20:14
  • 1
    @anubhava. I was specifically looking for this: https://httpd.apache.org/docs/current/mod/core.html#if. But I was able to find it within the page you linked. Thanks for the help. – domdambrogia Mar 12 '19 at 18:19
  • For more detailed docs, please refer: https://httpd.apache.org/docs/current/expr.html – anubhava Mar 12 '19 at 18:23
5

Looking at the documentation of SetEnv directive, I notice:

Sets an internal environment variable, which is then available to Apache HTTP Server modules, and passed on to CGI scripts and SSI pages.

which means that the environments are then available to other modules. Whereas, <if> directive is provided by the core. This can be confirmed if you try to see whether the environment is empty during the <if> clause:

<If "-z %{ENV:EARLY_VAR}">
   SetEnv TEST_VAR  if_branch
</If>

or

<If "-z env('EARLY_VAR')">
   SetEnv TEST_VAR  if_branch
</If>

both will give you:

string(1) "1" string(9) "if_branch" 

in your PHP.


There is also the following caveat listed on the Apache's environment variables wiki/docs pages:

The SetEnv directive runs late during request processing meaning that directives such as SetEnvIf and RewriteCond will not see the variables set with it.

hjpotter92
  • 78,589
  • 36
  • 144
  • 183
  • Thanks for your input and tests. Does this mean that I cannot use `If/Else` branching based on an environment var? In particular a var set in the same `.htaccess`. Perhaps it could work with a var set through `SetEnvIf`? – BeetleJuice Sep 13 '16 at 09:40
  • 1
    @BeetleJuice Not in the same context, no! You'd have to set the environment at a context at least one level above the `` directive location. – hjpotter92 Sep 13 '16 at 09:43
  • See comment under @anubhava's answer for a description of what unique thing is going on here. It is not an issue of an enclosing section, because that would not affect the execution timing. – covener Sep 17 '16 at 20:15
1

The only way I could make it work is using SetEnvIf both in .conf and .htaccess:

I used only this in .conf

SetEnvIf Server_Addr ^ EARLY_VAR=1

and then only this in .htaccess :

SetEnvIf EARLY_VAR ^ TEST_VAR=else_branch
SetEnvIf EARLY_VAR ^1$ TEST_VAR=if_branch

(without If directive. Whatever I tried within If, it seemed like it was evaluated before EARLY_VAR is set)

Dusan Bajic
  • 10,249
  • 3
  • 33
  • 43
  • Please specify whether you mean that you did one or the other, or you had to do both (`.conf` and `.htaccess` settings). Please also show the expression within `` as well. – BeetleJuice Sep 13 '16 at 09:37
  • No `If` unfortunately, so the usability of this approach is quite limited – Dusan Bajic Sep 13 '16 at 09:48
0

If you found problem with SetEnv and SetEnvIf in your Apache configuration.

Set the variable in httpd.conf file as below

SetEnvIf Host ".*" EARLY_VAR=1
SetEnvIf Host eval EARLY_VAR=1
SetEnvIf Host dev EARLY_VAR=1

It assign the value in all type of server (production ,evaluation or development)

Now you can use your variable in .htaccess file.

<IF "%{ENV:EARLY_VAR} == 1">
    SetEnv TEST_VAR if_value
</IF>
<ELSE>
    SetEnv TEST_VAR else_value
</ELSE>
Shailesh Chauhan
  • 559
  • 3
  • 14