├── .gitignore ├── .scrutinizer.yml ├── .travis.yml ├── LICENSE ├── README.md ├── composer.json ├── phpunit.xml ├── src ├── DotEnv.php └── Exceptions │ └── MissingVariableException.php └── tests ├── DotEnvTest.php └── fixtures └── test_source.php /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | composer.phar 3 | composer.lock 4 | .DS_Store 5 | /.idea 6 | -------------------------------------------------------------------------------- /.scrutinizer.yml: -------------------------------------------------------------------------------- 1 | filter: 2 | paths: 3 | - 'src/*' 4 | excluded_paths: 5 | - 'vendor/*' 6 | - 'tests/*' 7 | tools: 8 | php_cs_fixer: 9 | config: { level: psr2 } 10 | checks: 11 | php: 12 | code_rating: true 13 | duplication: true -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.4 5 | - 5.5 6 | - 5.6 7 | - 7.0 8 | - 7.1 9 | 10 | before_script: 11 | - composer self-update 12 | - composer install --prefer-source --no-interaction 13 | 14 | script: 15 | - vendor/bin/phpunit -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Nekrasov Ilya 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Latest Stable Version](https://poser.pugx.org/arrilot/dotenv-php/v/stable.svg)](https://packagist.org/packages/arrilot/dotenv-php/) 2 | [![Total Downloads](https://img.shields.io/packagist/dt/arrilot/dotenv-php.svg?style=flat)](https://packagist.org/packages/Arrilot/dotenv-php) 3 | [![Build Status](https://img.shields.io/travis/arrilot/dotenv-php/master.svg?style=flat)](https://travis-ci.org/arrilot/dotenv-php) 4 | [![Scrutinizer Quality Score](https://scrutinizer-ci.com/g/arrilot/dotenv-php/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/arrilot/dotenv-php/) 5 | 6 | # Simple dotenv for PHP 7 | 8 | ## Introduction 9 | 10 | Q: What's the point of this package? How is it any different from those [vlucas/phpdotenv](https://github.com/vlucas/phpdotenv/) and [josegonzalez/php-dotenv](https://github.com/josegonzalez/php-dotenv) well-known packages? 11 | 12 | A: Those great packages are NOT for production. They were always meant to be used during local development only. 13 | The main reasons are: 14 | 1) Not fast enough 15 | 2) Not secure enough 16 | 17 | Many people are actually misuse those packages and use them to configure apps in production too. 18 | 19 | In contrast this package IS for production. 20 | It uses plain old php array for `.env` content and doesn't touch $_ENV or $_SERVER by default. 21 | As a result it's fast and secure but has less features. 22 | 23 | ## Installation 24 | 25 | 1) `composer require arrilot/dotenv-php` 26 | 27 | 2) Create `.env.php` file to store configuration settings that are environment specific or sensitive. 28 | 29 | Example: 30 | 31 | ```php 32 | 'root', 36 | 'DB_PASSWORD' => 'secret', 37 | ]; 38 | 39 | ``` 40 | 41 | This file should NEVER be added to version control. 42 | 43 | 3) Create `.env.example.php` file and add it to version control. This file should serve as an example for developers how `.env.php` file should look like. 44 | 45 | 4) Load `.env.php` file 46 | 47 | ```php 48 | use Arrilot\DotEnv\DotEnv; 49 | DotEnv::load('/path/to/.env.php'); 50 | ``` 51 | 52 | ## Usage 53 | 54 | ### Getting data 55 | 56 | The most used case is to get dotenv variable. 57 | 58 | ```php 59 | $dbUser = DotEnv::get('DB_USER'); 60 | ``` 61 | 62 | You may pass a second parameter, which is gonna be used as default if variable is not set. 63 | 64 | ```php 65 | $dbUser = DotEnv::get('DB_USER', 'admin'); 66 | ``` 67 | 68 | > Note 69 | This is the method you are going to use most of the time. 70 | It makes sense to add a global helper for it to avoid importing the class name and e.t.c. 71 | 72 | ```php 73 | function env($key, $default = null) 74 | { 75 | return \Arrilot\DotEnv\DotEnv::get($key, $default); 76 | } 77 | ... 78 | $dbUser = env('DB_USER', 'admin'); 79 | ``` 80 | 81 | You can also get all dotenv variables at once: 82 | 83 | ```php 84 | $variables = DotEnv::all(); 85 | ``` 86 | 87 | ### Setting data 88 | 89 | You can set or override specific variable like that: 90 | 91 | ```php 92 | DotEnv::set('DB_USER', 'admin'); 93 | DotEnv::set('DB_PASSWORD', 'secret'); 94 | // or 95 | DotEnv::set([ 96 | 'DB_USER' => 'root', 97 | 'DB_PASSWORD' => 'secret', 98 | ]); 99 | ``` 100 | 101 | You can reload all variables entirely from file or array 102 | 103 | ```php 104 | DotEnv::load('/path/to/new/.env.php'); 105 | //or 106 | DotEnv::load([ 107 | 'DB_USER' => 'root', 108 | 'DB_PASSWORD' => 'secret', 109 | ]); 110 | ``` 111 | 112 | ### Other methods 113 | 114 | There is way to ensure that a specific dotenv variable exists. 115 | Example: 116 | 117 | ```php 118 | DotEnv::setRequired(['DB_USER', 'DB_PASSWORD']); 119 | ``` 120 | If the variable is not loaded an `Arrilot\DotEnv\Exceptions\MissingVariableException` will be thrown. 121 | 122 | There are also convenient methods to copy all variables to `putenv()`, `$_ENV` or `$_SERVER` if you DO need it, but in most cases you don't 123 | 124 | ```php 125 | DotEnv::copyVarsToPutenv($prefix = 'PHP_'); // putenv() 126 | DotEnv::copyVarsToEnv(); // $_ENV 127 | DotEnv::copyVarsToServer() // $_SERVER 128 | ``` 129 | 130 | ### Testing 131 | 132 | Q: Why are there so many static calls? How am I supposed to mock them in tests? 133 | 134 | A: You shouldn't mock `DotEnv` class. Just override what you need using `set` or `load` methods. 135 | Note that `load` method understands arrays too. 136 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "arrilot/dotenv-php", 3 | "license": "MIT", 4 | "keywords": [ 5 | "dotenv", 6 | "production" 7 | ], 8 | "authors": [ 9 | { 10 | "name": "Nekrasov Ilya", 11 | "email": "nekrasov.ilya90@gmail.com" 12 | } 13 | ], 14 | "homepage": "https://github.com/arrilot/dotenv-php", 15 | "require": { 16 | "php": ">=5.4.0" 17 | }, 18 | "require-dev": { 19 | "phpunit/phpunit": "~4.0" 20 | }, 21 | "autoload": { 22 | "psr-4": { 23 | "Arrilot\\DotEnv\\": "src/" 24 | } 25 | }, 26 | "autoload-dev": { 27 | "psr-4": { 28 | "Arrilot\\Tests\\DotEnv\\": "tests/" 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | tests 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/DotEnv.php: -------------------------------------------------------------------------------- 1 | $value) { 53 | if (is_object($value) || is_array($value)) { 54 | $value = serialize($value); 55 | } 56 | 57 | putenv("{$prefix}{$key}={$value}"); 58 | } 59 | } 60 | 61 | /** 62 | * Copy all variables to $_ENV. 63 | */ 64 | public static function copyVarsToEnv() 65 | { 66 | foreach (self::all() as $key => $value) { 67 | $_ENV[$key] = $value; 68 | } 69 | } 70 | 71 | /** 72 | * Copy all variables to $_SERVER. 73 | */ 74 | public static function copyVarsToServer() 75 | { 76 | foreach (self::all() as $key => $value) { 77 | $_SERVER[$key] = $value; 78 | } 79 | } 80 | 81 | /** 82 | * Get env variables. 83 | * 84 | * @return array 85 | */ 86 | public static function all() 87 | { 88 | return self::$variables; 89 | } 90 | 91 | /** 92 | * Get env variable. 93 | * 94 | * @param string $key 95 | * @param mixed $default 96 | * 97 | * @return mixed 98 | */ 99 | public static function get($key, $default = null) 100 | { 101 | return isset(self::$variables[$key]) ? self::$variables[$key] : $default; 102 | } 103 | 104 | /** 105 | * Set env variable. 106 | * 107 | * @param string|array $keys 108 | * @param mixed $value 109 | * 110 | * @return void 111 | */ 112 | public static function set($keys, $value = null) 113 | { 114 | if (is_array($keys)) { 115 | self::$variables = array_merge(self::$variables, $keys); 116 | } else { 117 | self::$variables[$keys] = $value; 118 | } 119 | } 120 | 121 | /** 122 | * Set required variables. 123 | * 124 | * @param array $variables 125 | */ 126 | public static function setRequired(array $variables) 127 | { 128 | self::$required = $variables; 129 | 130 | if (self::$isLoaded) { 131 | self::checkRequiredVariables(); 132 | } 133 | } 134 | 135 | /** 136 | * Delete all variables. 137 | * 138 | * @return void 139 | */ 140 | public static function flush() 141 | { 142 | self::$variables = []; 143 | self::$isLoaded = false; 144 | } 145 | 146 | /** 147 | * Throw exception if any of required variables was not loaded. 148 | * 149 | * @throws MissingVariableException 150 | * 151 | * @return void 152 | */ 153 | protected static function checkRequiredVariables() 154 | { 155 | foreach (self::$required as $key) { 156 | if (!isset(self::$variables[$key])) { 157 | throw new MissingVariableException(".env variable '{$key}' is missing"); 158 | } 159 | } 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /src/Exceptions/MissingVariableException.php: -------------------------------------------------------------------------------- 1 | 'root', 22 | 'DB_PASSWORD' => 'secret', 23 | ]; 24 | 25 | $this->assertSame($expected, DotEnv::all()); 26 | } 27 | 28 | public function test_it_can_load_array() 29 | { 30 | $array = ['DB_USER' => 'root']; 31 | DotEnv::load($array); 32 | 33 | $this->assertSame($array, DotEnv::all()); 34 | } 35 | 36 | public function test_flush_method() 37 | { 38 | DotEnv::load(['DB_USER' => 'root']); 39 | DotEnv::flush(); 40 | 41 | $this->assertSame([], DotEnv::all()); 42 | } 43 | 44 | public function test_get_method() 45 | { 46 | DotEnv::load(['DB_USER' => 'root']); 47 | 48 | $this->assertSame('root', DotEnv::get('DB_USER')); 49 | $this->assertSame('root', DotEnv::get('DB_USER', 'foo')); 50 | $this->assertSame(null, DotEnv::get('DB_PASSWORD')); 51 | $this->assertSame('foo', DotEnv::get('DB_PASSWORD', 'foo')); 52 | } 53 | 54 | public function test_set_method_with_two_args() 55 | { 56 | DotEnv::load(['DB_USER' => 'root']); 57 | 58 | DotEnv::set('DB_PASSWORD', 'secret'); 59 | $this->assertSame('root', DotEnv::get('DB_USER')); 60 | $this->assertSame('secret', DotEnv::get('DB_PASSWORD')); 61 | } 62 | 63 | public function test_set_method_with_array() 64 | { 65 | DotEnv::load(['DB_USER' => 'root']); 66 | 67 | DotEnv::set([ 68 | 'DB_PASSWORD' => 'secret', 69 | 'DB_NAME' => 'test', 70 | ]); 71 | 72 | $this->assertSame('root', DotEnv::get('DB_USER')); 73 | $this->assertSame('secret', DotEnv::get('DB_PASSWORD')); 74 | $this->assertSame('test', DotEnv::get('DB_NAME')); 75 | } 76 | 77 | public function test_it_throws_missing_var_exception() 78 | { 79 | $this->setExpectedException('Arrilot\DotEnv\Exceptions\MissingVariableException'); 80 | 81 | DotEnv::setRequired(['DB_USER', 'DB_PASSWORD']); 82 | DotEnv::load(['DB_USER' => 'root']); 83 | } 84 | 85 | public function test_it_throws_missing_var_exception_even_after_load() 86 | { 87 | $this->setExpectedException('Arrilot\DotEnv\Exceptions\MissingVariableException'); 88 | 89 | DotEnv::load(['DB_USER' => 'root']); 90 | DotEnv::setRequired(['DB_USER', 'DB_PASSWORD']); 91 | } 92 | 93 | public function test_it_does_not_throw_missing_var_exception_if_all_required_vars_are_set() 94 | { 95 | DotEnv::setRequired(['DB_USER', 'DB_PASSWORD']); 96 | DotEnv::load(['DB_USER' => 'root', 'DB_PASSWORD' => 'secret']); 97 | } 98 | 99 | public function test_it_can_copy_vars_to_putenv() 100 | { 101 | DotEnv::load([ 102 | 'TEST_USER' => 'root', 103 | 'TEST_SOME_ARRAY' => ['FOO', 'BAR'] 104 | ]); 105 | DotEnv::copyVarsToPutenv(); 106 | 107 | $this->assertSame('root', getenv('PHP_TEST_USER')); 108 | $this->assertSame(['FOO', 'BAR'], unserialize(getenv('PHP_TEST_SOME_ARRAY'))); 109 | } 110 | 111 | public function test_it_can_copy_vars_to_env() 112 | { 113 | DotEnv::load([ 114 | 'TEST_USER' => 'root', 115 | 'TEST_SOME_ARRAY' => ['FOO', 'BAR'] 116 | ]); 117 | DotEnv::copyVarsToEnv(); 118 | 119 | $this->assertSame('root', $_ENV['TEST_USER']); 120 | $this->assertSame(['FOO', 'BAR'], $_ENV['TEST_SOME_ARRAY']); 121 | unset($_ENV['TEST_USER'], $_ENV['TEST_SOME_ARRAY']); 122 | } 123 | 124 | public function test_it_can_copy_vars_to_server() 125 | { 126 | DotEnv::load([ 127 | 'TEST_USER' => 'root', 128 | 'TEST_SOME_ARRAY' => ['FOO', 'BAR'] 129 | ]); 130 | DotEnv::copyVarsToServer(); 131 | 132 | $this->assertSame('root', $_SERVER['TEST_USER']); 133 | $this->assertSame(['FOO', 'BAR'], $_SERVER['TEST_SOME_ARRAY']); 134 | unset($_SERVER['TEST_USER'], $_SERVER['TEST_SOME_ARRAY']); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /tests/fixtures/test_source.php: -------------------------------------------------------------------------------- 1 | 'root', 5 | 'DB_PASSWORD' => 'secret', 6 | ]; --------------------------------------------------------------------------------