One of those moments again where the search engine did not turn up information which I need. So I hope this article will be helpful to someone out there.

It seems that environment variables in Apache are not being treated equally when SetEnv, SetEnvIf and RewriteRule directives are used. In my case, I want to limit access based on query string but SetEnvIf does not have that attribute to test against. RewriteRule creates an environment variable that is not accessible by Allow/Deny directive (Possibly because Allow/Deny are evaluated before RewriteRule). It makes things complicated when you are going to use environment variables to limit access but it does not work as expected.

Unfortunately, I do not have a solution for you but I hope this information will save you countless hours researching a solution that never exists. But if you do have one, please let me know as I would love to hear from you.

.htaccess Test Configuration

You can skip this part actually. But if you are interested in how the test is done, you can continue reading.

RewriteEngine On

# Putting Header before setting the environment variables do not seem to matter.
Header always add A_1 "%{A_1}e"
Header always add B_1 "%{B_1}e"
Header always add C_1 "%{C_1}e"
Header always add U_1 "%{U_1}e"

Header always add A_2 "%{A_2}e"
Header always add B_2 "%{B_2}e"
Header always add C_2 "%{C_2}e"
Header always add U_2 "%{U_2}e"

Header always add A_3 "%{A_3}e"
Header always add B_3 "%{B_3}e"
Header always add C_3 "%{C_3}e"
Header always add U_3 "%{U_3}e"

Header always add A_4 "%{A_4}e"
Header always add B_4 "%{B_4}e"
Header always add C_4 "%{C_4}e"
Header always add U_4 "%{U_4}e"

Header always add A_5 "%{A_5}e"
Header always add B_5 "%{B_5}e"
Header always add C_5 "%{C_5}e"
Header always add U_5 "%{U_5}e"
Header always add S_5 "%{S_5}e"

# Test to see if (1) Header can access the environment variables.
SetEnv A_1 SetEnv_Works
SetEnvIf always_match ^ B_1=SetEnvIf_Works
RewriteRule .* - [E=C_1:RewriteRule_Works,NE]
# U_1 is not set deliberately.

# Test to see if (2) SetEnvIf can access the environment variables.
SetEnvIf A_1 ^(.*)$ A_2="$1"
SetEnvIf B_1 ^(.*)$ B_2="$1"
SetEnvIf C_1 ^(.*)$ C_2="$1"
SetEnvIf U_1 ^(.*)$ U_2="$1"

# Test to see if (3) RewriteCond can access the environment variables.
RewriteCond %{ENV:A_1} ^(.*)$
RewriteRule .* - [E=A_3:"%1",NE]
RewriteCond %{ENV:B_1} ^(.*)$
RewriteRule .* - [E=B_3:"%1",NE]
RewriteCond %{ENV:C_1} ^(.*)$
RewriteRule .* - [E=C_3:"%1",NE]
RewriteCond %{ENV:U_1} ^(.*)$
RewriteRule .* - [E=U_3:"%1",NE]

# Test to see if (4) RewriteRule can access the environment variables.
RewriteRule .* - [E=A_4:"%{ENV:A_1}",NE]
RewriteRule .* - [E=B_4:"%{ENV:B_1}",NE]
RewriteRule .* - [E=C_4:"%{ENV:C_1}",NE]
RewriteRule .* - [E=U_4:"%{ENV:U_1}",NE]

# Test to see if (5) <IfDefine> can access the environment variables.
<IfDefine A_1>
    SetEnv A_5 Can_Access
<IfDefine B_1>
    SetEnv B_5 Can_Access
<IfDefine C_1>
    SetEnv C_5 Can_Access
<IfDefine U_1>
    SetEnv U_5 Can_Access
SetEnv S_5 Unconditionally_Set

# Test to see if (6) Allow/Deny can access the environment variables.
Options +Indexes
Order Deny,Allow
Deny from all
# To test, only one should be uncommented at any point in time.
#Allow from env=A_1
#Allow from env=B_1
#Allow from env=C_1
#Allow from env=U_1
Allow from all    # Required for (3) RewriteCond and (4) RewriteRule test to work properly.

Test Result

A_1	SetEnv_Works
B_1	SetEnvIf_Works
C_1	RewriteRule_Works
U_1	(null)
A_2	""
B_2	"SetEnvIf_Works"
C_2	""
U_2	""
A_3	""
B_3	"SetEnvIf_Works"
C_3	"RewriteRule_Works"
U_3	""
A_4	""
B_4	"SetEnvIf_Works"
C_4	"RewriteRule_Works"
U_4	""
A_5	(null)
B_5	(null)
C_5	(null)
U_5	(null)
S_5	Unconditionally_Set


Set Using (U)
Accessible By (1) Header Yes Yes Yes (null)
(2) SetEnvIf No Yes No
(3) RewriteCond* No Yes Yes
(4) RewriteRule* No Yes Yes
(5) No No No No
(6) Allow/Deny
No Yes No

*Will not work if “Deny from all” is in effect.

Excellent References: