I am using PHP as PHP-FPM on Centos. I am trying to follow the http://12factor.net/ guidelines of having the settings be stored in environment variables.
I have created a file in /etc/profile.d that sets the environment variables I want, and the environment variables appear when tested in the CLI via Bash i.e. running the bash script:
echo $SOME_SERVER_SETTING
shows the correct output.
I have set the clear_env setting to false and variables_order to EGPCS, however, the variable I have set does not show up in PHP either getenv('SOME_SERVER_SETTING') or doing var_dump($_ENV)
What other setting needs to be set to allow PHP-FPM to receive all of the server environment variables, and in particular those set through a shell script in /etc/profiles.d on Centos?
Tested on Centos 7 with Systemd service and PHP 5.6.4
OPEN
/etc/php.ini
FIND
variables_order = "GPCS"
REPLACE TO
variables_order = "EGPCS"
# http://php.net/manual/en/ini.core.php#ini.variables-order
OPEN
/etc/php-fpm.d/www.conf (maybe /etc/php5/fpm/pool.d/www.conf)
(do not confuse with /etc/php-fpm.conf)
FIND IF EXIST
clear_env = yes
REPLACE TO OR ADD
clear_env = no
# http://php.net/manual/en/install.fpm.configuration.php
OPEN
/etc/environment
ADD
#any variables you need, for example:
MY_VAR=1234
RUN IN SHELL FOR CHECK
source /etc/environment
echo $MY_VAR # 1234
RUN IN SHELL
ln -fs /etc/environment /etc/sysconfig/php-fpm
systemctl daemon-reload && service php-fpm restart
...TESTING
OPEN
index.php # in your project folder, running with php-fpm
ADD
var_dump(getenv('MY_VAR'), $_ENV['MY_VAR']);exit;
RUN IN BROWSER
http://mylink.to.project/index.php
string(4) "1234"
string(4) "1234"
ENJOY!
Security reasons :-)
See /etc/php5/fpm/pool.d/www.conf (debian location, may be different on CentOs)
; Clear environment in FPM workers
; Prevents arbitrary environment variables from reaching FPM worker processes
; by clearing the environment in workers before env vars specified in this
; pool configuration are added.
; Setting to "no" will make all environment variables available to PHP code
; via getenv(), $_ENV and $_SERVER.
; Default Value: yes
;clear_env = no
; Pass environment variables like LD_LIBRARY_PATH. All $VARIABLEs are taken from
; the current environment.
; Default Value: clean env
;env[HOSTNAME] = $HOSTNAME
;env[PATH] = /usr/local/bin:/usr/bin:/bin
;env[TMP] = /tmp
;env[TMPDIR] = /tmp
;env[TEMP] = /tmp
Environment variables in a FastCGI setup are set as input by the client of the FPM process, for instance NginX. They are sent as headers to the FastCGI server, which interprets them and sets them accordingly for you to read out with getenv.
If you are in fact using NginX, look for the fastcgi_param directives. You can also set environment variables in your pool config of php5-fpm, depending on your use case.
You need to read the environment variables from the correct location. PHP creates a super global variable for this: $_ENV So you can access a single variable by accessing a certain element from that variable, which holds an array: echo $_ENV['SOME_SERVER_SETTING'];
I have no idea why your example above should work on CLI. The super global variable is the documented location and works.
What might be your issue here is that the variables are not set for the http server process. Typically scripts like those in /etc/profile.d are executed at login time. So when a user creates a session inside the system. But that will never happen for an http server started as a system server. No login is performed, no profile script is executed, no environment variables are set.
To solve this you can
set the environment variables inside the startup script of the service
set the variables inside the host configuration or .htaccess style files
auto-prepend a script setting the variables
Related
I'm trying to set multiple cloud servers behind an ALB to write their log files to my common EFS. I have a single shared drive EFS, which I can access via a single development instance, while all my production instances are securely behind a VCN. I am trying to use system environment variables (specifically the HOSTNAME) so that each of the production instances, which use the same configuration file to start php-fpm (so that I can do auto-scaling), write a different log.
I've seen answers that say that the *nix way of using environment variables should work, but they are not working for me. Specifically ${HOSTNAME} returns blank (and I have checked it is set for the apache and root users; root starts the php-frm service). I also tried interpolations of that, and the bash flavor of things "%()". None of them work.
All of them return blank strings (but not errors).
I did create a single variable in my environment variable, and got that to work.
I also read that you can't assign a env value to a variable directly, but when I tried to create a separate variable, that actually returned an error when starting the service.
This is what I would expect to work:
slowlog = "/shared/logs/php-fpm/www-slow-${HOSTNAME}.log"
Tried all of the following:
slowlog = "/shared/logs/php-fpm/www-slow-".${HOSTNAME}.".log"
--> blank for hostname
slowlog = "/shared/logs/php-fpm/www-slow-${HOSTNAME}.log"
--> blank for hostname
slowlog = "/shared/logs/php-fpm/www-slow-%(HOSTNAME).log"
--> the file name includes %(HOSTNAME)
slowlog = "/shared/logs/php-fpm/www-slow-$HOSTNAME.log"
--> the file name includes $HOSTNAME
slowlog = "/shared/logs/php-fpm/www-slow-{$HOSTNAME}.log"
--> the file name includes {$HOSTNAME}
slowlog_name = "/shared/logs/php-fpm/www-slow-{$HOSTNAME}.log"
slowlog = slowlog_name
--> start error: unknown variable slowlog_name
Thank you for any tips/advice!
PHP 7.3 does support environment variable interpolation for log file names in config files - I just tested this. I suspect that where you're getting caught is that in bash, $HOSTNAME is a bash variable but not automatically an environment variable, and Linux systems vary in whether $HOSTNAME is set as an environment variable. RedHat distros do set it, Ubuntu does not:
jacob#nitrogen ~ $ cat /etc/redhat-release
Fedora release 29 (Twenty Nine)
jacob#nitrogen ~ $ echo $HOSTNAME
nitrogen
jacob#nitrogen ~ $ env | grep HOSTNAME
HOSTNAME=nitrogen
jacob#iad11:~$ grep PRETTY_NAME /etc/os-release
PRETTY_NAME="Ubuntu 18.04.2 LTS"
jacob#iad11:~$ echo $HOSTNAME
iad11
jacob#iad11:~$ env | grep HOSTNAME
You can test with a different environment variable, and then set $HOSTNAME in a custom startup script that then starts PHP.
I'm running Apache/2.2.11 (Win32) PHP/5.3.0 and I did the following in my .htaccess file:
SetEnv FOO bar
If I print out the $_ENV variable in a PHP file, I get an empty array. Why doesn't my environment variable appear there? Why is it empty in the first place?
I did find my variable though, but it appears in the $_SERVER variable. And for some reason it appears twice, sort of. Why is this?
[REDIRECT_FOO] => bar
[FOO] => bar
It appears I can get it using getenv('FOO'), so maybe I should just use that instead. But I am still a bit curious to what causes this. Is this a Windows issue? Or what is going on?
Turns out there was two issues here:
1. $_ENV is only populated if php.ini allows it, which it doesn't seem to do by default, at least not in the default WAMP server installation.
; This directive determines which super global arrays are registered when PHP
; starts up. If the register_globals directive is enabled, it also determines
; what order variables are populated into the global space. G,P,C,E & S are
; abbreviations for the following respective super globals: GET, POST, COOKIE,
; ENV and SERVER. There is a performance penalty paid for the registration of
; these arrays and because ENV is not as commonly used as the others, ENV is
; is not recommended on productions servers. You can still get access to
; the environment variables through getenv() should you need to.
; Default Value: "EGPCS"
; Development Value: "GPCS"
; Production Value: "GPCS";
; http://php.net/variables-order
variables_order = "GPCS"
When I set the variables_order back to EGPCS, $_ENV is no longer empty.
2. When you use SetEnv in your .htaccess, it ends up in $_SERVER, not in $_ENV, which I gotta say is a tad confusing when it's named SetEnv...
# .htaccess
SetEnv ENV dev
SetEnv BASE /ssl/
# php
var_dump($_SERVER['ENV'], $_SERVER['BASE']);
// string 'dev' (length=3)
// string '/ssl/' (length=5)
3. The getenv function will always work and is not affected by the PHP setting for $_ENV Additionally it seems to do so insensitive to case, which might be useful.
var_dump(getenv('os'), getenv('env'));
// string 'Windows_NT' (length=10)
// string 'dev' (length=3)
$_ENV variables are imported from the environment under which PHP is running, and depending on your setup (the OS, your server, whether PHP runs as an Apache module or under FastCGI, etc.), this can vary greatly.
IIRC in a standard Apache+mod_php install on Windows, the only way to change variables in $_ENV is to change Windows' environment variables (see this). This can be significant when dealing with PHP extensions on Windows, because some of them (eg: php_ldap) are only configurable through environment vars on $_ENV.
REDIRECT_* variables appear if you are using RewriteRules. On my server they also appear just so. It might have something to do with running under FastCGI. And if combined with suexec, that's most likely to clean up the complete environment var pool. There might be additional configuration necessary to get them back, PassEnv particularily. As to why getenv() works for you, I have no clue. But all phenomena are specific to your server and php configuration. Ask on serverfault, they should know.
I have the following executable python script:
#!/usr/bin/python
import os
print os.environ
when I execute it from the command line as root, I get the following:
{
'LANG': 'en_US.UTF-8',
'TERM': 'xterm-256color',
'SHELL': '/bin/bash',
'LESSCLOSE': '/usr/bin/lesspipe %s %s',
'LANGUAGE': 'en_US:en',
'SHLVL': '1',
'SSH_TTY': '/dev/pts/0',
'OLDPWD': '/var/www/bais-mordechai-laravel',
'COMP_WORDBREAKS': ' \t\n"\'><;|&(:',
'PWD': '/var/www/bais-mordechai-laravel/public',
'LESSOPEN': '| /usr/bin/lesspipe %s',
'SSH_CLIENT': '71.205.188.8 56489 22',
'LOGNAME': 'root',
'USER': 'root',
'PATH': '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games',
'MAIL': '/var/mail/root',
'LS_COLORS':'...',
'HOME': '/root',
'_': './pythontest',
'SSH_CONNECTION': '...'
}
But when I run this from a php script (running on nginx server) and echo back the result I get:
{
'HOME': '/var/www',
'PWD': '/var/www/bais-mordechai-laravel/public',
'USER': 'www-data'
}
Why are they different? Specifically, how can I get the web version to include the 'PATH' variable?
For apache, see mod_setenv.
This module allows for control of internal environment variables that are used by various Apache HTTP Server modules. These variables are also provided to CGI scripts as native system environment variables, and available for use in SSI pages. Environment variables may be passed from the shell which invoked the httpd process. Alternatively, environment variables may be set or unset within the configuration process.
If you are using Apache's FCGId, see FcgidInitialEnv.
Use FcgidInitialEnv to define environment variables to pass to the FastCGI application. This directive can be used multiple times.
This setting will apply to all applications spawned for this server or virtual host. Use FcgidCmdOptions to apply this setting to a single application.
For Nginx CGI, see the env setting.
By default, nginx removes all environment variables inherited from its parent process except the TZ variable. This directive allows preserving some of the inherited variables, changing their values, or creating new environment variables.
If you are using NgxWSGIModule, see the wsgi_var setting.
Directive assigns the variable, which will be added to the
environment dictionary passed to the WSGI application.
It is possible to use strings, nginx variables and their
combination as values. Directives not set are inherited from the
outer level.
If you are running your application under (gunicorn|tornado|twisted|etc)+supervisord, see the environment directive.
A list of key/value pairs in the form KEY="val",KEY2="val2" that will be placed in the supervisord process’ environment (and as a result in all of its child process’ environments). This option can include the value %(here)s, which expands to the directory in which the supervisord configuration file was found. Values containing non-alphanumeric characters should be quoted (e.g. KEY="val:123",KEY2="val,456"). Otherwise, quoting the values is optional but recommended. Note that subprocesses will inherit the environment variables of the shell used to start supervisord except for the ones overridden here and within the program’s environment option.
If you are using something else, let me know.
You can always inject environment variables using os.environ - do it at the start of your (c|fc|ws)gi.py script. Se also sys.path:
sys.path.append('/usr/local/django')
I'm running Apache/2.2.11 (Win32) PHP/5.3.0 and I did the following in my .htaccess file:
SetEnv FOO bar
If I print out the $_ENV variable in a PHP file, I get an empty array. Why doesn't my environment variable appear there? Why is it empty in the first place?
I did find my variable though, but it appears in the $_SERVER variable. And for some reason it appears twice, sort of. Why is this?
[REDIRECT_FOO] => bar
[FOO] => bar
It appears I can get it using getenv('FOO'), so maybe I should just use that instead. But I am still a bit curious to what causes this. Is this a Windows issue? Or what is going on?
Turns out there was two issues here:
1. $_ENV is only populated if php.ini allows it, which it doesn't seem to do by default, at least not in the default WAMP server installation.
; This directive determines which super global arrays are registered when PHP
; starts up. If the register_globals directive is enabled, it also determines
; what order variables are populated into the global space. G,P,C,E & S are
; abbreviations for the following respective super globals: GET, POST, COOKIE,
; ENV and SERVER. There is a performance penalty paid for the registration of
; these arrays and because ENV is not as commonly used as the others, ENV is
; is not recommended on productions servers. You can still get access to
; the environment variables through getenv() should you need to.
; Default Value: "EGPCS"
; Development Value: "GPCS"
; Production Value: "GPCS";
; http://php.net/variables-order
variables_order = "GPCS"
When I set the variables_order back to EGPCS, $_ENV is no longer empty.
2. When you use SetEnv in your .htaccess, it ends up in $_SERVER, not in $_ENV, which I gotta say is a tad confusing when it's named SetEnv...
# .htaccess
SetEnv ENV dev
SetEnv BASE /ssl/
# php
var_dump($_SERVER['ENV'], $_SERVER['BASE']);
// string 'dev' (length=3)
// string '/ssl/' (length=5)
3. The getenv function will always work and is not affected by the PHP setting for $_ENV Additionally it seems to do so insensitive to case, which might be useful.
var_dump(getenv('os'), getenv('env'));
// string 'Windows_NT' (length=10)
// string 'dev' (length=3)
$_ENV variables are imported from the environment under which PHP is running, and depending on your setup (the OS, your server, whether PHP runs as an Apache module or under FastCGI, etc.), this can vary greatly.
IIRC in a standard Apache+mod_php install on Windows, the only way to change variables in $_ENV is to change Windows' environment variables (see this). This can be significant when dealing with PHP extensions on Windows, because some of them (eg: php_ldap) are only configurable through environment vars on $_ENV.
REDIRECT_* variables appear if you are using RewriteRules. On my server they also appear just so. It might have something to do with running under FastCGI. And if combined with suexec, that's most likely to clean up the complete environment var pool. There might be additional configuration necessary to get them back, PassEnv particularily. As to why getenv() works for you, I have no clue. But all phenomena are specific to your server and php configuration. Ask on serverfault, they should know.
I'm running Apache/2.2.11 (Win32) PHP/5.3.0 and I did the following in my .htaccess file:
SetEnv FOO bar
If I print out the $_ENV variable in a PHP file, I get an empty array. Why doesn't my environment variable appear there? Why is it empty in the first place?
I did find my variable though, but it appears in the $_SERVER variable. And for some reason it appears twice, sort of. Why is this?
[REDIRECT_FOO] => bar
[FOO] => bar
It appears I can get it using getenv('FOO'), so maybe I should just use that instead. But I am still a bit curious to what causes this. Is this a Windows issue? Or what is going on?
Turns out there was two issues here:
1. $_ENV is only populated if php.ini allows it, which it doesn't seem to do by default, at least not in the default WAMP server installation.
; This directive determines which super global arrays are registered when PHP
; starts up. If the register_globals directive is enabled, it also determines
; what order variables are populated into the global space. G,P,C,E & S are
; abbreviations for the following respective super globals: GET, POST, COOKIE,
; ENV and SERVER. There is a performance penalty paid for the registration of
; these arrays and because ENV is not as commonly used as the others, ENV is
; is not recommended on productions servers. You can still get access to
; the environment variables through getenv() should you need to.
; Default Value: "EGPCS"
; Development Value: "GPCS"
; Production Value: "GPCS";
; http://php.net/variables-order
variables_order = "GPCS"
When I set the variables_order back to EGPCS, $_ENV is no longer empty.
2. When you use SetEnv in your .htaccess, it ends up in $_SERVER, not in $_ENV, which I gotta say is a tad confusing when it's named SetEnv...
# .htaccess
SetEnv ENV dev
SetEnv BASE /ssl/
# php
var_dump($_SERVER['ENV'], $_SERVER['BASE']);
// string 'dev' (length=3)
// string '/ssl/' (length=5)
3. The getenv function will always work and is not affected by the PHP setting for $_ENV Additionally it seems to do so insensitive to case, which might be useful.
var_dump(getenv('os'), getenv('env'));
// string 'Windows_NT' (length=10)
// string 'dev' (length=3)
$_ENV variables are imported from the environment under which PHP is running, and depending on your setup (the OS, your server, whether PHP runs as an Apache module or under FastCGI, etc.), this can vary greatly.
IIRC in a standard Apache+mod_php install on Windows, the only way to change variables in $_ENV is to change Windows' environment variables (see this). This can be significant when dealing with PHP extensions on Windows, because some of them (eg: php_ldap) are only configurable through environment vars on $_ENV.
REDIRECT_* variables appear if you are using RewriteRules. On my server they also appear just so. It might have something to do with running under FastCGI. And if combined with suexec, that's most likely to clean up the complete environment var pool. There might be additional configuration necessary to get them back, PassEnv particularily. As to why getenv() works for you, I have no clue. But all phenomena are specific to your server and php configuration. Ask on serverfault, they should know.