Forum Moderators: coopster & phranque

Message Too Old, No Replies

Reading [E] variables set in Apache

         

csdude55

10:06 pm on Jan 21, 2021 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



I have a lot of variables set in Apache using [E], which really was MUCH faster to process than setting them in PHP! But I have no idea how to access them via Perl; specifically, the username and password for MySQL, which I thought might be safer to store in Apache.

They all show up under $_SERVER in PHP, so I know they're working properly. But they don't show up in the %ENV hash (there are 72 values, just not the ones I've defined), and there's not a %SERVER or %_SERVER hash.

I've read that there's some issue with suexec and environment variables, but (a) I have no idea how to see if Perl is using suexec, and (b) since it shows up in PHP I don't think that's the issue?

Any other suggestions?

Brett_Tabke

10:33 pm on Jan 21, 2021 (gmt 0)

WebmasterWorld Administrator 10+ Year Member Top Contributors Of The Month



print out %ENV hash.

#$ENV{REMOTE_HOST}
#$ENV{REMOTE_ADDR}
#$ENV{'HTTP_USER_AGENT'}

foreach $enVar (sort keys %ENV) {
print "$enVar : $ENV{$enVar} <br>";
}

csdude55

10:40 pm on Jan 21, 2021 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



That's more or less what I did, but the ones I set with [E] aren't showing up.

foreach (sort keys %ENV) {
print $_ . ' = ' . $ENV{$_} . "\n";
}

Brett_Tabke

10:48 pm on Jan 21, 2021 (gmt 0)

WebmasterWorld Administrator 10+ Year Member Top Contributors Of The Month



no clue with [E], but that sounds outside the SCOPE of the Apache instance. Only if you set the variable in PHP, then call/execute the Perl as a subprocess, will that be the same instance of Apache.

phranque

11:06 pm on Jan 21, 2021 (gmt 0)

WebmasterWorld Administrator 10+ Year Member Top Contributors Of The Month



the ones I set with [E] aren't showing up


... Apache (or mod_perl) don't pass on environment variables from the shell by default; you'll have to specify these using either the standard PassEnv or mod_perl's PerlPassEnv directives.

(source: https://perl.apache.org/docs/1.0/guide/config.html#PerlSetEnv_and_PerlPassEnv

Apache Module mod_env PassEnv Directive documentation:
http://httpd.apache.org/docs/current/mod/mod_env.html#passenv

csdude55

12:18 am on Jan 22, 2021 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Hmm. So you're saying that I need to install mod_env with Apache, then it'll show up?

I currently have them set in Apache using:

RewriteRule ^ - [E=foo:bar]


Would I also need to change that this?:

SetEnv foo bar


The PassEnv section makes no sense at all to me :-O

phranque

1:16 am on Jan 22, 2021 (gmt 0)

WebmasterWorld Administrator 10+ Year Member Top Contributors Of The Month



after reading the Environment Variables in Apache [httpd.apache.org] document, i am also confused.
Second, the Apache HTTP Server provides a mechanism for storing information in named variables that are also called environment variables. This information can be used to control various operations such as logging or access control. The variables are also used as a mechanism to communicate with external programs such as CGI scripts.

and
The most basic way to set an environment variable in Apache is using the unconditional SetEnv directive.

i always thought the [E] flag was equivalent to SetEnv(If):
Environment variables can then be used in a variety of contexts, including CGI programs, ...

source: http://httpd.apache.org/docs/current/rewrite/flags.html#flag_e

i would try testing with an actual SetEnv directive and see if anything shows up.

lucy24

6:54 am on Jan 22, 2021 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



i always thought the [E] flag was equivalent to SetEnv(If)
The complication is that, by the usual reverse-alphabetical-order guideline, mod_rewrite (RewriteRule with [E] flag, OR RewriteCond looking at %{ENV:blahblah}) executes after mod_setenvif (SetEnvIf directive) but before mod_env [httpd.apache.org] (simple SetEnv directive). But of course this is only relevant if you're using the environmental variable in a RewriteRule. By the time you reach the page--whether it's php, perl or something else--everything should be set regardless.

Got a vague recollection that in php there are two slightly different ways to get at environmental variables, depending on whether they're built-in or ones you set yourself. Does perl do something similar?

Brett_Tabke

5:31 pm on Jan 22, 2021 (gmt 0)

WebmasterWorld Administrator 10+ Year Member Top Contributors Of The Month



Ok, I kinda see what you are trying to do now.

How are you setting the apache variables? .htaccess or httpd.conf?

csdude55

5:51 pm on Jan 22, 2021 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Ya'll... I'm stupid. I'm sorry :-(

In my .conf files, I remembered that I had explicitly told it to not apply any rewrites to my CGI bin:

RewriteRule ^/(?:(?:includes|images|cgi-bin|cache)/)|404\.php - [PT]


I placed the [E] before this, and now it works. So it was an ID-ten-T error all along.

Sorry about that!

csdude55

11:58 pm on Jan 22, 2021 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



On a slight tangent, any guess on a way to select JUST the environment variables that I set? %ENV has 72 server variables in it.

It would be easier to do something like this rather than converting them all manually, but I don't want ALL of them to be set to a variable:

foreach (sort keys %ENV) {
$$_ = $ENV{$_};
}

phranque

1:56 am on Jan 23, 2021 (gmt 0)

WebmasterWorld Administrator 10+ Year Member Top Contributors Of The Month



a way to select JUST the environment variables that I set?

i'm pretty sure the Env perl module [perldoc.perl.org] is what you are looking for.

csdude55

2:42 am on Jan 23, 2021 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



If I'm reading correctly, though, it would still convert all of them, right? Like GATEWAY_INTERFACE, REQUEST_SCHEME, SSL_CIPHER, etc?

I'm not sure that it really matters, other than just have 72 unnecessary scalars.

lucy24

3:12 am on Jan 23, 2021 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



foreach (sort keys %ENV)
Could the "foreach" be replaced with something that takes an argument, using the specific name of the variable you’re interested in?

Let's not talk about something clunky like putting in a further loop to the effect of "if {thing I'm currently looking at} == {some specific value} then-and-only-then {do stuff}".

phranque

4:19 am on Jan 23, 2021 (gmt 0)

WebmasterWorld Administrator 10+ Year Member Top Contributors Of The Month



If I'm reading correctly, though, it would still convert all of them, right?

quoted from the Env documentation, my emphasis added:
The Env::import() function ties environment variables with suitable names to global Perl variables with the same names. By default it ties all existing environment variables (keys %ENV) to scalars. If the import function receives arguments, it takes them to be a list of variables to tie; it's okay if they don't yet exist.

csdude55

6:31 am on Jan 23, 2021 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Don't take this the wrong way or anything, @phranque, but... sometimes, man, you make me feel really stoopid :-P

I mean, I read that, but it might as well be written in Latin or something because I don't know what they're trying to say. The docs make a vague reference to Env::import(), but there's no example of how I'm supposed to use it or anything.

Taking a relatively wild guess here, is it saying that if I did this in Apache:

RewriteRule ^ - [E=foo:bar]
RewriteRule ^ - [E=lorem:ipsum]


And then did this in Perl:

use Env::import('foo');


then it would create $foo == 'bar', but not $lorem ?

If so, that would more or less defeat my goal here. This is a site that's still in development, of course, and I might add variables to the .conf that I would want to carry over to php, cgi, pl, and lib scripts. I'm hoping to not have to remember to add anything in all 4 locations, though, which is why I would rather have something a little more automated so that once it's added to the .conf, it's everywhere.


Let's not talk about something clunky like putting in a further loop to the effect of "if {thing I'm currently looking at} == {some specific value} then-and-only-then {do stuff}".

@lucy24... I was absolutely NOT about to suggest writing my variables in lower case, then in the loop:

foreach (keys %ENV) {
if ($_ == lc($_)) {
$$_ = $ENV{$_};
}
}


LOL

phranque

7:42 am on Jan 23, 2021 (gmt 0)

WebmasterWorld Administrator 10+ Year Member Top Contributors Of The Month



This is a site that's still in development, of course, and I might add variables to the .conf that I would want to carry over to php, cgi, pl, and lib scripts.

but you would have to change the script(s) to use the new variable, correct?
it seems like adding another argument to the list of tied variables is a small effort compared to implementing new code using the new variable elsewhere in the script.

phranque

7:46 am on Jan 23, 2021 (gmt 0)

WebmasterWorld Administrator 10+ Year Member Top Contributors Of The Month



then it would create $foo == 'bar', but not $lorem ?

yes and then you would also not have access to variables such as $REMOTE_HOST and $HTTP_USER_AGENT.

lucy24

5:42 pm on Jan 23, 2021 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



I was absolutely NOT about to suggest writing my variables in lower case, then in the loop
Haha, see, that’s pretty exactly what I ended up doing in my logheaders routine when I expanded it to record any environmental variables that I’ve set. Turns out there’s a slew of variables set by the server that I’m not interested in, but fortunately they are in ALL_CAPS while my own variable names are lower-case. So I really do have a loop that says "if the name of the environmental variable starts with a lower-case letter, AND it has a non-zero value, then do this extra thing”.

It is disheartening how often, in various situations, two steps forward and one back turns out to be the easiest solution, though not necessarily the most elegant or efficient.

csdude55

7:03 pm on Jan 23, 2021 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



but you would have to change the script(s) to use the new variable, correct?
it seems like adding another argument to the list of tied variables is a small effort compared to implementing new code using the new variable elsewhere in the script.

Not exactly, @phranque. See, on every PHP script I use require_once $_SERVER['DOCUMENT_ROOT'] . '/variables.php';, and every Perl script uses require $ENV{'DOCUMENT_ROOT'} . '/cgi-bin/variables.lib'; (typed, not pasted, so please ignore any typos).

As development continues, I might find it better to put a new variable in the Apache .conf that could be used everywhere. Something automated would keep me from having to remember to put it in the two variables scripts, I could just add it to the one and go on. It's not a huge deal or anything, it's just something that might save me 2 steps down the road.

So I really do have a loop that says "if the name of the environmental variable starts with a lower-case letter, AND it has a non-zero value, then do this extra thing”.

Haha, well, if it's good enough for @lucy24 then it's good enough for me :-)

I didn't think about checking for a non-zero value. If it's '' or 0, maybe I should set the scalar to false?

Key_Master

7:16 pm on Jan 23, 2021 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Check out mod_setenvif

SetEnvIf foo ^bar$ lorem=ipsum

Key_Master

7:21 pm on Jan 23, 2021 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



You can also do:

RewriteCond %{ENV:foo} ^bar$
RewriteRule ^ - [E=lorem:ipsum]

phranque

7:25 pm on Jan 23, 2021 (gmt 0)

WebmasterWorld Administrator 10+ Year Member Top Contributors Of The Month



Check out mod_setenvif

how does this address the stated problem of accessing an apache environment variable in perl?

Key_Master

7:51 pm on Jan 23, 2021 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



I suspect the variables he is setting are not being set in $_ENV but rather $_SERVER. Setenvif will ensure his custom variables will be available to cgi scripts.

He could also be subject to suexec security issues. In such a case, he will need to prepend his variables with HTTP_. For example, use HTTP_foo instead of foo.

Timing is also important. Foo needs to be set to bar before lorem can be set to ipsum.

lucy24

10:28 pm on Jan 23, 2021 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



I didn't think about checking for a non-zero value. If it's '' or 0, maybe I should set the scalar to false?
This is probably a site-specific question. I do it because sometimes I set a variable and later un-set it, and I want to make double-sure the unset ones are ignored. (Apache docs say it is “removed”, but sometimes I am over-anxious.) On the other hand, if your environmental variables might actually have a value of zero or empty string, then obviously you should not impose this limitation.

Timing is also important. Foo needs to be set to bar before lorem can be set to ipsum.
So that's a situation where ordering of modules--assuming you're setting them in Apache before arriving at your script--can make a difference. Stuff that if done in mod_setenvif will be available to mod_rewrite but not vice versa, and stuff done in mod_env will not be available to either of the others.

phranque

12:39 am on Jan 24, 2021 (gmt 0)

WebmasterWorld Administrator 10+ Year Member Top Contributors Of The Month



He could also be subject to suexec security issues. In such a case, he will need to prepend his variables with HTTP_.

there's not much documentation on this but if you are using suexec, you need to modify the safe_env_lst variable in suexec.c before any custom variable will be passed.

i found an old sample of the source code to give you an idea of what you are looking for:
suexec.c [askapache.com]