diff --git a/UPGRADE-4.3.md b/UPGRADE-4.3.md index 873dc682569b1..85358cfbf66b4 100644 --- a/UPGRADE-4.3.md +++ b/UPGRADE-4.3.md @@ -45,6 +45,12 @@ Doctrine Bridge * Passing an `IdReader` to the `DoctrineChoiceLoader` when the query cannot be optimized with single id field has been deprecated, pass `null` instead * Not passing an `IdReader` to the `DoctrineChoiceLoader` when the query can be optimized with single id field has been deprecated +Dotenv +------ + + * First parameter of `Dontenv::__construct()` will change from `true` to `false` in Symfony 5.0. A deprecation warning + will be triggered if no parameter is used. Use `$usePutenv=true` to upgrade without breaking changes. + EventDispatcher --------------- diff --git a/src/Symfony/Component/Dotenv/CHANGELOG.md b/src/Symfony/Component/Dotenv/CHANGELOG.md index 3d3546f76c63d..296f029e7a9ac 100644 --- a/src/Symfony/Component/Dotenv/CHANGELOG.md +++ b/src/Symfony/Component/Dotenv/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +4.3.0 +----- + + * deprecated use of `putenv()` but default. This feature will be opted-in with a constructor argument to `Dotenv`. + 4.2.0 ----- diff --git a/src/Symfony/Component/Dotenv/Dotenv.php b/src/Symfony/Component/Dotenv/Dotenv.php index 697e09ec0b443..e980544f73c1b 100644 --- a/src/Symfony/Component/Dotenv/Dotenv.php +++ b/src/Symfony/Component/Dotenv/Dotenv.php @@ -35,6 +35,21 @@ final class Dotenv private $data; private $end; private $values; + private $usePutenv = true; + + /** + * @var bool If we should use `putenv()` to define environment variables + * or not. Since Symfony 5.0 the default value is false + * because `putenv()` is not thread safe. + */ + public function __construct(bool $usePutenv = true) + { + if (0 === \func_num_args()) { + @trigger_error(sprintf('The default value of "$usePutenv" argument of "%s\'s constructor will change from "true" to "false" in Symfony 5.0, you should define its value explicitly.', __METHOD__), E_USER_DEPRECATED); + } + + $this->usePutenv = $usePutenv; + } /** * Loads one or several .env files. @@ -126,7 +141,10 @@ public function populate(array $values, bool $overrideExistingVars = false): voi continue; } - putenv("$name=$value"); + if ($this->usePutenv) { + putenv("$name=$value"); + } + $_ENV[$name] = $value; if ($notHttpName) { $_SERVER[$name] = $value; @@ -140,7 +158,11 @@ public function populate(array $values, bool $overrideExistingVars = false): voi if ($updateLoadedVars) { unset($loadedVars['']); $loadedVars = implode(',', array_keys($loadedVars)); - putenv('SYMFONY_DOTENV_VARS='.$_ENV['SYMFONY_DOTENV_VARS'] = $_SERVER['SYMFONY_DOTENV_VARS'] = $loadedVars); + $_ENV['SYMFONY_DOTENV_VARS'] = $_SERVER['SYMFONY_DOTENV_VARS'] = $loadedVars; + + if ($this->usePutenv) { + putenv('SYMFONY_DOTENV_VARS='.$loadedVars); + } } } diff --git a/src/Symfony/Component/Dotenv/README.md b/src/Symfony/Component/Dotenv/README.md index 244ed7700a14e..38dde84bc4d95 100644 --- a/src/Symfony/Component/Dotenv/README.md +++ b/src/Symfony/Component/Dotenv/README.md @@ -2,7 +2,7 @@ Dotenv Component ================ Symfony Dotenv parses `.env` files to make environment variables stored in them -accessible via `getenv()`, `$_ENV`, or `$_SERVER`. +accessible via `$_ENV`, `$_SERVER` and optionally `getenv()`. Resources --------- diff --git a/src/Symfony/Component/Dotenv/Tests/DotenvTest.php b/src/Symfony/Component/Dotenv/Tests/DotenvTest.php index 36c0af252094a..8d308c415925c 100644 --- a/src/Symfony/Component/Dotenv/Tests/DotenvTest.php +++ b/src/Symfony/Component/Dotenv/Tests/DotenvTest.php @@ -22,7 +22,7 @@ class DotenvTest extends TestCase */ public function testParseWithFormatError($data, $error) { - $dotenv = new Dotenv(); + $dotenv = new Dotenv(true); try { $dotenv->parse($data); @@ -62,7 +62,7 @@ public function getEnvDataWithFormatErrors() */ public function testParse($data, $expected) { - $dotenv = new Dotenv(); + $dotenv = new Dotenv(true); $this->assertSame($expected, $dotenv->parse($data)); } @@ -193,7 +193,7 @@ public function testLoad() file_put_contents($path1, 'FOO=BAR'); file_put_contents($path2, 'BAR=BAZ'); - (new Dotenv())->load($path1, $path2); + (new Dotenv(true))->load($path1, $path2); $foo = getenv('FOO'); $bar = getenv('BAR'); @@ -224,7 +224,7 @@ public function testLoadEnv() // .env file_put_contents($path, 'FOO=BAR'); - (new DotEnv())->loadEnv($path, 'TEST_APP_ENV'); + (new Dotenv(true))->loadEnv($path, 'TEST_APP_ENV'); $this->assertSame('BAR', getenv('FOO')); $this->assertSame('dev', getenv('TEST_APP_ENV')); @@ -232,33 +232,33 @@ public function testLoadEnv() $_SERVER['TEST_APP_ENV'] = 'local'; file_put_contents("$path.local", 'FOO=localBAR'); - (new DotEnv())->loadEnv($path, 'TEST_APP_ENV'); + (new Dotenv(true))->loadEnv($path, 'TEST_APP_ENV'); $this->assertSame('localBAR', getenv('FOO')); // special case for test $_SERVER['TEST_APP_ENV'] = 'test'; - (new DotEnv())->loadEnv($path, 'TEST_APP_ENV'); + (new Dotenv(true))->loadEnv($path, 'TEST_APP_ENV'); $this->assertSame('BAR', getenv('FOO')); // .env.dev unset($_SERVER['TEST_APP_ENV']); file_put_contents("$path.dev", 'FOO=devBAR'); - (new DotEnv())->loadEnv($path, 'TEST_APP_ENV'); + (new Dotenv(true))->loadEnv($path, 'TEST_APP_ENV'); $this->assertSame('devBAR', getenv('FOO')); // .env.dev.local file_put_contents("$path.dev.local", 'FOO=devlocalBAR'); - (new DotEnv())->loadEnv($path, 'TEST_APP_ENV'); + (new Dotenv(true))->loadEnv($path, 'TEST_APP_ENV'); $this->assertSame('devlocalBAR', getenv('FOO')); // .env.dist unlink($path); file_put_contents("$path.dist", 'BAR=distBAR'); - (new DotEnv())->loadEnv($path, 'TEST_APP_ENV'); + (new Dotenv(true))->loadEnv($path, 'TEST_APP_ENV'); $this->assertSame('distBAR', getenv('BAR')); putenv('FOO'); @@ -290,7 +290,7 @@ public function testOverload() file_put_contents($path1, 'FOO=BAR'); file_put_contents($path2, 'BAR=BAZ'); - (new Dotenv())->overload($path1, $path2); + (new Dotenv(true))->overload($path1, $path2); $foo = getenv('FOO'); $bar = getenv('BAR'); @@ -310,7 +310,7 @@ public function testOverload() */ public function testLoadDirectory() { - $dotenv = new Dotenv(); + $dotenv = new Dotenv(true); $dotenv->load(__DIR__); } @@ -318,7 +318,7 @@ public function testServerSuperglobalIsNotOverriden() { $originalValue = $_SERVER['argc']; - $dotenv = new Dotenv(); + $dotenv = new Dotenv(true); $dotenv->populate(['argc' => 'new_value']); $this->assertSame($originalValue, $_SERVER['argc']); @@ -329,7 +329,7 @@ public function testEnvVarIsNotOverriden() putenv('TEST_ENV_VAR=original_value'); $_SERVER['TEST_ENV_VAR'] = 'original_value'; - $dotenv = new Dotenv(); + $dotenv = new Dotenv(true); $dotenv->populate(['TEST_ENV_VAR' => 'new_value']); $this->assertSame('original_value', getenv('TEST_ENV_VAR')); @@ -339,7 +339,7 @@ public function testHttpVarIsPartiallyOverriden() { $_SERVER['HTTP_TEST_ENV_VAR'] = 'http_value'; - $dotenv = new Dotenv(); + $dotenv = new Dotenv(true); $dotenv->populate(['HTTP_TEST_ENV_VAR' => 'env_value']); $this->assertSame('env_value', getenv('HTTP_TEST_ENV_VAR')); @@ -351,7 +351,7 @@ public function testEnvVarIsOverriden() { putenv('TEST_ENV_VAR_OVERRIDEN=original_value'); - $dotenv = new Dotenv(); + $dotenv = new Dotenv(true); $dotenv->populate(['TEST_ENV_VAR_OVERRIDEN' => 'new_value'], true); $this->assertSame('new_value', getenv('TEST_ENV_VAR_OVERRIDEN')); @@ -373,7 +373,7 @@ public function testMemorizingLoadedVarsNamesInSpecialVar() unset($_SERVER['DATABASE_URL']); putenv('DATABASE_URL'); - $dotenv = new Dotenv(); + $dotenv = new Dotenv(true); $dotenv->populate(['APP_DEBUG' => '1', 'DATABASE_URL' => 'mysql://root@localhost/db']); $this->assertSame('APP_DEBUG,DATABASE_URL', getenv('SYMFONY_DOTENV_VARS')); @@ -390,7 +390,7 @@ public function testMemorizingLoadedVarsNamesInSpecialVar() unset($_SERVER['DATABASE_URL']); putenv('DATABASE_URL'); - $dotenv = new Dotenv(); + $dotenv = new Dotenv(true); $dotenv->populate(['APP_DEBUG' => '0', 'DATABASE_URL' => 'mysql://root@localhost/db']); $dotenv->populate(['DATABASE_URL' => 'sqlite:///somedb.sqlite']); @@ -406,7 +406,7 @@ public function testOverridingEnvVarsWithNamesMemorizedInSpecialVar() putenv('BAZ=baz'); putenv('DOCUMENT_ROOT=/var/www'); - $dotenv = new Dotenv(); + $dotenv = new Dotenv(true); $dotenv->populate(['FOO' => 'foo1', 'BAR' => 'bar1', 'BAZ' => 'baz1', 'DOCUMENT_ROOT' => '/boot']); $this->assertSame('foo1', getenv('FOO')); @@ -414,4 +414,21 @@ public function testOverridingEnvVarsWithNamesMemorizedInSpecialVar() $this->assertSame('baz1', getenv('BAZ')); $this->assertSame('/var/www', getenv('DOCUMENT_ROOT')); } + + /** + * @group legacy + * @expectedDeprecation The default value of "$usePutenv" argument of "%s's constructor will change from "true" to "false" in Symfony 5.0, you should define its value explicitly. + */ + public function testDeprecationWarning() + { + new Dotenv(); + } + + public function testNoDeprecationWarning() + { + $dotenv = new Dotenv(true); + $this->assertInstanceOf(Dotenv::class, $dotenv); + $dotenv = new Dotenv(false); + $this->assertInstanceOf(Dotenv::class, $dotenv); + } }
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: