How to set global environment variables for PHP - php

I have read the question/answers here but I don't understand how to set variables in /etc/environment. If I edit the file, do I need to restart my machine or simply log out my current user (or log in a new one?).
I want to set a global variable to denote that websites on my machine are in 'development' or 'testing' mode. I don't want to have to set this for every project (whether it uses PHP, Java/Tomcat, NodeJS, etc). I'm aware that (for Apache) I can set the environment variable in the following ways:
directly from php with putenv() (this seems useless since I want to avoid logic that tries to figure out what server the files are on)
using .htaccess SetEnv ENVIRONMENT 'local' (this would require me to duplicate this file/code for every server, not ideal)
using a Virtual Host directive SetEnv ENVIRONMENT 'local' (if I'm using a virtual host, which in nearly all cases I am, but again requires me to copy/paste code over and over again)
in httpd-conf SetEnv ENVIRONMENT 'local' (this will only apply to apache, and I would like it to apply to NodeJS servers as well)
I'm not saying I can't do #4 (and apply #3 selectively to NodeJS servers). But I'm thinking that this is a good reason to use /etc/environment. As I said above, I have edited the file (after first creating it) and tried the following combinations, none of which seemed to work:
ENVIRONMENT='local'
ENVIRONMENT=local
export ENVIRONMENT='local'
export ENVIRONMENT=local
I say that none of them worked because I did not find the variable in output from:
print_r($_SERVER);
print_r($_ENV);
echo(getenv('ENVIRONMENT'));

What you want to do is use an Apache configuration file. You will need access to a configuration folder and the httpd.conf file (or modified version). You can then configure the httpd.conf to dynamically load configuration files using this approach
Include conf.d/*.conf
Inside the conf.d folder you place your specific environment configuration files.
server-environment-dev.conf example:
SetEnv ENVIRONMENT "local"
server-environment-prod.conf example:
SetEnv ENVIRONMENT "production"
These settings will show up in your php code as available environment variables. This approach allows you to keep your vhost files, .htaccess, and your other configuration files agnostic of the environment.
etc/environment, etc/profile.d, .bash_profile, .profile, etc files are not readable by PHP in Apache due to some process/user limitations. You can bash, smash, crash the variables all you want and see them set in your terminal but they will not show up in phpinfo() unless you set it via one of the Apache configuration files.
For NodeJS you can start the app passing in your environment variable or you can set the NODE_ENV in multiple ways include your .bash_profile and possibly etc/environment file if you want to be user agnostic.
A good read for Node:
http://www.hacksparrow.com/running-express-js-in-production-mode.html

So I would assume you have a global config file somewhere. Why not put a constant in that file that you can change? Would be far easier that trying to set something on the server level.
define('ENVIRONMENT', 'testing');
if(ENVIRONMENT == 'testing') {
echo 'We\'re just testing';
}

If you still can't get your environment variables:
you may need to edit your real httpd.conf in
~/Library/Application Support/appsolute/MAMP PRO/
instead of
/Applications/MAMP/conf/apache/
Also you may need to use getenv() instead of $_ENV

Related

Is it safe to source system-wide environment variables in apache envvars?

I am trying to set an environment variable on Linux which should be available in shell as well as Apache.
I added the variable to /etc/environment, so the file looks something like this:
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
MY_VAR="foo"
To have MY_VAR available in apache, this is what I added in /etc/apache2/envvars:
. /etc/environment
export MY_VAR=$MY_VAR
After doing a lot of research, this is the only way I was able to get the same environment variable work system-wide and in Apache without having to declare them twice.
Are there any security concerns with this approach?
In general, you don't need to use the keyword export when sourcing scripts.
Therefore the extra script (i.e. my_apacheenv.sh) should have this format:
VARIABLE_A="some hardcoded value"
VARIABLE_B="${DYNAMIC_ONE}"
VARIABLE_C="${APACHE_HOSTNAME}"
and be sure it is marked as executable (chmod +x /path/to/my_apacheenv.sh).
The file /etc/apache2/envvars should contain:
. /path/to/my_apacheenv.sh
Then you can define the value of DYNAMIC_ONE or APACHE_HOSTNAME in any usual way, either in the session or as environment variable.
For me, it works pretty well when used in combination of a docker-compose file:
version: "3"
services:
single-apache-php:
build: ./../cicd/apache
environment:
APACHE_HOSTNAME: "my.dynamic.hostname.com"
I was able to solve my own problem. I removed MY_VAR from /etc/environment and created a separate file /etc/profile.d/apache.sh which looks like this:
export MY_VAR="foo"
Then I sourced this file in /etc/apache2/envvars like so:
. /etc/profile.d/apache.sh
Any variable set in apache.sh is available system-wide as well as in Apache
Because apache.sh is a script, unlike /etc/environment, the variables do not have to be "export"ed again in envvars
There is no security risk because no unwanted variables are passed magically to Apache
Whatever variables you want to be available system-wide as well as Apache, you add it to apache.sh and if you want it only in Apache then you add it in envvars

How can I setup an environment variable to hold a DSN for PHP?

I am trying to set up a permanent "environment" variable per this SO Post.
I put the variable in my .bash_profile and am able to access it from the command line using.
echo $VAR
However, this is a DSN ( DB Credentials ) needed by PHP ( same thing Heroku does ) and I need to access it using
getenv() or similar.
If I run env from the command line I do not see it listed.
It appears there are different types of environment variables and I'm using the wrong one.
How should I do this correctly?
Your webserver does not run your shell so it doesn't the .bash_profile. There are various tricks to get environment variables into Apache but they all rely on having administration access to your webserver, and you don't get that on low-end godaddy hosting.
If you were to explain why you are trying to get environment variables into Apache, what type of hosting you have and what access you have to the server we might be able to better advise. There are modules which expose access to manipulate environment variables for Apache (mod_env for example) but these may not be available/appropriate. It's also possible to get data (and code) into PHP from a .htaccess file, but again its impossible to say whether this meets your requirements.

How secure is storing DB variables with SetEnv or in php.ini?

I don't like storing sitewide crypto keys and DB access information under document_root, so I was using Apache's SetEnv and php.ini files under conf.d to separate these from the codebase. The big question is, which one is better? Inside environment variables under apache vhost files (SetEnv SITEKEY 'oinkoink!') or inside conf.d/xxx.ini files (db_pass="oink?")? Maybe something else?
PROS n CONS:
SetEnv:
+Stored outside DOCUMENT_ROOT
+Only the given vhost has access
-Visible with PHPINFO() - Hacker needs direct access/upload exploit to files
get_cfg_var:
+Stored outside DOCUMENT_ROOT
+Not visible with PHPINFO()
-(VERY BAD) All the defined ini variables are included, so each vhost can query them via (ini_get_all), so not usable in a shared vhost environment
As long as *.ini and SetEnv are outside of the web root (document root) it doesn't matter either way. Just choose whichever you prefer. I like SetEnv, but it's really just personal preference. It makes more sense to me to use SetEnv since the variables are put into _SERVER. With the .ini, I think it makes more sense to leave it for initialization settings specific to how the code works.
Not storing under the document root is a good idea to prevent access to possibly secure data.
Note that phpinfo() will list any server variables that are set, so be very careful about that.
Finally, if you are including files, make sure that you don't allow gratuitous ../../ set by the user somehow or they will have access to potentially secure files (even including /etc/passwd!)
I think your main question is "how secure." Well, this probably about as secure as you can get without causing major headaches. The php code has access to these variables, so if you print them out they are easily visible, so it depends on how secure your code base is. It might be possible to use LDAP with MySQL, but that sounds like a huge pain.
It's common practice to use store non-public files outside of document_root. A typical layout could be this:
.../myProject
.../myProject/documentRoot
.../myProject/documentRoot/....
.../myProject/nonPublicFiles
.../myProject/nonPublicFiles/...
Store your PHP stuff in documentRoot and all non-public stuff in nonPublicFiles. documentRoot would be the Apache document_root of the vHost. Since nonPublicFiles is outside, Apache won't answer request.
Recarding security, SetEnv or *.ini tend to be equivalent: In case someone gains rights to execute arbitrary PHP-Code, both ways provide the sensible information to this code.
I'd prefer the SetEnv and *.ini method, since Apache won't disclose these details itself. A script is required.
Misconfiguration may disclose the contents of nonPublicFiles even without a script.
If case you are going to use nonPublicFiles, prepare upfront a script, which checks if everything is set up fine and forward an email, if it found problems. Probably call it using CRON.
I prefer storing them in either non-public folders, which can be accessed only by apache, or outside the document_root.

PHP set_inlude_path and include best practises

Where would
set_include_path("../../");
point to?
I am trying to run some PHP code on a standard XAMPP server. And put my stuff into the htdocs folder. The includes point to relative paths, But it does not work. Is there any best-practise for includes? The code has to run on machines of multiple developers.
Relative path should work fine (warning: apache on windows, as I know, don't follow the simlinks, or whatever are called on that os).
Maybe you should use the syntax (in order to avoid problem with different php versions)
ini_set('include_path', 'yourdir');
and test the return value to see if all is ok.
Turning to the best practices:
To me setting an configuration directive into a script, expecially if project-wide, is wrong, or at least dangerous.
A better practice is to put the directive into the .htaccess file in the directory that contains your php files project.
Even better, it is faster, put the directives into the appropriate virtualhost section of your apache config. For develop, though, .htaccess is more flexible and therefore preferable.
It should be something like this:
php_value include_path ".:../..:<your path collection>"
Doing this lets you share the php configuration w/o have fiddling with the ini_set directive in every php file you write.
Not to mention that if you have a special file that needs a custom include_path, you can set it in the file and this will be evident to everyone at a very rapid glance.
Two directories down from where the file (or the file which included it) is running from.
As for best practices there are only two advices i can give you.
Use relative paths.
If relative paths are giving you trouble, use an absolute path as a single static variable and the developers only change that one variable.

reinitialize system wide environment variable in linux

I just want my apache to register some of my predefined environment so that i can retrieve it using getenv function in php. How can i do this? I tried adding /etc/profile.d/foo.sh with export FOO=/bar/baz using root and restarted apache.
Environment variables are inherited by processes in Unix. The files in /etc/profile.d are only executed (in the current shell, not in a subshell) when you log in. Just changing the value there and then restarting a process will not update the environment.
Possible Fixes:
log out/log in, then start apache
source the file: # . /etc/profile.d/foo.sh, then restart apache
source the file in the apache init script
You also need to make sure that /etc/profile.d/ is sourced when Apache is started by init rather than yourself.
The best fix might also depend on the distribution you are using, because they use different schemes for configuration.
You can use SetEnv in your config files (/etc/httpd/conf.d/*.conf, .htaccess ...). Additionally you should be able to define them in /etc/sysconfig/httpd (on RPM-based distribs) and export them (note: not tested).
Note: it wouldn't surprise me if some distributions tried quite hard to hide as much as possible, as far as system config is concerned, from a publically accessible service such as Apache. And if they don't, they might start doing this in a future version. Hence I advise you to do this explicitly. If you need to share such a setting between Apache and your shells, you could try sourcing /etc/profile.d/yourprofile.sh from /etc/sysconfig/httpd
Apache config files allow you to set environment variables on a per site basis.
So if your web server is serving pages from two logical sites you can have the same environment variable set differently for each site and thus get your PHP to react differently.
See the Apache mod_env for details:
If you need env vars for Apache only, what worked for me was editing the /etc/apache2/envvars and restart of Apache. I added these settings:
export LANG='en_US.UTF-8'
export LC_ALL='en_US.UTF-8'

Categories