I have been developing an application locally with an application environment setting of development. I think this is being set in the .htaccess file.
Then, I have been deploying new versions to the production server.
I don't want to have to manually change the application environment, by hand, every time I deploy a new version.
How should I do this, so I can set the application environment variable automatically (maybe based on the location that it's being hosted? i.e. myapp.com vs. myapp.local)?
You can do this in the either in the server config, virtual host, directory or .htaccess through
SetEnv SPECIAL_PATH /foo/bin
Ex.
<VirtualHost host1>
SetEnv FOO bar1
...
</VirtualHost>
<VirtualHost host2>
SetEnv FOO bar2
...
</VirtualHost>
For more readings
http://httpd.apache.org/docs/1.3/mod/mod_env.html#setenv
http://docstore.mik.ua/orelly/linux/apache/ch04_06.htm
if (false !== stripos($_SERVER['HTTP_HOST'], 'yourdomain.tld')) {
$_ENV['APPLICATION_ENV'] = $_SERVER['APPLICATION_ENV'] = 'production';
}
at the top of index.php
I do something like SM, but slight different:
$env = 'development';
if ('www.my-host-name.com' == $_SERVER['HTTP_HOST'] || 'my-server-name' == exec('hostname')) {
$env = 'production';
}
defined('APPLICATION_ENVIRONMENT') or define('APPLICATION_ENVIRONMENT', $env);
unset($env);
I use my server hostname to determine the environment. I also use my server name because some scripts are run from a cron job and I need this to do the tests.
Related
I've enabled development mode using composer development-enable . How can I check in my module's config/module.config.php that development is enabled or not?
I've also added SetEnv APPLICATION_ENV development in public/.htaccess and tried to use it in module.config.php using echo APPLICATION_ENV;exit; but it doesn't give me environment.
How I can set and get application environment in zend framework 3?
use the correct function ;)
$environment = getenv('APPLICATION_ENV');
Usage for config in ZF2/3:
$env = getenv('APPLICATION_ENV'); // Expect null or "development"
$modules = [];
if ($env === 'development') {
//Array of modules used only for development
$modules = array_merge_recursive($modules, [
'Zf2Whoops',
]);
}
In just Zend Framework nothing special happens with the usage of composer development-enable. However, if you use Apigility at some point, it will create a development.config.php file for you which disables application caches.
TL;DR
Does PHP 5.4 built-in webserver have any bug or restriction about relative paths? Or does it need to be properly (and additionally) configured?
When I used to programming actively I had a system working under URI routing using these lines in a .htaccess file:
RewriteEngine On
RewriteRule !\.(js|ico|gif|jpg|png|css)$ index.php [L]
The FrontController received the Request, find the proper route from given URI in a SQLITE database and the Dispatcher call the the Action Controller.
It worked very nicely with Apache. Today, several months later I decided to run my Test Application with PHP 5.4 built-in webserver.
First thing I noticed, obviously, .htaccess don't work so I used code file instead:
<?php
if( preg_match( '/\.(?:png|jpg|jpeg|gif)$/', $_SERVER["REQUEST_URI"] ) ) {
return false;
}
include __DIR__ . '/index.php';
And started the webserver like this:
php.exe -c "php.ini" -S "localhost:8080" "path\to\testfolder\routing.php"
So far, so good. Everything my application need to bootstrap could be accomplished by modifying the include_path like this:
set_include_path(
'.' . PATH_SEPARATOR . realpath( '../common/next' )
);
Being next the core folder of all modules inside a folder for with everything common to all applications I have. And it doesn't need any further explanation for this purpose.
None of the AutoLoader techniques I've ever saw was able to autoload themselves, so the only class manually required is my Autoloader. But after running the Test Application I received an error because my AutoLoader could not be found. o.O
I always was very suspicious about realpath() so I decided to change it with the full and absolute path of this next directory and it worked. It shouldn't be needed to do as I did, but it worked.
My autoloader was loaded and successfully registered by spl_autoload_register(). For the reference, this is the autoloading function (only the Closure, of course):
function( $classname ) {
$classname = stream_resolve_include_path(
str_replace( '\\', DIRECTORY_SEPARATOR, $classname ) . '.php'
);
if( $classname !== FALSE ) {
include $classname;
}
};
However, resources located whithin index.php path, like the MVC classes, could not be found. So I did something else I also should not be doing and added the working directory to the include_path. And again, manually, without rely on realpath():
set_include_path(
'.' . PATH_SEPARATOR . 'path/to/common/next'
. PATH_SEPARATOR . 'path/to/htdocs/testfolder/'
);
And it worked again... Almost! >.<
The most of Applications I can create with this system works quite well with my Standard Router, based on SQLITE databases. And to make things even easier this Router looks for a predefined SQLITE file within the working directory.
Of course, I also provide a way to change this default entry just in case and because of this I check if this file exist and trigger an error if it doesn't.
And this is the specific error I'm seeing. The checking routine is like this:
if( ! file_exists( $this -> options -> dbPath ) ) {
throw RouterException::connectionFailure(
'Routes Database File %s doesn\'t exist in Data Directory',
array( $this -> options -> dbPath )
);
}
The dbPath entry, if not changed, uses a constant value Data/Routes.sqlite, relatively to working directory.
If, again, again, I set the absolute path manually, everything (really) works, the the Request flow reached the Action Controllers successfully.
What's going on?
This a bug in PHP's built-in web server that is still not fixed, as of PHP version 5.6.30.
In short, the web server does not redirect to www.foo.com/bar/ if www.foo./bar was requested and happens to be a directory. The client being server www.foo.com/bar, assumes it is a file (because of the missing slash at the end), so all subsequent relative links will be fetched relative to www.foo.com/instead of www.foo.com/bar/.
A bug ticket was opened back in 2013 but was mistakenly set to a status of "Not a Bug".
I'm experiencing a similar issue in 2017, so I left a comment on the bug ticket.
Edit : Just noticed that #jens-a-koch opened the ticket I linked to. I was not awar of his comment on the original question.
I have a web application which I test locally and deploy on EC2 instance
I am using local nginx configuration which looks like as
location /static/ { alias /home/me/code/p/python/myapp/static/;
# if asset versioning is used
if ($query_string) {
expires max;
}
} location /templates/ { alias /home/me/code/p/python/app/templates/;
# if asset versioning is used
if ($query_string) {
expires max;
}
}
On EC2 instance, the only thing that would change is the path, e.g.
/home/me/code/p/python/myapp/static/ to /User/ubuntu/code/p/python/myapp/static/
To make this happen I change the configuration to look like
~/code/p/python/myapp/static/
but this didn't work, it shows the path
/etc/nginx/~/code/p/python/myapp/static/
which is not right
Question
- Is it possible to include environment variables in nginx conf?
What I want
- Nginx conf, which can read variables on specific machines to create paths, so that I don't have to change it per machine and code is reusable
Thank you
Two ways of doing this:
As suggested above, symlinking is a really good way of making paths match on machines, while keeping code in one place. A symbolic link basically is an alias; if /link is a symlink for /file, when you ask for /link, you'll get /file.
ln -s /file /link
Using include statements. In nginx, you can include variables.conf;. E.g.
nginx.conf:
include variables.conf
...
http {
listen $port;
...
}
variables.conf:
set $foo "Something";
set $bar "Else";
set $port 80;
I have a staging server setup something like this:
http://staging.mysite.com
the method below works just fine for my development environment.
In the .htaccess file, i included:
SetEnv APPLICATION_ENV "staging"
Yet Zend still thinks the environment is production.
<title>My Site :: <?= APPLICATION_ENV; ?></title>
yields:
My Site :: production
in the title bar of the browser.
I have searched multiple threads and tried using the
SetEnvIf directive as well with no luck.
Please help!
SetEnv simply sets the Apache environment variable, you can access this with PHP in $_SERVER or using PHP's getenv() function as ZiTAL posted above. You probably want something like this somewhere early in your app (e.g. index.php):
defined('APPLICATION_ENV') || define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'production'));
This populates the constant with the environment variable value unless it is already defined, falling back to the value of 'production' if the env var isn't populated.
Under my local server running php on fcgi, the following .htaccess directive
SetEnv APPLICATION_ENV development
results in the following $_SERVER variable
...
[REDIRECT_APPLICATION_ENV] => development
...
Try to remove the double quote:
SetEnv APPLICATION_ENV staging
and check the return of getenv in PHP:
echo getenv('APPLICATION_ENV');
What do I change to switch from production to staging.. etc.. and where.. Bootstrap ?
Also, Curious if anyone has configured their Zend Framework to automatically switch from
production, staging, test.. etc based on Host information..
example..
if (hostname = 'prodServer') ... blah
if (hostname = 'testServer') ... blah
I'm new to Zend but I typically configure my projects to automatically switch
run environments based on the host information.
thanks
Assuming that you are using APPLICATION_ENV as part of Zend_Application, then you could add this in either your .htaccess or main Apache config (assuming Apache is in use - should still be possible with different Web servers too).
For example, in your .htaccess/config (assumes mod_setenv):
SetEnvIf HTTP_HOST abc.example.com APPLICATION_ENV=production
SetEnvIf HTTP_HOST def.example.com APPLICATION_ENV=staging
SetEnvIf HTTP_HOST ghi.example.com APPLICATION_ENV=development
Then ensure that APPLICATION_ENV is set in index.php by using:
// Define application environment
defined('APPLICATION_ENV') || define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'production'));
This is added by Zend_Tool if you use it to generate the project.
That work for me in .htaccess
SetEnvIf Host dev.mydomain.ca APPLICATION_ENV=development
SetEnvIf Host mydomain.ca APPLICATION_ENV=production
SetEnvIf Host mydomain.localhost APPLICATION_ENV=production
Then in my application.ini
[development : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1
resources.frontController.params.displayExceptions = 1
; Database for development
resources.db.params.dbname = "mydabase-dev"
We define an environment variable (ENVPHP), and use this in our XML configuration files, so the correct DB parameters are loaded as long as you define the correct ENVPHP environment variable. Using XML you can extend (or override) your common parameters with those for the specific environments.
ie. the configuration looks as follows :
<?xml version="1.0" encoding="UTF-8"?>
<application>
<common>
<name>MyApp_name</name>
<code>MyApp_code</code>
<version>MyApp_version</version>
<authentication>
... authentication specific parameters (ie. LDAP connection parameters)
</authentication>
...
</common>
<dev extends="common">
<database>
... DB connection parameters for development
</database>
...
</dev>
<tst extends="common">
<database>
... DB connection parameters for test
</database>
...
</tst>
<prd extends="common">
<database>
... DB connection parameters for production
</database>
...
</prd>
</application>
And to load the configuration, I have the following in my bootstrap (well, actually in an Application singleton class) :
public static function getEnv()
{
if (self::$env === null) {
self::$env = getenv('ENVPHP');
} else {
return self::$env;
}
}
protected function initConfig ()
{
$configFile = $this->appDir . '/config/application.xml';
if (! is_readable($configFile)) {
throw new Application_Exception('Config file "' . $configFile . '" is not readable');
}
if (false === self::getEnv()) {
throw new Application_Exception('The environment variable "ENVPHP" is not defined');
}
$config = new Zend_Config_Xml($configFile, self::getEnv(), true);
$config->setReadOnly();
Zend_Registry::set('config', $config);
$this->config = $config;
}
In PHP code if I want to do some things only for specific environments then I use Application::getEnv() to check what environment I'm in and execute the code I want according to it.
BTW The ENVPHP environment variable can be set in your apache configuration file using ie. SetEnv ENVPHP "dev" within your VirtualHost container. For CLI PHP scripts you should set it as an OS environment variable...
The best way that I saw is:
index.php - production
index_dev.php - dev, index_dev.php/controller/action
I also tried host named configs files:
base.ini - base config
localhost.ini - dev config
prod.host.com.ini - prod config
but the first approach is much better.