Skip to content

Commit 2a7dcf7

Browse files
Fixed parsing regressions (vlucas#338)
1 parent f3aae28 commit 2a7dcf7

File tree

4 files changed

+76
-23
lines changed

4 files changed

+76
-23
lines changed

src/Parser.php

Lines changed: 61 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,10 @@
77
class Parser
88
{
99
const INITIAL_STATE = 0;
10-
const UNQUOTED_STATE = 1;
11-
const QUOTED_STATE = 2;
12-
const ESCAPE_STATE = 3;
13-
const WHITESPACE_STATE = 4;
14-
const COMMENT_STATE = 5;
10+
const QUOTED_STATE = 1;
11+
const ESCAPE_STATE = 2;
12+
const WHITESPACE_STATE = 3;
13+
const COMMENT_STATE = 4;
1514

1615
/**
1716
* Parse the given variable name.
@@ -29,39 +28,53 @@ public static function parseName($name)
2928
* Parse the given variable value.
3029
*
3130
* @param string $value
32-
*
31+
*
3332
* @throws \Dotenv\Exception\InvalidFileException
3433
*
3534
* @return string
3635
*/
3736
public static function parseValue($value)
37+
{
38+
if ($value === '') {
39+
return '';
40+
} elseif ($value[0] === '"' || $value[0] === '\'') {
41+
return Parser::parseQuotedValue($value);
42+
} else {
43+
return Parser::parseUnquotedValue($value);
44+
}
45+
}
46+
47+
/**
48+
* Parse the given quoted value.
49+
*
50+
* @param string $value
51+
*
52+
* @throws \Dotenv\Exception\InvalidFileException
53+
*
54+
* @return string
55+
*/
56+
public static function parseQuotedValue($value)
3857
{
3958
$data = array_reduce(str_split($value), function ($data, $char) use ($value) {
4059
switch ($data[1]) {
4160
case Parser::INITIAL_STATE:
42-
if ($char === '"') {
61+
if ($char === '"' || $char === '\'') {
4362
return array($data[0], Parser::QUOTED_STATE);
4463
} else {
45-
return array($data[0].$char, Parser::UNQUOTED_STATE);
46-
}
47-
case Parser::UNQUOTED_STATE:
48-
if ($char === '#') {
49-
return array($data[0], Parser::COMMENT_STATE);
50-
} elseif (ctype_space($char)) {
51-
return array($data[0], Parser::WHITESPACE_STATE);
52-
} else {
53-
return array($data[0].$char, Parser::UNQUOTED_STATE);
64+
throw new InvalidFileException(
65+
'Expected the value to start with a quote.'
66+
);
5467
}
5568
case Parser::QUOTED_STATE:
56-
if ($char === '"') {
69+
if ($char === $value[0]) {
5770
return array($data[0], Parser::WHITESPACE_STATE);
5871
} elseif ($char === '\\') {
5972
return array($data[0], Parser::ESCAPE_STATE);
6073
} else {
6174
return array($data[0].$char, Parser::QUOTED_STATE);
6275
}
6376
case Parser::ESCAPE_STATE:
64-
if ($char === '"' || $char === '\\') {
77+
if ($char === $value[0] || $char === '\\') {
6578
return array($data[0].$char, Parser::QUOTED_STATE);
6679
} else {
6780
return array($data[0].'\\'.$char, Parser::QUOTED_STATE);
@@ -70,11 +83,9 @@ public static function parseValue($value)
7083
if ($char === '#') {
7184
return array($data[0], Parser::COMMENT_STATE);
7285
} elseif (!ctype_space($char)) {
73-
if ($data[0] !== '' && $data[0][0] === '#') {
74-
return array('', Parser::COMMENT_STATE);
75-
} else {
76-
throw new InvalidFileException('Dotenv values containing spaces must be surrounded by quotes.');
77-
}
86+
throw new InvalidFileException(
87+
'Dotenv values containing spaces must be surrounded by quotes.'
88+
);
7889
} else {
7990
return array($data[0], Parser::WHITESPACE_STATE);
8091
}
@@ -85,4 +96,31 @@ public static function parseValue($value)
8596

8697
return trim($data[0]);
8798
}
99+
100+
/**
101+
* Parse the given unquoted value.
102+
*
103+
* @param string $value
104+
*
105+
* @throws \Dotenv\Exception\InvalidFileException
106+
*
107+
* @return string
108+
*/
109+
public static function parseUnquotedValue($value)
110+
{
111+
$parts = explode(' #', $value, 2);
112+
$value = trim($parts[0]);
113+
114+
// Unquoted values cannot contain whitespace
115+
if (preg_match('/\s+/', $value) > 0) {
116+
// Check if value is a comment (usually triggered when empty value with comment)
117+
if (preg_match('/^#/', $value) > 0) {
118+
$value = '';
119+
} else {
120+
throw new InvalidFileException('Dotenv values containing spaces must be surrounded by quotes.');
121+
}
122+
}
123+
124+
return trim($value);
125+
}
88126
}

tests/Dotenv/DotenvTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,14 @@ public function testQuotedDotenvLoadsEnvironmentVars()
6464
$this->assertSame('with spaces', getenv('QSPACED'));
6565
$this->assertEmpty(getenv('QNULL'));
6666
$this->assertSame('pgsql:host=localhost;dbname=test', getenv('QEQUALS'));
67+
6768
$this->assertSame('test some escaped characters like a quote (") or maybe a backslash (\\)', getenv('QESCAPED'));
6869
$this->assertSame('iiiiviiiixiiiiviiii\\n', getenv('QSLASH1'));
6970
$this->assertSame('iiiiviiiixiiiiviiii\\n', getenv('QSLASH2'));
71+
72+
$this->assertSame('test some escaped characters like a quote (\') or maybe a backslash (\\)', getenv('SQESCAPED'));
73+
$this->assertSame('iiiiviiiixiiiiviiii\\n', getenv('SQSLASH1'));
74+
$this->assertSame('iiiiviiiixiiiiviiii\\n', getenv('SQSLASH2'));
7075
}
7176

7277
public function testLargeDotenvLoadsEnvironmentVars()
@@ -261,6 +266,9 @@ public function testDotenvAllowsSpecialCharacters()
261266
$this->assertSame('jdgEB4{QgEC]HL))&GcXxokB+wqoN+j>xkV7K?m$r', getenv('SPVAR3'));
262267
$this->assertSame('22222:22#2^{', getenv('SPVAR4'));
263268
$this->assertSame('test some escaped characters like a quote " or maybe a backslash \\', getenv('SPVAR5'));
269+
$this->assertSame('secret!@#', getenv('SPVAR6'));
270+
$this->assertSame('secret!@#', getenv('SPVAR7'));
271+
$this->assertSame('secret!@#', getenv('SPVAR8'));
264272
}
265273

266274
public function testDotenvAssertions()

tests/fixtures/env/quoted.env

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,7 @@ QWHITESPACE = "no space"
99
QESCAPED="test some escaped characters like a quote (\") or maybe a backslash (\\)"
1010
QSLASH1="iiiiviiiixiiiiviiii\n"
1111
QSLASH2="iiiiviiiixiiiiviiii\\n"
12+
13+
SQESCAPED='test some escaped characters like a quote (\') or maybe a backslash (\\)'
14+
SQSLASH1='iiiiviiiixiiiiviiii\n'
15+
SQSLASH2='iiiiviiiixiiiiviiii\\n'

tests/fixtures/env/specialchars.env

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,6 @@ SPVAR2="?BUty3koaV3%GA*hMAwH}B"
33
SPVAR3="jdgEB4{QgEC]HL))&GcXxokB+wqoN+j>xkV7K?m$r"
44
SPVAR4="22222:22#2^{"
55
SPVAR5="test some escaped characters like a quote \" or maybe a backslash \\" # not escaped
6+
SPVAR6=secret!@#
7+
SPVAR7='secret!@#'
8+
SPVAR8="secret!@#"

0 commit comments

Comments
 (0)