In the same way that you can generate specific content based on browser type is there a way to generate specific content based on the server running PHP without reference to the server or site name?
For example, a way for PHP to automatically detect the environment it was in and configure things like DB connections, ini_set for errors etc. depending if it was a development, ITS, UAT or production environment.
The 2 ways I thought of were to recognise an HTTP header indicating development and QA environments or to have custom properties in php.ini.
I have woken up slightly and found out the php function to read the http headers but php overrides anything I set in the web server and I do not know if they can be set in php.ini at all.
I have no idea if it is possible to add custom values to php.ini but I had a test and ini_get would not find it (I had restarted the web server after changing php.ini of course).
you can specify an environment variable in apache (conf, vhost, .htaccess or as an httpd daem) and then acces it via the ˆ$_ENVˆsuperglobal
I use the following to load different settings for different servers:
switch ($_SERVER['SERVER_NAME']) {
case 'web-host': case '10.0.0.208':
# Set DB Settings
case 'mydomain.com': default:
# Live server settings
}
Not had a problem with it so far
$_ENV / http://www.php.net/manual/en/reserved.variables.environment.php
Using FastCGI on IIS you can set Environment variables. They do not seem to be available to $_ENV but can be retrieved with getenv("varname").
To configure FastCGI environment variables in IIS 5 or 6 you need to edit:
C:\%systemdrive%\system32\inetsrv\fcgiext.ini
For example:
[Types]
php=d:\Dev\PHP\php-cgi.exe
php:1=PHP Site 1
*=Wildcard Mapping
[d:\Dev\PHP\php-cgi.exe]
QueueLength=999
MaxInstances=20
InstanceMaxRequests=500
[PHP Site 1]
ExePath=d:\Dev\PHP\php-cgi.exe
EnvironmentVars=PHPRC:d:\Dev\PHP\,SiteType:Developer
In this instance it is IIS 5 so there is only one site and the site ID is 1 as indicated in line 2 of [Types].
On IIS 6 you may have multiple sites and the following link tells you how to find the Site ID: http://weblogs.asp.net/owscott/archive/2005/07/29/how-to-find-the-siteid-in-iis5-and-iis6.aspx.
IIS 7 can be configured via the UI apparently once the Administration Pack for IIS 7 has been installed.
Another alternative that hasn't been mentioned yet would be to create a server-specific (but with the same name) configuration file that would be included in the beginning of your site script. In that server-specific config file you could set configuration variables as constants. That way, if there was a 'generic' configuration file loaded later, its values could be overridden in the server-specific configuration file as constants can't be redefined. You would want to either exclude the server-specific configuration file name from the synchronizations, or keep it in a path outside of the main content so that it is not accidentally overwritten.
For this purpose you can even configure Constant Arrays with help of Constant Array 2 class.
When server-specific configuration files are used you don't have to worry about the current SERVER_NAME -- this makes it easier for you to define the intended environment regardless of the current system name which could be handy also for QA purposes.
Related
[Asked this at SU; suggestion there was to repost at SO]
We have PHP programs that use $_SERVER['DOCUMENT_ROOT'] as a path to a place where we can place a private directory (using a unique name) in a safe, known place on server. This directory holds data summaries collected from multiple perhaps thousands of served PHP pages; this summary has no impact on the main functionality of the pages served, and eventually can be ignored or deleted. While it exists, a PHP-based tool can inspect the summary data and provide a report.
This has worked well on a variety of PHP servers, and appears to be "automatically" (?) set according to the PHP Manual documentation:
'DOCUMENT_ROOT'
The document root directory under which the current script
is executing, as defined in the server's configuration file.
We installed several different PHP servers over the years, and they all seem to come with this pre-configured to a reasonable path without any explicit configuration effort on our part.
We have some clients using our software that complain that this path seems to be set to null, which seems inconsistent with the above definition. (Does null signify some special path?) (One of these clients claims they have (php -v) "PHP 5.6.16-3+deb.sury.org~trusty+1 (cli) ... Zend Engine v2.6.0, ... with Zend OPcache v7.0.6-dev, ..." and (uname -or) "3.19.0-25-generic GNU/Linux" [??Generic GNU/Linux??]
Pardon my ignorance, but is DOCUMENT_ROOT a configurable item? Where do I find the server "configuration file" for this? Is it the same place for all different PHP server implementations? Can I/should I change that configuration files to set this explicitly if it is not set?
If not, is there another way to provide a path to a safe long-term "temporary" local directory?
$_SERVER['DOCUMENT_ROOT'] is found in your apache httpd.conf and it can be configured. It's the directory out of which you will serve your documents. By default, all web requests are taken from this directory so it should not be null.
This link gives you quick run-down as to why documentroot is in place: http://httpd.apache.org/docs/2.4/urlmapping.html#documentroot.
I personally don’t see an issue using $_SERVER['DOCUMENT_ROOT'] for servers which I have full control, but I would be wary using this path reference on shared hosting solution’s due to aliases in the config. In this instance, I would just set the $_SERVER['DOCUMENT_ROOT'] manually.
<?php
echo $_SERVER['DOCUMENT_ROOT'];//Real Path
$_SERVER['DOCUMENT_ROOT'] = "/new/path/www";
echo $_SERVER['DOCUMENT_ROOT'];//New Path
?>
The Bolt documentation mentions setting up configuration files for each environment, but doesn't explain how to make it happen.
When you have multiple environments for the same site, like development, staging, or production, you’ll want parts of the config to be the same, and some different per environment. You’ll probably have different database info and debug settings. This can be accomplished by splitting the config.yml file. Put all settings you share over all environments in the default config.yml, you can commit this in your version control system if wanted. Every setting which is different per environment, or which you do not want in version control (like database info), you put in config_local.yml. First config.yml is loaded and then config_local.yml, so that config_local.yml can override any setting in config.yml.
Of course I have no problem creating an additional config file, but how do I tell Bolt which environment it's running in and which file it ought to load?
Turns out Bolt is completely unaware of its environment. It always loads config.yml followed by config_local.yml, regardless of domain name.
From Config.php, starting at line 226:
protected function parseGeneral()
{
// Read the config and merge it. (note: We use temp variables to prevent
// "Only variables should be passed by reference")
$tempconfig = $this->parseConfigYaml('config.yml');
$tempconfiglocal = $this->parseConfigYaml('config_local.yml');
$general = Arr::mergeRecursiveDistinct($tempconfig, $tempconfiglocal);
The solution to my problem is to never allow config_local.yml to get deployed.
The config_local.yml file is intended for development use so that you can override configuration setting that might be committed to your VCS in production use.
I tried to setup a development environment where my server environment is emulated by virtual machine running centos 6.3 and development is done from host OS. The application code (codeigniter app) is in a shared folder mounted to /home/foo/Desktop/code/app and I have created a virtual host in apache to serve this application.
On the development side, git is used as the VCS .
The problem is that when loading a helper two files are being included. Eg, I have a helper in application/helper named my_date_helper. It has two functions. I autoload this helper.
When running this application php throws this error
Fatal error: Cannot redeclare time12to24() (previously declared in /home/mlakhara/code/cosys/application/helpers/my_date_helper.php:9) in /home/mlakhara/code/cosys/application/helpers/MY_date_helper.php on line 11
When I comment the function, it says the functions are undefined.
Also the time related functions throw a warning telling me to set a timezone which I have already in the php.ini file using date.timezone option.
I assumed that these two files can be same included twice with different names, but the line numbers suggest something else.. (function is declared at different lines).
The application functions correctly when served from normal folder (non shared). I removed git from the vn and tried but it did not make any difference.
What can be the problem ?
---------------EDIT -----------------------
Taking hints from Magnus Eriksson's answer, I found that I was autoloading these 'extended' helpers instead of loading the actual path and date helpers. This lead to getting two copies of the same function. However the problem with timezone setting still persists.
As a corrective measure I added the time value to my .htaccess file as well. However is there any better way to do it.
Try removing "my_" in the filename. CodeIgniter uses "MY_" to extend the core and might test with both lower and upper case and thus loading the same file twice.
Either way, as Rob W pointed out, always wrap your helper functions in if (!function_exists()) {}
About the timezone problem: Since I haven't seen your php.ini or your setup, I can't say why it isn't working.
One solution should be to add date_default_timezone_set('UTC'); (or what timezone you want) first thing in index.php.
Since I don't always have access to modify php.ini on clients production servers, I usually add that in.
You are defining the function twice. When including the files, try using require_once('path/to/file.php') instead of include or require. Otherwise, in the source file, you can do:
if(!function_exists("time12to24")) {
function time12to24() [...]
}
Is there a way to check if we are running a PHP script on localhost - development server or on live server - production server? Is there any PHP constant, variable, function,etc that can give me this information.
I need this to put different settings for production and development server. Now I parse the URL to see which one it is but I was wondering s there any better way to do that. My concern is that we may change the URL of the script and that may ruin my check.
I am looking few a solution with one config file and IF condition in it depending on which I will define different settings. The only problem is that I do not want to change the IF statement when there are changes on the server settings like hostname, document_root or something else that I am using to identify local/remote host.
And want to SVN update from one source without changing anything to my production server.
And I would like ideally to be able to run and CRON jobs with these settings.
I use the SetEnv in my host definition to locate on which environment i am running (Dev, Stage, Production) :
<VirtualHost *:80>
(all the host info)
SetEnv SERVER_CONTEXT "dev"
</VirtualHost>
And each config file as an extra word in it : config.dev.ini, config.stage.ini, config.prod.ini, etc, ...
It works like a charm.
if($_SERVER["REMOTE_ADDR"]=="127.0.0.1"){
$local = True;
}else{
$local = False;
}
EDIT
You could also check the first part of the address and see if the server is in the local network, the again assuming your server won't be in the local network when in production
I set an environment variable in the Apache configuration and check that. This has the advantage over using a PHP configuration file that all your application code remains exactly the same on PROD, TEST, DEV etc; no need to go and make changes after a check out, as the code just pulls the config from Apache.
To demonstrate, the following can be set in your VirtualHost configuration
SetEnv ENVIRONMENT PROD
In your PHP code, you can then check the environment with
$env = getenv('ENVIRONMENT');
If you feel the need to make this available everywhere, you can then use define, but I don't find it necessary (I use the specified environment to load the appropriate configuration files and create a read-only Singleton configuration, which is then used to check any configuration options; better than if ($env == 'PROD') {} type code, as all that logic is in the config, not in your code).
Use a config file you include with a define in it
define("DEBUG",true); //set to false for live
and use that in your code, e.g.:
if(DEBUG){}
You can try and use the global $_SERVER['SERVER_NAME'] This should tell you the host name of the system that's running the script. You could use this to determine what settings to use (depending on the system).
I don't know that this will output 'localhost' however and you may need to know your actual host name of your development machine.
The server has no idea what environment it is unless you tell it to. What I do is use DEFINE to set the environment. My application code is the same on every instance but the my configuration files change. That way you can use .htaccess file include the configuration files on every script and check to see what they settings are.
I know this word may sound strange to PHP developer, but have you considered build of your project?
In PHP there's nothing to compile, however changing copied files is one of features of any build process. You could specify 2 targets: production and dev. There would be no need for any conditionals, that should work, or may work, but under some circumstances won't.
i always make "config.php" wich i include to other php files...
it contains something like (home file):
$CONFIG['server']="dev";
$CONFIG['db_user']="root";
and thing like that...
so at home i have this one up there and at server where site is running i have another one wich i dont update if not changes to it...
so on server i have something like:
$CONFIG['server']="prod";
$CONFIG['db_user']="lwu9918_admin";
and then in other php files:
include("config.php");
if($CONFIG['server']=="dev"){echo "Development";}
thing like that!
On dev server
* * * * * php -r cronjob.php this_is_dev
On production server
* * * * * php -r cronjob.php this_is_live
In your script
switch ($argv[1])
case 'this_is_dev':
// load your dev configuration
break;
case 'this_is_live':
// load your live configuration
break;
default:
die('invalid server');
break;
}
since is meant for cronjob, the $argv is exist
good luck with Windows :(
you better put the cli running program outside www directory ,for example
c:\iis\www is the public html directory
the cli file should be put under c:\iis instead
I'm trying to determine the best way of having a PHP script determine which server the script/site is currently running on.
At the moment I have a switch() that uses $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT'] to determine which server it's on. It then sets a few paths, db connection parameters, SMTP paramters and debug settings based on which server it's on. (There maybe additional parameters depending on the site needs.)
This means that I can simply drop the site onto any of the configured servers without having to change any code (specifically the configuration). If it's a new server, then I simply add a new case and it's ready from then on.
We have done loading config files based on the same SERVER_NAME:SERVER_PORT combination, but found that it's another file you have to maintain, plus we weren't sure on the speed of parsing ini files, (although having extra cases for each server may be just as slow).
Another problem we have is when a site is often moved between 2 servers, but we use the same SERVER_NAME and SERVER_PORT on each. This means we need to temporarily comment one case and ensure it doesn't get into the repo.
Another other ideas? It needs to be available on all servers (sometimes SERVER_NAME and SERVER_PORT are not). It would also be nice if it worked with the CLI PHP.
How about using $_SERVER['SERVER_ADDR'] and base your identity off the IP address of the server.
UPDATE: In a virtual host situation, you might also like to concatenate the IP with the document root path like so:
$id = $_SERVER['SERVER_ADDR'] . $_SERVER['DOCUMENT_ROOT'];
We use the $_SERVER['HTTP_HOST'] variable to create the filename of a PHP include file which contains all the vhost-specific information (we deploy the same software to a lot of vhosts)
I like this technique, as you can get clever with it to build hierarchies of configurations, e.g. for www.foo.com,
try to load com.config.php
try to load foo.com.config.php
try to load www.foo.com.config.php
Doing it this way lets you set options for all your live sites globally, and tweak individual sites on as as-needed basis. We have our own internal root domain name for developer sandboxes too, so we can enable all the developer level options in internal.config.php
You can also do this in reverse, i.e. try to load www.foo.com.config.php, and only if not found would you try to load foo.com.config.php, and so on. More efficient, but a little less flexible.
Here are some variables you can check:
$_SERVER['HTTP_HOST'];
I use this one for checking which server I'm on when php is running through apache.
$_SERVER['USER'];
$_SERVER['LOGNAME'];
I use these two for when I know I'm running from the console. One of those invariably resolves to a usable username. There seem to be no other host-defining variables in console mode.
This might not help you enough; If you find you still have a hard time being able to uniquely identify what server you are on you can give it a little bit of a "push." In my situation I have a small config file which is unique to each server, basically setting a php variable defining which environment I'm running in (e.g. development or production.) This way you only need to maintain one small, easy to recreate file outside of your source control.
Ive always kept a config.php on my sites, storeing such infomation which may be percificic to that server.
Being php parseing it is nearly (eg the file needs to be opened, closed, etc) as fast as having the code at the top of each script, and much faster than ini and xml config solutions
Centralised location for the sites configuration on each server, so easy to keep upto date (server doesn't change that oftern, updateing the config is simple with an update script).
Can be generated by the script, all my sites have a function that rebuilds the config file useing the $config[] assoc array.
Updates that effect the config file are as simple as "$config['key'] = 'new value';config_update()"
I have been using the following mechanism:
if(__FILE__ === '/Sites/mywebsite.com/includes/config.php')
define('SERVER', 'DEV');
else
define('SERVER', 'PRODUCTION');
My development environment has a rather distinct path structure so this works well, and I don't need to worry if additional domains are added to $_SERVER[HTTP_HOST], or a client that provides an incorrect HTTP_HOST value (although that would be rare ...).
Why don't you have configuration files for each host stored outside of the project directory and read it from the php code?
Having host specific code is not really a good practice.
$posix_uname = function_exists('posix_uname') ? posix_uname() : null;
$this_hostname = !empty($_SERVER["HOSTNAME"]) ? $_SERVER["HOSTNAME"] : $_ENV["HOSTNAME"];
$this_hostname = !empty($this_hostname) ? $this_hostname : $posix_uname['nodename'];
We use environment variables for this (ENVPHP environment variable which will contain the specific server environment - ie. development/test/production). This approach works very well for CLI scripts as well (for CLI you set the OS environment variables, for Apache you can use SetEnv switches in the host configuration). In PHP you access this environment variable using getenv('ENVPHP')...