77class 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}
0 commit comments