Laravel Environment detection - php

I want custom environment detection. I know how the existing Laravel environment detection works, but I want a more dynamic way. I want to EXPORT a variable in my Ubuntu env, suggesting it's 'development' or 'production', as opposed to using host names and IP addresses.
Any help would be great, thanks.

What I do in my projects is I create a file "app/bootstrap/environment.php"
environment.php
<?php
//Get the environment
$environment = getenv('ENV');
//Check if the environment has been set
if(is_string($environment) && ($environment != '')){
//Return the environment
return $environment;
}else{
//On default return production environment
return 'production';
}
Then in "app/bootstrap/start.php"
start.php
$env = $app->detectEnvironment(function()
{
//Return the environment we're currently using
return require __DIR__.'/environment.php';
});
Works perfect for me.

Related

Laravel 4.2 Environments on the same Server

I've to deploy several instances of a Laravel app to a unique server. Each instance requires a different database configuration. The default Laravel's environment configuration based on hostnames doesn't work for me because all the apps are going to be on the same server, so there's no way to tell which config fiel to use. Here is my bootstrap/start.php file:
$env = $app->detectEnvironment(array(
'development' => array('Ariels-MacBook-Pro.local'),
'server' => array('srv-hostname'),
));
It would be great that I can define the environment based upon a domain (because my apps area gonna be on diferent domains), so in this way I can define a different config for each domain (hosted on the same server)
Any ideas?
Laravel's detectEnvironment method has a nify feature where you can progamatically determine the current enviornment with a closure. For example, this would configure Laravel to always use the local enviornment.
$env = $app->detectEnvironment(function()
{
return 'local';
});
The domain name should be somewhere in $_SERVER, so something like this untested pseudo-code should get you what you want.
$env = $app->detectEnvironment(function()
{
switch($_SERVER['HTTP_HOST'])
{
case: 'example.com':
return 'production';
case: 'another.example.xom':
return 'production';
default:
return 'local'; //default to local
}
});
My option, in file app/config/database.php add this line at the end
'enviorement' => 'local',
// 'enviorement' => 'development', // this is for dev
// 'enviorement' => 'production', // this is for production
and then access from your controller with this
$env = Config::get('database.enviorement');
echo $env;
database.php file is different, you have for ur local another for developemet server and another for producction because there is the "database conection" so i used it to implicit write the enviorement.
Have fun.

Environment detection in Laravel 4.1+

Laravel 4.1 removed the feature to use the domain for detecting what environment the app is running in. Reading the docs they now suggest using host names. However, to me that seems cumbersome if you are working in a team. Should everyone change the bootstrap/start.php file and add their own host name to be able to run the app in a dev environment? Also, what if you want to have two different environments on the same machine?
How to best detect the environment if you are working in a team in Laravel 4.1+?
Here is my settings from bootstrap/start.php file:
$env = $app->detectEnvironment(function() use($app) {
return getenv('ENV') ?: ($app->runningInConsole() ? 'local' : 'production');
});
Instead of default array, this method in my case is returning closure with ternary. That way I got more flexibility in choosing desired environment. You can use switch statement also. Laravel will read return value and configure itself.
With getenv native function, I am just listening for a given environment. If my app is on the server, then it will "pick" server configurations. If locally, then it will pick local (or development)
And don't forget to create custom directories for you environemnts in app/config
There is also testing env, which is choosen automatically, every time you are unit testing app.
Laravel makes working with environments really fun.
UPDATE:
With environments we are mostly cencerned about db credentials.
For production I use Fortrabbit, so when configuring new app on server, fortrabbit is generating those values for me. I just need to declare them. e.g. DB of just database or db... Or DB_HOST or HOST ...
Locally, those values are the one you use for your localhost/mysql settings.
Update:
In Laravel 5.0 environment detection is no longer needed in the same way. In the .env file you can simply have a variable for which environment the app should run in.
Old answer for Laravel <= 4.2
What I ended up doing is very close to what carousel suggested. Anyway, thought I would share it. Here is the relevant part of our bootstrap/start.php file:
$env = $app->detectEnvironment(function ()
{
if($app->runningInConsole())
return "development";
$validEnvironments = array("development", "staging", "production");
if (in_array(getenv('APP_ENV'), $validEnvironments)) {
return getenv('APP_ENV');
}
throw new Exception("Environment variable not set or is not valid. See developer manual for further information.");
});
This way all team members have to declare an environment variable somewhere. I haven't really decided if throwing an exception if the environment variable is not set or just default to production is the best thing. However, with the above, it's easy to change.
For me, I just use 'dev' => '*.local' and it works. I haven't 100% tested in a team situation but I think it'd work (big assumption alert:) assuming you're on OSX and get the default Alexs-iMac.local-like hostname.
As for faking an environment, I'm not sure it's really supported. It'll be doable, but in general the whole point of environments is that dev has entirely different needs to production and the two are mutually exclusive. Having the ability to switch on one physical environment seems counter to that goal.
Laravel 4.1 and 4.2 detects the environments through the machine names specified in the "bootstrap/start.php" file.
For example, in my case the config becomes:
$env = $app->detectEnvironment(array(
'local' => array('Victor.local', 'Victor-PC'),
));
This means that Laravel will use the 'local' environment settings for both machines: 'Victor.local' (a Mac) and 'Victor-PC' (Windows).
This way you can regsiter several machines to work as local environment. Other environments can be registered too.
In order to know the current machine name, you can use the following PHP code:
<?php echo gethostname(); ?>
Hope it helps!
You can use something like this:
$env = $app->detectEnvironment(function(){
if($_SERVER['HTTP_HOST'] == 'youdomain_local')
{
return 'local';
}elseif($_SERVER['HTTP_HOST'] == 'youdomain_team')
{
return 'team';
}else{
return 'production';
}
});
what i did is, make dir app/config/local and use code
$env = $app->detectEnvironment(function(){
return $_SERVER['HTTP_HOST']=="localhost"?"local":"production";
});
For localhost and online.
I didn't like that production was default, so I made it anything other than live server will go to local configs:
in bootstrap/start.php :
$env = $app->detectEnvironment(function(){
if (gethostname() !== 'live_server_hostname'){
return 'local';
} else {
return 'production';
}
});
In bootstrap/start.php define this:
$env = $app->detectEnvironment(function() use($app) {
$enviromentsHosts = [
'localhost',
'local',
];
if ($app->runningInConsole() || in_array($app['request']->getHost(), $enviromentsHosts)) {
return 'local';
} else {
return 'production';
}
});
I believe it is better to use only the resources of Laravel 4

Multiple Environments and CRON with PHP

On my CodeIgniter site, I use something like this to distinguish between live and dev environments.
if (defined('STDIN') || $_SERVER['SERVER_NAME']=='livesite.com') {
define('ENVIRONMENT', 'production');
} else {
define('ENVIRONMENT', 'development');
}
Then, based on environment my code sets up proper database configurations.
I also have several CRON jobs that run via PHP, effectively running certain code within the site.
When I run CRON jobs that work with this code, they seem to just default to production environment. So all the CRONs I run on dev are still connecting to production database. How can I modify the code above to play nice with CRON as well? I just need a way to detect if CRON is being run on production or dev as well so that it will connect to respective DB.
$_SERVER is not defined in cronjobs, which is why your check fails.
There are several ways to identify the environment, depending on your configuration:
php -B "define('ENVIRONMENT', 'test');" /path/to/cronjob.php
Then in the code check:
if (!defined('ENVIRONMENT')) {
.. do your $_SERVER check ..
}
If your environments are on different hosts, you can use:
if (php_sapi_name() == 'cli') { // Check if it's running from console/cron
if (trim(`uname -n`) == 'myserver.dev') { // not portable to windows
define('ENVIRONMENT', 'test');
} else {
define('ENVIRONMENT', 'production');
}
} else {
... do your $_SERVER check ...
}
You can set a cron variable, e.g.
*/15 * * * * ENVIRONMENT="test" php /path/to/cron
Then check in your script:
if (php_sapi_name() == 'cli') {
// you should check if it's valid first. Left out as exercise for the reader
define('ENVIRONMENT', $_ENV['ENVIRONMENT']);
} else {
... do your $_SERVER check ...
}
Here's what worked for me:
if (php_sapi_name() == 'cli') {
switch ($_SERVER['PWD']) {
case '/path/to/production':
define('ENVIRONMENT', 'production');
break;
case '/path/to/testing':
define('ENVIRONMENT', 'testing');
break;
default:
define('ENVIRONMENT', 'development');
break;
}
} else {
// Not via CLI; Check $_SERVER['HTTP_HOST']
}
Open up Terminal and run php -i to see what variables are available on your server that you can use. I like to default to my development environment because different developers can set up different virtual hosts or paths to their working directory.
Set Var in Command Way:
$ CI_ENV="production" php index.php welcome/index
Create Bootstrap Way
You could create a bootstrap for CLI with production environment concern:
In Codeigniter webroot: ./cli-prod.php
if (php_sapi_name() !== 'cli') {
die('Access Denied');
}
define('ENVIRONMENT', 'production');
require __DIR__ . '/index.php';
After that, run command likes:
php ./cli-prod.php controller/action

How to determine the environment in a cronjob

I've got an issue on how to determine the application's environment during a cronjob.
I have currently have 2 environments: a production and a testing environment. They both use their own database.
I determine the current environment based on the URL. For example: dev.domain.com sets the environment to testing and domain.com sets it to production.
This works perfectly. However, this does not work for cronjobs. Because a cronjob does not get a domain.
How would I solve this and still keeping things dynamic?
This is what the code currently looks like:
if($_SERVER['SERVER_NAME'] == 'dev.domain.com' || $_SERVER['SERVER_NAME'] == 'domain.local') {
define('ENVIRONMENT', 'development');
}else if ($_SERVER['SERVER_NAME'] == 'domain.com'){
define('ENVIRONMENT', 'production');
}
Thanks in advance.
You can pass server name in cron job.
Example if your current php command look likes.
php a.php --uri="/foo"
It will become
SERVER_NAME=dev.domain.com php a.php --uri="/foo"

How to check if the php script is running on a local server?

Is it possible to check if the website (php) is running locally or on a hosted server?
I want to enable some logs if the website is running locally and I don't want these to appear on the site online..
I can set a variable $local=1; but I'll have to change that before uploading.. is there anyway to automate this task?
Local Server : WampServer 2.0 / Apache
WebServer: Apache
Check $_SERVER['REMOTE_ADDR']=='127.0.0.1'. This will only be true if running locally. Be aware that this means local to the server as well. So if you have any scripts running on the server which make requests to your PHP pages, they will satisfy this condition too.
I believe the best approach is to 'fake' a testing mode, which can be done by creating a file in your local environment.
When I used this approach I created an empty text file called testing.txt and then used the following code:
if (file_exists('testing.txt')) {
// then we are local or on a test environment
} else {
// we are in production!
}
This approach is 100% compatible with any Operating System and you can use several test files in case you want a more granular approach (e.g. development.txt, testing.txt, staging.txt, or production.txt) in order to customise your deployment process.
You should automate deployment
This is not directly the answer to your question, but in my opinion the better way. In an automated deployment process, setting a variable like $local = true, like other configuration values (for example your db-connection), would be no manual, error prone, task.
Checking for 'localness' is in my opinion the wrong way: you dont want to show your logs to every local visitor (a Proxy may be one), but only when deployed in a testing environment.
A popular tool for automated deployment is Capistrano, there should be PHP-Centric tools too.
Just in case this is useful to anybody, I made this function as the above answers didn't really do what I was looking for:
function is_local() {
if($_SERVER['HTTP_HOST'] == 'localhost'
|| substr($_SERVER['HTTP_HOST'],0,3) == '10.'
|| substr($_SERVER['HTTP_HOST'],0,7) == '192.168') return true;
return false;
}
$whitelist = array(
'127.0.0.1',
'::1'
);
if(!in_array($_SERVER['REMOTE_ADDR'], $whitelist)){
// not valid
}
I have build this function that checks if current server name has name server records, normally local server don't has.
<?php
function isLocal ()
{
return !checkdnsrr($_SERVER['SERVER_NAME'], 'NS');
}
?>
Your remote server is unlikely to have a C drive! So I run with this:
//Local detection
$root = $_SERVER["DOCUMENT_ROOT"];
$parts = explode("/",$root);
$base = $parts[0];
$local = false;
if ($base == "C:") {
$local = true; //Change later for if local
}

Categories