Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 551a80e

Browse files
Amoifrnicolas-grekas
authored andcommitted
[Dotenv] Fix self-referencing variable resolution with suffix/prefix
1 parent cae019c commit 551a80e

2 files changed

Lines changed: 77 additions & 4 deletions

File tree

Dotenv.php

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ final class Dotenv
3636
private string $data;
3737
private int $end;
3838
private array $values = [];
39+
private array $overriddenValues = [];
3940
private string $envKey;
4041
private string $debugKey;
4142
private array $prodEnvs = ['prod'];
@@ -644,7 +645,15 @@ private function doLoad(bool $overrideExistingVars, array $paths): void
644645
throw new FormatException('Loading files containing NUL bytes is not supported.', new FormatExceptionContext($data, $path, 1, 0));
645646
}
646647

647-
$this->populate($this->parseRaw($data, $path), $overrideExistingVars);
648+
$values = $this->parseRaw($data, $path);
649+
650+
foreach ($values as $name => $_) {
651+
if (!isset($this->overriddenValues[$name]) && isset($_ENV[$name])) {
652+
$this->overriddenValues[$name] = $_ENV[$name];
653+
}
654+
}
655+
656+
$this->populate($values, $overrideExistingVars);
648657
}
649658
}
650659

@@ -731,10 +740,19 @@ private function resolveLoadedVars(): void
731740
if (isset($selfReferencingVars[$name])) {
732741
$envBackup = $_ENV[$name] ?? null;
733742
$serverBackup = $_SERVER[$name] ?? null;
734-
unset($_ENV[$name], $_SERVER[$name]);
743+
if (isset($this->overriddenValues[$name])) {
744+
$_ENV[$name] = $this->overriddenValues[$name];
745+
$_SERVER[$name] = $this->overriddenValues[$name];
746+
} else {
747+
unset($_ENV[$name], $_SERVER[$name]);
748+
}
735749
if ($this->usePutenv) {
736-
$getenvBackup = $this->usePutenv ? (string) getenv($name) : null;
737-
putenv($name);
750+
$getenvBackup = (string) getenv($name);
751+
if (isset($this->overriddenValues[$name])) {
752+
putenv("$name={$this->overriddenValues[$name]}");
753+
} else {
754+
putenv($name);
755+
}
738756
}
739757
}
740758

@@ -782,6 +800,7 @@ private function resolveLoadedVars(): void
782800
}
783801

784802
$this->values = [];
803+
$this->overriddenValues = [];
785804
unset($this->path, $this->data, $this->lineno, $this->cursor, $this->end);
786805
}
787806
}

Tests/DotenvTest.php

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,60 @@ public function testLoadEnvSelfReferencingVariableWithDefault()
589589
@rmdir($tmpdir);
590590
}
591591

592+
public function testLoadSelfReferencingVariableWithSuffix()
593+
{
594+
$resetContext = static function (): void {
595+
unset($_ENV['SYMFONY_DOTENV_VARS'], $_ENV['MY_VAR']);
596+
unset($_SERVER['SYMFONY_DOTENV_VARS'], $_SERVER['MY_VAR']);
597+
putenv('SYMFONY_DOTENV_VARS');
598+
putenv('MY_VAR');
599+
};
600+
601+
@mkdir($tmpdir = sys_get_temp_dir().'/dotenv');
602+
$basePath = tempnam($tmpdir, 'sf-');
603+
$overridePath = tempnam($tmpdir, 'sf-');
604+
605+
// Base file sets original value, override file appends suffix
606+
file_put_contents($basePath, 'MY_VAR=original');
607+
file_put_contents($overridePath, 'MY_VAR="${MY_VAR}_suffix"');
608+
609+
$resetContext();
610+
$dotenv = (new Dotenv())->usePutenv();
611+
$dotenv->load($basePath);
612+
$dotenv->load($overridePath);
613+
614+
$this->assertSame('original_suffix', getenv('MY_VAR'));
615+
616+
// Test with prefix instead of suffix
617+
file_put_contents($overridePath, 'MY_VAR="prefix_${MY_VAR}"');
618+
619+
$resetContext();
620+
$dotenv = (new Dotenv())->usePutenv();
621+
$dotenv->load($basePath);
622+
$dotenv->load($overridePath);
623+
624+
$this->assertSame('prefix_original', getenv('MY_VAR'));
625+
626+
// Test chained loads (three files)
627+
$thirdPath = tempnam($tmpdir, 'sf-');
628+
file_put_contents($overridePath, 'MY_VAR="${MY_VAR}_middle"');
629+
file_put_contents($thirdPath, 'MY_VAR="${MY_VAR}_end"');
630+
631+
$resetContext();
632+
$dotenv = (new Dotenv())->usePutenv();
633+
$dotenv->load($basePath);
634+
$dotenv->load($overridePath);
635+
$dotenv->load($thirdPath);
636+
637+
$this->assertSame('original_middle_end', getenv('MY_VAR'));
638+
639+
$resetContext();
640+
unlink($basePath);
641+
unlink($overridePath);
642+
unlink($thirdPath);
643+
@rmdir($tmpdir);
644+
}
645+
592646
public function testLoadEnvSelfReferencingEnvKeyControlsFileLoading()
593647
{
594648
$resetContext = static function (): void {

0 commit comments

Comments
 (0)