From 770385c2678618b536430014dfca9f11e8ff9e15 Mon Sep 17 00:00:00 2001 From: YoussefMansour9 Date: Thu, 17 Sep 2026 05:58:20 +0300 Subject: [PATCH] Report unterminated double-quoted values instead of dropping them MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the input ended while still inside a double-quoted value, the buffered content was discarded, so the entry and every line after it disappeared with no error: Dotenv::parse('FOO="bar'); // [] Dotenv::parse("A=\"oops\nB=keep"); // [] — B is swallowed too The single-quoted path already reports a missing closing quote for the same mistake, so a stray double quote silently erased configuration instead of failing loudly. `Lines::process()` now emits the still-open buffer once the input ends. The parser then reports the same "missing closing quote" error the single-quoted path produces, and stops swallowing the following lines. Properly closed multiline values are unaffected. Fixes #610 --- src/Parser/Lines.php | 7 +++++++ tests/Dotenv/DotenvTest.php | 25 +++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/Parser/Lines.php b/src/Parser/Lines.php index de290c5a..05d3139c 100644 --- a/src/Parser/Lines.php +++ b/src/Parser/Lines.php @@ -43,6 +43,13 @@ public static function process(array $lines) } } + // The input ended while still within a multiline value. Emit what was + // buffered, so that the parser reports the missing closing quote, + // instead of discarding this entry and every line that followed it. + if ($multiline) { + $output[] = \implode("\n", $multilineBuffer); + } + return $output; } diff --git a/tests/Dotenv/DotenvTest.php b/tests/Dotenv/DotenvTest.php index 99494bc7..2a7f567c 100644 --- a/tests/Dotenv/DotenvTest.php +++ b/tests/Dotenv/DotenvTest.php @@ -6,6 +6,7 @@ use Dotenv\Dotenv; use Dotenv\Exception\InvalidEncodingException; +use Dotenv\Exception\InvalidFileException; use Dotenv\Exception\InvalidPathException; use Dotenv\Loader\Loader; use Dotenv\Parser\Parser; @@ -450,6 +451,30 @@ public function testDotenvParseMultilineContainingHash() ); } + public function testDotenvParseUnterminatedDoubleQuote() + { + $this->expectException(InvalidFileException::class); + $this->expectExceptionMessage('Encountered a missing closing quote at ["bar].'); + + Dotenv::parse('FOO="bar'); + } + + public function testDotenvParseUnterminatedDoubleQuoteDoesNotSwallowLaterLines() + { + $this->expectException(InvalidFileException::class); + $this->expectExceptionMessage('Encountered a missing closing quote at ["oops].'); + + Dotenv::parse("A=\"oops\nB=keep"); + } + + public function testDotenvParseUnterminatedDoubleQuoteMatchesSingleQuote() + { + $this->expectException(InvalidFileException::class); + $this->expectExceptionMessage('Encountered a missing closing quote at [\'bar].'); + + Dotenv::parse("FOO='bar"); + } + public function testDotenvParseEmptyCase() { $output = Dotenv::parse('');