Skip to content

Instantly share code, notes, and snippets.

@levacic
Last active August 29, 2015 14:06
Show Gist options
  • Save levacic/c78db820d7ee3f389a86 to your computer and use it in GitHub Desktop.
Save levacic/c78db820d7ee3f389a86 to your computer and use it in GitHub Desktop.
Laravel environment loading
<?php
/**
* Copy this file to `.environment.php`, and set all variables to the
* environment-specific configuration.
*/
return [
/**
* The current application environment.
*/
'APP_ENV' => '',
/**
* Database credentials.
*/
'DB_HOSTNAME' => '',
'DB_DATABASE' => '',
'DB_USERNAME' => '',
'DB_PASSWORD' => '',
/**
* Redis configuration and credentials.
*/
'REDIS_HOST' => '',
'REDIS_PORT' => '',
'REDIS_DATABASE' => '',
'REDIS_PASSWORD' => '',
/**
* The app key used for encryption. This can be generated via the artisan
* command `key:generate`, but the `app.key` config entry should reference
* this environment variable, rather than hardcoding (and commiting to the
* repository) a key in the config file.
*/
'APP_KEY' => '',
];
<?php
/*
|--------------------------------------------------------------------------
| Load The Environment configuration
|--------------------------------------------------------------------------
|
| First we'll load the environment variables from the appropriate
| configuration file. This enables as to protect sensitive application
| configuration parameters, in environments where it's not possible to
| configure actual environment variables to the appropriate values.
|
*/
$environmentLoader = new Creitive\Config\EnvironmentLoader(__DIR__.'/..');
$environmentLoader->load();
/*
|--------------------------------------------------------------------------
| Create The Application
|--------------------------------------------------------------------------
|
| The first thing we will do is create a new Laravel application instance
| which serves as the "glue" for all the components of Laravel, and is
| the IoC container for the system binding all of the various parts.
|
*/
$app = new Illuminate\Foundation\Application;
/*
|--------------------------------------------------------------------------
| Detect The Application Environment
|--------------------------------------------------------------------------
|
| Laravel takes a dead simple approach to your application environments
| so you can just specify a machine name for the host that matches a
| given environment, then we will automatically detect it for you.
|
*/
$env = $app->detectEnvironment(function()
{
$env = getenv('APP_ENV');
if ($env !== false)
{
return $env;
}
$zone = new DateTimeZone('UTC');
$now = new DateTime('now', $zone);
$now = $now->format('Y-m-d H:i:s');
error_log("[{$now}] log.ERROR: The \"/.environment.php\" file is missing, and the \"APP_ENV\" environment variable is not set - falling back to production. Please configure the environment explicitly.\n", 3, __DIR__.'/../app/storage/logs/laravel.log');
return 'production';
});
/* path binding, app loading, return $app */
<?php namespace Creitive\Config\Console;
use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputOption;
class MakeEnvironmentConfigCommand extends Command {
/**
* The console command name.
*
* @var string
*/
protected $name = 'make:env';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Environment configuration generator';
/**
* Execute the console command.
*
* @return void
*/
public function fire()
{
$sourceFile = $this->option('source');
$targetFile = $this->option('target');
$template = require $sourceFile;
$target = file_exists($targetFile) ? (require $targetFile) : [];
$this->info("Configure the new environment variable values. Current values are shown in square brackets. Just press ENTER to leave the default. This will overwrite {$targetFile}");
foreach ($template as $key => $value)
{
$current = isset($target[$key]) ? $target[$key] : $value;
$target[$key] = $this->ask("{$key} [{$current}]:", $current);
}
file_put_contents($targetFile, $this->compileFile($target));
return 0;
}
/**
* Compiles the configuration array into a file that can later be required
* within PHP.
*
* @param array $configuration
* @return string
*/
public function compileFile(array $configuration)
{
$values = var_export($configuration, true);
return "<?php return {$values};";
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return [
['source', null, InputOption::VALUE_REQUIRED, 'The source file', '.environment.template.php'],
['target', null, InputOption::VALUE_REQUIRED, 'The source file', '.environment.php'],
];
}
}
<?php namespace Creitive\Config;
/**
* PHP $_ENV loader for protecting sensitive configuration options.
*
* Inspired by the wonderful "Dotenv" library by Vance Lucas.
*/
class EnvironmentLoader {
/**
* The path to the configuration files.
*
* @var string
*/
protected $path;
/**
* The server environment instance.
*
* @param string $path
* @return void
*/
public function __construct($path)
{
$this->path = $path;
}
/**
* Load the server variables for a given environment.
*
* @return void
*/
public function load()
{
foreach ($this->loadFromFile() as $key => $value)
{
$_ENV[$key] = $value;
$_SERVER[$key] = $value;
putenv("{$key}={$value}");
/**
* In cases where an environment variable is set by Apache, e.g. via
* .htaccess or the VirtualHost block, none of the above approaches
* seem to work; ie. the variable is overriden by whatever is
* already configured with Apache. This is the correct solution for
* that problem, but `apache_setenv()` is only available if PHP is
* actually running on Apache, so we'll just call it when we can.
*/
if (function_exists('apache_setenv'))
{
apache_setenv($key, $value);
}
}
}
/**
* Load the environment variables.
*
* @return array
*/
public function loadFromFile()
{
$path = $this->path.'/.environment.php';
if ( ! file_exists($path))
{
return [];
}
return require $path;
}
}
@levacic
Copy link
Author

levacic commented Sep 17, 2014

The kind of complicated logging in the detectEnvironment() closure is needed because Laravel hasn't yet called date_default_timezone_set() by this point, and PHP complains if you try to instantiate DateTime without a timezone.

We're defaulting to production to protect sensitive data from being leaked (since, by default, debugging is off in non-local environments, and if we had debugging, this would be a serious security issue, because Whoops dumps all superglobals).

@levacic
Copy link
Author

levacic commented Sep 17, 2014

The MakeEnvironmentConfigCommand could also automatically generate the APP_KEY, without prompting the user, if it isn't set already, or just leave it if it is (it certainly shouldn't be changed once configured, since that would break encryption application-wide).

If it does need to be force-changed, though, we could add a --regenerate-app-key option.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment