diff --git a/CHANGELOG-6.4.md b/CHANGELOG-6.4.md index 56efbaa4a9bbf..8a69b0c80ff17 100644 --- a/CHANGELOG-6.4.md +++ b/CHANGELOG-6.4.md @@ -1,3 +1,4 @@ + CHANGELOG for 6.4.x =================== @@ -9,6 +10,7 @@ To get the diff between two versions, go to https://github.com/symfony/symfony/c * 6.4.11 (2024-08-30) + * bug #58214 [Dotenv] Fix can not load BOM-signed env files (hosni) * bug #58110 [PropertyAccess] Fix handling property names with a `.` (alexandre-daubois) * bug #58127 [Validator] synchronize IBAN formats (xabbuh) * bug #58112 fix Twig 3.12 compatibility (xabbuh) diff --git a/src/Symfony/Component/Dotenv/Dotenv.php b/src/Symfony/Component/Dotenv/Dotenv.php index 297310309a362..e527aff615f39 100644 --- a/src/Symfony/Component/Dotenv/Dotenv.php +++ b/src/Symfony/Component/Dotenv/Dotenv.php @@ -228,7 +228,7 @@ public function populate(array $values, bool $overrideExistingVars = false): voi public function parse(string $data, string $path = '.env'): array { $this->path = $path; - $this->data = str_replace(["\r\n", "\r"], "\n", $data); + $this->data = $this->normalizeString($data); $this->lineno = 1; $this->cursor = 0; $this->end = \strlen($this->data); @@ -264,6 +264,25 @@ public function parse(string $data, string $path = '.env'): array } } + private function normalizeString(string $data): string + { + /** + * Remove BOM charachters from first of the string + * The order of the if statements is important due to the varying lengths of BOM characters (4, 3, or 2 bytes). + * @see https://github.com/symfony/symfony/issues/58214 + * @see https://en.wikipedia.org/wiki/Byte_order_mark + */ + if (\substr($data, 0, 4) == "\x00\x00\xFE\xFF" || \substr($data, 0, 4) == "\xFF\xFE\x00\x00") { // UTF-32 (big-endian|little-endian) + $data = \substr($data, 4); + } elseif (\substr($data, 0, 3) == "\xEF\xBB\xBF") { // UTF-8 + $data = \substr($data, 3); + } elseif (\substr($data, 0, 2) == "\xFE\xFF" || \substr($data, 0, 2) == "\xFF\xFE") { // UTF-16 (big-endian|little-endian) + $data = \substr($data, 2); + } + + return str_replace(["\r\n", "\r"], "\n", $data); + } + private function lexVarname(): string { // var name + optional export diff --git a/src/Symfony/Component/Dotenv/Tests/DotenvTest.php b/src/Symfony/Component/Dotenv/Tests/DotenvTest.php index 644126d6b2ba1..d6de30274ed3e 100644 --- a/src/Symfony/Component/Dotenv/Tests/DotenvTest.php +++ b/src/Symfony/Component/Dotenv/Tests/DotenvTest.php @@ -180,6 +180,13 @@ public static function getEnvData() // underscores ['_FOO=BAR', ['_FOO' => 'BAR']], ['_FOO_BAR=FOOBAR', ['_FOO_BAR' => 'FOOBAR']], + + // BOM charachters + ["\xEF\xBB\xBFFOO=BAR", ['FOO' => 'BAR']], // UTF-8 + ["\xFE\xFFFOO=BAR", ['FOO' => 'BAR']], // UTF-16 (big-endian) + ["\xFF\xFEFOO=BAR", ['FOO' => 'BAR']], // UTF-16 (little-endian) + ["\x00\x00\xFE\xFFFOO=BAR", ['FOO' => 'BAR']], // UTF-32 (big-endian) + ["\xFF\xFE\x00\x00FOO=BAR", ['FOO' => 'BAR']], // UTF-32 (little-endian) ]; if ('\\' !== \DIRECTORY_SEPARATOR) {