├── CHANGELOG.md ├── composer.json ├── .gitignore ├── LICENSE.md ├── src └── dotenvy └── README.md /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Connect Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | ## 1.1.0 - 2019-08-14 6 | ### Changed 7 | * Updated to `"vlucas/phpdotenv": "^3.4.0"` 8 | 9 | ## 1.0.2 - 2019-03-24 10 | ### Added 11 | * Add the generation of `.env_docker.txt` for the Docker `Dockerfile` 12 | 13 | ## 1.0.1 - 2019-02-17 14 | ### Added 15 | * Shorten the executable path to `vendor/bin/dotenvy` by telling Composer about the binary 16 | 17 | ## 1.0.0 - 2019-02-16 18 | ### Added 19 | * Initial release 20 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nystudio107/dotenvy", 3 | "description": "Speed up your production sites by ditching .env for key/value variable pairs as Apache, Nginx, and shell equivalents.", 4 | "version": "1.1.0", 5 | "keywords": ["env", "dotenv", "environment", "apache", "nginx", "bash"], 6 | "support": { 7 | "docs": "https://github.com/nystudio107/dotenvy/blob/v1/README.md", 8 | "issues": "https://github.com/nystudio107/dotenvy/issues" 9 | }, 10 | "license" : "MIT", 11 | "authors" : [ 12 | { 13 | "name": "nystudio107", 14 | "homepage": "https://nystudio107.com" 15 | } 16 | ], 17 | "require": { 18 | "php": ">=7.0.0", 19 | "vlucas/phpdotenv": "^3.4.0" 20 | }, 21 | "bin": ["src/dotenvy"], 22 | "autoload": { 23 | "psr-4": { 24 | "nystudio107\\dotenvy\\": "src/" 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Craft 3 .gitignore 2 | # 3 | # Example .gitignore file for Craft 3 CMS projects 4 | # 5 | # @author nystudio107 6 | # @copyright Copyright (c) 2017 nystudio107 7 | # @link https://nystudio107.com/ 8 | # @package nystudio107/craft 9 | # @since 1.0.0 10 | # @license MIT 11 | 12 | # This file should be renamed to '.gitignore' and placed in your 13 | # Craft 3 CMS project root directory 14 | 15 | # CRAFT ENVIRONMENT 16 | .env* 17 | 18 | # COMPOSER 19 | /vendor 20 | 21 | # CRAFT STORAGE 22 | /storage/* 23 | !/storage/.gitkeep 24 | 25 | # ASSETS 26 | /web/assets/* 27 | 28 | # BUILD FILES 29 | /bower_components/* 30 | /node_modules/* 31 | /build/* 32 | /yarn-error.log 33 | /npm-debug.log 34 | /web/dist/* 35 | 36 | # MISC FILES 37 | .cache 38 | .DS_Store 39 | .idea 40 | .project 41 | .settings 42 | *.esproj 43 | *.sublime-workspace 44 | *.sublime-project 45 | *.tmproj 46 | *.tmproject 47 | .vscode/* 48 | !.vscode/settings.json 49 | !.vscode/tasks.json 50 | !.vscode/launch.json 51 | !.vscode/extensions.json 52 | config.codekit3 53 | prepros-6.config 54 | 55 | # CUSTOM 56 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 nystudio107 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /src/dotenvy: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | load(); 26 | $vars = $env->getEnvironmentVariableNames(); 27 | if (!empty($vars)) { 28 | $spaces = getMaxSpaces($vars); 29 | createApacheEnvFile($vars, $spaces); 30 | createNginxEnvFile($vars, $spaces); 31 | createCliEnvFile($vars, $spaces); 32 | createDockerEnvFile($vars, $spaces); 33 | } else { 34 | echo PHP_EOL.'No variables found in the .env at '.DOTENVY_BASE_PATH.PHP_EOL; 35 | } 36 | } else { 37 | echo PHP_EOL.'No .env file found in '.DOTENVY_BASE_PATH.PHP_EOL; 38 | } 39 | 40 | /** 41 | * Generate the Apache SetEnv variables based on the .env file 42 | * 43 | * @param array $vars 44 | * @param int $spaces 45 | */ 46 | function createApacheEnvFile(array $vars, int $spaces) 47 | { 48 | echo 'Generating '.DOTENVY_BASE_PATH.'/.env_apache.txt'.PHP_EOL; 49 | // Open the file 50 | $fp = fopen(DOTENVY_BASE_PATH . '/.env_apache.txt', 'wb'); 51 | // Write out the comments 52 | $comments = [ 53 | '# Apache .env variables', 54 | '# Paste these inside the block', 55 | '# or just include the file directly with the `Include` directive', 56 | ]; 57 | foreach ($comments as $comment) { 58 | fwrite($fp, $comment . PHP_EOL); 59 | } 60 | // Write out the .env variables 61 | foreach ($vars as $var) { 62 | fwrite($fp, 'SetEnv'.getSpaces('', 4).$var.getSpaces($var, $spaces).'"'. $_ENV[$var].'"'.PHP_EOL); 63 | } 64 | fclose($fp); 65 | } 66 | 67 | /** 68 | * Generate the Nginx fastcgi_param variables based on the .env file 69 | * 70 | * @param array $vars 71 | * @param int $spaces 72 | */ 73 | function createNginxEnvFile(array $vars, int $spaces) 74 | { 75 | echo 'Generating '.DOTENVY_BASE_PATH.'/.env_nginx.txt'.PHP_EOL; 76 | // Open the file 77 | $fp = fopen(DOTENVY_BASE_PATH . '/.env_nginx.txt', 'wb'); 78 | // Write out the comments 79 | $comments = [ 80 | '# Nginx .env variables', 81 | '# Paste these inside the server {} or location ~ \.php {} block or in the fastcgi_params file', 82 | '# or just include the file directly with the `include` directive', 83 | ]; 84 | foreach ($comments as $comment) { 85 | fwrite($fp, $comment . PHP_EOL); 86 | } 87 | // Write out the .env variables 88 | foreach ($vars as $var) { 89 | fwrite($fp, 'fastcgi_param'.getSpaces('', 4).$var.getSpaces($var, $spaces).'"'. $_ENV[$var].'";'.PHP_EOL); 90 | } 91 | fclose($fp); 92 | } 93 | 94 | /** 95 | * Generate the shell environment variables based on the .env file 96 | * 97 | * @param array $vars 98 | * @param int $spaces 99 | */ 100 | function createCliEnvFile(array $vars, int $spaces) 101 | { 102 | echo 'Generating '.DOTENVY_BASE_PATH.'/.env_cli.txt'.PHP_EOL; 103 | // Open the file 104 | $fp = fopen(DOTENVY_BASE_PATH . '/.env_cli.txt', 'wb'); 105 | // Write out the comments 106 | $comments = [ 107 | '# CLI (bash) .env variables', 108 | '# Paste these inside your .bashrc file in your $HOME directory:', 109 | ]; 110 | foreach ($comments as $comment) { 111 | fwrite($fp, $comment . PHP_EOL); 112 | } 113 | // Write out the .env variables 114 | foreach ($vars as $var) { 115 | fwrite($fp, 'export '.$var.'="'. $_ENV[$var].'"'.PHP_EOL); 116 | } 117 | fclose($fp); 118 | } 119 | 120 | /** 121 | * Generate the Dockerfile ENV variables based on the .env file 122 | * 123 | * @param array $vars 124 | * @param int $spaces 125 | */ 126 | function createDockerEnvFile(array $vars, int $spaces) 127 | { 128 | echo 'Generating '.DOTENVY_BASE_PATH.'/.env_docker.txt'.PHP_EOL; 129 | // Open the file 130 | $fp = fopen(DOTENVY_BASE_PATH . '/.env_docker.txt', 'wb'); 131 | // Write out the comments 132 | $comments = [ 133 | '# Docker .env variables', 134 | '# Paste these into your Dockerfile', 135 | ]; 136 | foreach ($comments as $comment) { 137 | fwrite($fp, $comment . PHP_EOL); 138 | } 139 | // Write out the .env variables 140 | foreach ($vars as $var) { 141 | fwrite($fp, 'ENV '.$var.'="'. $_ENV[$var].'"'.PHP_EOL); 142 | } 143 | fclose($fp); 144 | } 145 | 146 | /** 147 | * @param array $vars 148 | * 149 | * @return int 150 | */ 151 | function getMaxSpaces(array $vars) 152 | { 153 | $len = 0; 154 | // Find the longest .env variable name 155 | foreach ($vars as $var) { 156 | if (strlen($var) > $len) { 157 | $len = strlen($var); 158 | } 159 | } 160 | 161 | return (int)(round(($len / 4) + .5) * 4); 162 | } 163 | 164 | /** 165 | * @param string $str 166 | * @param int $number 167 | * 168 | * @return string 169 | */ 170 | function getSpaces(string $str, int $number): string 171 | { 172 | $spaces = ''; 173 | $num = $number - strlen($str); 174 | if ($num < 0) { 175 | $num = 0; 176 | } 177 | while ($num--) { 178 | $spaces .= ' '; 179 | } 180 | 181 | return $spaces; 182 | } 183 | 184 | exit(0); 185 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/nystudio107/dotenvy/badges/quality-score.png?b=v1)](https://scrutinizer-ci.com/g/nystudio107/dotenvy/?branch=v1) [![Code Coverage](https://scrutinizer-ci.com/g/nystudio107/dotenvy/badges/coverage.png?b=v1)](https://scrutinizer-ci.com/g/nystudio107/dotenvy/?branch=v1) [![Build Status](https://scrutinizer-ci.com/g/nystudio107/dotenvy/badges/build.png?b=v1)](https://scrutinizer-ci.com/g/nystudio107/dotenvy/build-status/v1) [![Code Intelligence Status](https://scrutinizer-ci.com/g/nystudio107/dotenvy/badges/code-intelligence.svg?b=v1)](https://scrutinizer-ci.com/code-intelligence) 2 | 3 | # Dotenvy 4 | 5 | Speed up your production sites by ditching .env for key/value variable pairs as Apache, Nginx, and shell equivalents 6 | 7 | ## Requirements 8 | 9 | PHP 7.0 or later, and a project that uses [Composer](https://getcomposer.org/) 10 | 11 | ## Installation 12 | 13 | To install this package, follow these instructions. 14 | 15 | 1. Open your terminal and go to your project: 16 | 17 | cd /path/to/project 18 | 19 | 2. Then tell Composer to require the package: 20 | 21 | composer require nystudio107/dotenvy 22 | 23 | ## CraftQuest.io video: Injecting Environment Variables with Dotenvy 24 | 25 | [![CraftQuest.io video: Injecting Environment Variables with Dotenvy](https://i.vimeocdn.com/video/769743390.jpg?mw=1900&mh=1069&q=70)](https://craftquest.io/livestreams/injecting-environment-variables-with-dotenvy) 26 | 27 | ## Dotenvy Overview 28 | 29 | Dotenvy is a small tool that takes the contents of your `.env` file, and outputs them in a format that can be pasted directly into an Apache server config, Nginx server config, shell CLI `.bashrc`, or Docker `Dockerfile` 30 | 31 | Why? Because as per the [phpdotenv](https://github.com/vlucas/phpdotenv) documentation: 32 | 33 | > phpdotenv is made for development environments, and generally should not be used in production. **In production, the actual environment variables should be set so that there is no overhead of loading the .env file on each request.** This can be achieved via an automated deployment process with tools like Vagrant, chef, or Puppet, or can be set manually with cloud hosts like Pagodabox and Heroku. 34 | 35 | The `.env` file is meant to be a convenience to make things easier to change in local development environments. 36 | 37 | What the [phpdotenv](https://github.com/vlucas/phpdotenv) package does is parse your `.env` file, and then call [putenv()](http://php.net/manual/en/function.putenv.php) to set each environment variable. This sets the [$_ENV superglobal](http://php.net/manual/en/reserved.variables.environment.php) that your application can later read in via [getenv()](http://php.net/manual/en/function.getenv.php). 38 | 39 | Using the technique described here, the exact same `$_ENV` superglobal gets set with your environmental variables, and are made available via the same `getenv()` function. The difference is that your webserver or CLI sets the variables directly, without having to parse the `.env` file. 40 | 41 | Without question, this is a micro-optimization... and is unlikely to make a significant performance difference. But why add overhead for no reason? 42 | 43 | This is a partial implementation of feature I've been hoping to have in Craft CMS core in some fashion: [Add `craft config/cache` as a console command](https://github.com/craftcms/cms/issues/1607) 44 | 45 | ## Using Dotenvy 46 | 47 | From your project's root directory that contains the `.env` and `/vendor` directory, do: 48 | 49 | ```bash 50 | vendor/bin/dotenvy 51 | ``` 52 | 53 | If you're on Windows, do: 54 | ```bash 55 | vendor/bin/dotenvy.bat 56 | ``` 57 | 58 | If your `.env` file lives somewhere else, you can pass in the directory to the `.env` file: 59 | 60 | ```bash 61 | vendor/bin/dotenvy /path/to/some/dir/ 62 | ``` 63 | 64 | Then **do not create** a `.env` file on your production environment, instead paste or insert via a deployment system the resulting file that Dotenvy generates for you. 65 | 66 | In this way, the appropriate `.env` variables will be automatically injected by your Apache server, or Nginx server, or via CLI. 67 | 68 | This means that the `.env` file no longer needs to be parsed on every request. 69 | 70 | ### Updating `.gitignore` 71 | 72 | Make sure you `.gitignore` all of the `.env*` files with a line like this in your root project `.gitignore` file: 73 | 74 | ``` 75 | .env* 76 | ``` 77 | ...to ensure that none of your secrets in the generated `.env*` files are checked into git. Note the trailing `*` 78 | 79 | ### Example `.env` file 80 | 81 | Given a `.env` file that looks like this: 82 | 83 | ```bash 84 | # The environment Craft is currently running in ('dev', 'staging', 'production', etc.) 85 | ENVIRONMENT="local" 86 | 87 | # The secure key Craft will use for hashing and encrypting data 88 | SECURITY_KEY="jMgCxHuaM1g3qSzHiknTt5S8gDy5BNW7" 89 | 90 | # The database driver that will be used ('mysql' or 'pgsql') 91 | DB_DRIVER="mysql" 92 | 93 | # The database server name or IP address (usually this is 'localhost' or '127.0.0.1') 94 | DB_SERVER="localhost" 95 | 96 | # The database username to connect with 97 | DB_USER="homestead" 98 | 99 | # The database password to connect with 100 | DB_PASSWORD="secret" 101 | 102 | # The name of the database to select 103 | DB_DATABASE="craft3" 104 | 105 | # The database schema that will be used (PostgreSQL only) 106 | DB_SCHEMA="public" 107 | 108 | # The prefix that should be added to generated table names (only necessary if multiple things are sharing the same database) 109 | DB_TABLE_PREFIX="" 110 | 111 | # The port to connect to the database with. Will default to 5432 for PostgreSQL and 3306 for MySQL. 112 | DB_PORT="3306" 113 | ``` 114 | 115 | The following files will be output in the same directory as the `.env` file: 116 | 117 | #### Apache `.env_apache.txt` 118 | 119 | Paste these inside the `` block 120 | 121 | ```apacheconfig 122 | # Apache .env variables 123 | # Paste these inside the block: 124 | SetEnv ENVIRONMENT "local" 125 | SetEnv SECURITY_KEY "jMgCxHuaM1g3qSzHiknTt5S8gDy5BNW7" 126 | SetEnv DB_DRIVER "mysql" 127 | SetEnv DB_SERVER "localhost" 128 | SetEnv DB_USER "homestead" 129 | SetEnv DB_PASSWORD "secret" 130 | SetEnv DB_DATABASE "craft3" 131 | SetEnv DB_SCHEMA "public" 132 | SetEnv DB_TABLE_PREFIX "" 133 | SetEnv DB_PORT "3306" 134 | ``` 135 | 136 | ...or you can include the files that Dotenvy generates directly in your Apache conf via: 137 | 138 | ``` 139 | Include /home/forge/SOMEDOMAIN/.env_apache.txt 140 | ``` 141 | 142 | #### Nginx `.env_nginx.txt` 143 | 144 | Paste these inside the `server {}` or `location ~ \.php {}` block or in the `fastcgi_params` file: 145 | 146 | ```apacheconfig 147 | # Nginx .env variables 148 | # Paste these inside the server {} or location ~ \.php {} block or in the fastcgi_params file: 149 | fastcgi_param ENVIRONMENT "local"; 150 | fastcgi_param SECURITY_KEY "jMgCxHuaM1g3qSzHiknTt5S8gDy5BNW7"; 151 | fastcgi_param DB_DRIVER "mysql"; 152 | fastcgi_param DB_SERVER "localhost"; 153 | fastcgi_param DB_USER "homestead"; 154 | fastcgi_param DB_PASSWORD "secret"; 155 | fastcgi_param DB_DATABASE "craft3"; 156 | fastcgi_param DB_SCHEMA "public"; 157 | fastcgi_param DB_TABLE_PREFIX ""; 158 | fastcgi_param DB_PORT "3306"; 159 | ``` 160 | 161 | ...or you can include the files that Dotenvy generates directly in your Nginx conf via: 162 | 163 | ``` 164 | include /home/forge/SOMEDOMAIN/.env_nginx.txt 165 | ``` 166 | 167 | See [Nginx-Craft](https://github.com/nystudio107/nginx-craft) for details. 168 | 169 | #### CLI (Bash shell) `.env_cli.txt` 170 | 171 | Paste these inside your `.bashrc` file in your `$HOME` directory: 172 | 173 | ```bash 174 | # CLI (bash) .env variables 175 | # Paste these inside your .bashrc file in your $HOME directory: 176 | export ENVIRONMENT="local" 177 | export SECURITY_KEY="jMgCxHuaM1g3qSzHiknTt5S8gDy5BNW7" 178 | export DB_DRIVER="mysql" 179 | export DB_SERVER="localhost" 180 | export DB_USER="homestead" 181 | export DB_PASSWORD="secret" 182 | export DB_DATABASE="craft3" 183 | export DB_SCHEMA="public" 184 | export DB_TABLE_PREFIX="" 185 | export DB_PORT="3306" 186 | ``` 187 | 188 | #### Docker `.env_docker.txt` 189 | 190 | Paste these inside your `Dockerfile` file: 191 | 192 | ```dockerfile 193 | # Docker .env variables 194 | # Paste these into your Dockerfile 195 | ENV ENVIRONMENT="local" 196 | ENV SECURITY_KEY="jMgCxHuaM1g3qSzHiknTt5S8gDy5BNW7" 197 | ENV DB_DRIVER="mysql" 198 | ENV DB_SERVER="localhost" 199 | ENV DB_USER="homestead" 200 | ENV DB_PASSWORD="secret" 201 | ENV DB_DATABASE="craft3" 202 | ENV DB_SCHEMA="public" 203 | ENV DB_TABLE_PREFIX="" 204 | ENV DB_PORT="3306" 205 | ``` 206 | 207 | ## The Craft CMS CLI 208 | 209 | Note that if you set the `.env` variables directly in your Apache or Nginx config, these variables will **not** be available using the Craft CMS `./craft` CLI command. 210 | 211 | That's because the webserver doesn't run at all for CLI requests. Instead, you'll need to add them to your `.bashrc` file as noted above, or you can use the Unix [source](https://bash.cyberciti.biz/guide/Source_command) command, e.g: 212 | 213 | ```bash 214 | source .env_cli.txt && ./craft migrate/all 215 | ``` 216 | 217 | In the above example, the `source` command will execute the `export` statements in the `.env_cli.txt` and then run the `./craft` executable with those environmental variables set. 218 | 219 | This pattern is useful if you are running multiple sites on a single instance, and so setting the `.env` variables globally for a user via `.bashrc` doesn't make sense. 220 | 221 | ## Dotenvy Roadmap 222 | 223 | Some things to do, and ideas for potential features: 224 | 225 | * Release it 226 | 227 | Brought to you by [nystudio107](https://nystudio107.com/) 228 | --------------------------------------------------------------------------------