Hello!
I use .env files on every ProcessWire project to manage environment-specific configurations and settings. I've built a ProcessWire specific utility that makes using .env files a breeze. This post isn't intended to debate .env vs. config.php, use what you're comfortable with and prefer. That said, here are a few benefits to using .env files that may make it worth considering:
Native support on web servers, including Apache, they are not served via http request by default
True environment based secrets and settings management
A standard file widely used and accepted as the method for managing secrets and sensitive values
Able to store any value whether sensitive or not and access them globally
Building a dedicated solution came from a discussion here on the forums where I threw together a rough implementation that needed little polish for real world use. It makes use of phpdotenv.
This utility delivers the following:
Easy use of and access to .env variables
Caching the parsed .env for performance. This is a significant part of this utility and addresses a known need
Automatic .env change recognition and re-caching
Utilities to make working with environment variables feel ProcessWire native and a few extra nifty things
What it isn't:
A module. It's not possible to make a module for this need because the information kept in a .env file needs to be available before ProcessWire boots.
Adding this to a new or existing project is very easy. It's designed to implement quickly and use immediately in your projects. Full documentation is provided in the Github repository.
Here are a few examples of using this tool:
<?php namespace ProcessWire;
use Env\Env;
if(!defined("PROCESSWIRE")) die();
$env = Env::load(__DIR__ . '/../');
// Make env available throughout the application
$config->env = $env;
$config->dbName = $env->get('DB_NAME');
$config->dbUser = $env->get('DB_USER');
$config->dbPass = $env->get('DB_PASS');
// Env::get() takes a second argument that is the fallback value if for any reason DEBUG doesn't exist
$config->debug = $env->get('DEBUG', false);
// Conditional values. By default, if the condition is falsey, Env::if() returns null
$config->adminEmail = $env->if('APP_ENV', 'production', 'you@youremail.com');
// A fourth argument will be returned if condition is false, truthy/falsey output can be env var names or specific values
$config->adminEmail = $env->if('APP_ENV', 'production', 'ADMIN_EMAIL', 'you@youremail.com');
// Conversely, you can also check if a condition is not met.
$config->adminEmail = $env->ifNot('APP_ENV', 'development', 'ADMIN_EMAIL');
// Use one env value to set multiple config properties
$config->advanced = $env->if('APP_ENV', 'production', false, 'ENABLE_ADVANCED'); // Never in production, change locally in env as needed
$config->adminEmail = $env->ifNot('APP_ENV', 'development', 'ADMIN_EMAIL'); // Never send an email in dev, always on staging/production
These helper methods make is very straightforward to implement a dynamic config file. This can be useful for using secure .env values while retaining the ability to commit and upload some types of changes to your config.php file without needing to touch .env values on the server.
You can also use Env::pushToConfig(). As long as you use the "screaming snake case" naming convention for your environment variable names, type and value recognition are handled automatically.
<?php
$env->pushToConfig($config, [
'usePageClasses' => true,
'templateCompile' => 'TEMPLATE_COMPILE',
'debug' => ['DEBUG', false], // Fallback to false
'advanced' => $env->if('APP_ENV', 'production', false, 'ENABLE_ADVANCED'),
'adminEmail' => $env->ifNot('APP_ENV', 'development', 'ADMIN_EMAIL'),
'httpHosts' => [
'something.com',
'staging.something.com',
'something.ddev.site'
],
]);
Using Env in your application files and templates can be very useful. In the above example we assigned the Env object to $config->env. This lets you access your .env variables globally and use some helpful methods.
<?php if ($config->env->eq('APP_ENV', 'development')): ?>
<script src="/some/development/stuff.js"></script>
<?php endif ?>
<?php
if (!$config->env->exists('GOOGLE_API_KEY')) {
$wire->error('A Google API key could not be loaded from the environment file.');
}
try {
// Do something that could fail
} catch (Exception $e) {
$message = $config->env->if('APP_ENV', 'production', 'Oh no. Friendly message here', $e->getMessage());
}
This utility also automatically casts 'true' and 'false' values in .env files to booleans, and casts numbers to integers. It also includes several configuration options.
I have been using this tool in production and have been happy with it. Maybe you might find it helpful in your projects as well. If you like it, throw a star on the repo. If you run into any bugs, file an issue on Github. I may publish it as a composer package at some point.
Env utility for ProcessWIre on Github.