properly parse backslashes in unquoted env vars
This commit is contained in:
parent
b6f9f8d769
commit
785fff56ce
@ -224,10 +224,11 @@ final class Dotenv
|
||||
throw $this->createFormatException('Missing quote to end the value');
|
||||
}
|
||||
++$this->cursor;
|
||||
$value = str_replace(array('\\\\', '\\"', '\r', '\n'), array('\\', '"', "\r", "\n"), $value);
|
||||
$value = str_replace(array('\\"', '\r', '\n'), array('"', "\r", "\n"), $value);
|
||||
$resolvedValue = $value;
|
||||
$resolvedValue = $this->resolveVariables($resolvedValue);
|
||||
$resolvedValue = $this->resolveCommands($resolvedValue);
|
||||
$resolvedValue = str_replace('\\\\', '\\', $resolvedValue);
|
||||
$v .= $resolvedValue;
|
||||
} else {
|
||||
$value = '';
|
||||
@ -250,6 +251,7 @@ final class Dotenv
|
||||
$resolvedValue = $value;
|
||||
$resolvedValue = $this->resolveVariables($resolvedValue);
|
||||
$resolvedValue = $this->resolveCommands($resolvedValue);
|
||||
$resolvedValue = str_replace('\\\\', '\\', $resolvedValue);
|
||||
|
||||
if ($resolvedValue === $value && preg_match('/\s+/', $value)) {
|
||||
throw $this->createFormatException('A value containing spaces must be surrounded by quotes');
|
||||
@ -350,24 +352,31 @@ final class Dotenv
|
||||
}
|
||||
|
||||
$regex = '/
|
||||
(\\\\)? # escaped with a backslash?
|
||||
(?<!\\\\)
|
||||
(?P<backslashes>\\\\*) # escaped with a backslash?
|
||||
\$
|
||||
(?!\() # no opening parenthesis
|
||||
(\{)? # optional brace
|
||||
('.self::VARNAME_REGEX.') # var name
|
||||
(\})? # optional closing brace
|
||||
(?!\() # no opening parenthesis
|
||||
(?P<opening_brace>\{)? # optional brace
|
||||
(?P<name>'.self::VARNAME_REGEX.')? # var name
|
||||
(?P<closing_brace>\})? # optional closing brace
|
||||
/x';
|
||||
|
||||
$value = preg_replace_callback($regex, function ($matches) {
|
||||
if ('\\' === $matches[1]) {
|
||||
// odd number of backslashes means the $ character is escaped
|
||||
if (1 === \strlen($matches['backslashes']) % 2) {
|
||||
return substr($matches[0], 1);
|
||||
}
|
||||
|
||||
if ('{' === $matches[2] && !isset($matches[4])) {
|
||||
// unescaped $ not followed by variable name
|
||||
if (!isset($matches['name'])) {
|
||||
return $matches[0];
|
||||
}
|
||||
|
||||
if ('{' === $matches['opening_brace'] && !isset($matches['closing_brace'])) {
|
||||
throw $this->createFormatException('Unclosed braces on variable expansion');
|
||||
}
|
||||
|
||||
$name = $matches[3];
|
||||
$name = $matches['name'];
|
||||
if (isset($this->values[$name])) {
|
||||
$value = $this->values[$name];
|
||||
} elseif (isset($_SERVER[$name]) && 0 !== strpos($name, 'HTTP_')) {
|
||||
@ -378,15 +387,14 @@ final class Dotenv
|
||||
$value = (string) getenv($name);
|
||||
}
|
||||
|
||||
if (!$matches[2] && isset($matches[4])) {
|
||||
if (!$matches['opening_brace'] && isset($matches['closing_brace'])) {
|
||||
$value .= '}';
|
||||
}
|
||||
|
||||
return $value;
|
||||
return $matches['backslashes'].$value;
|
||||
}, $value);
|
||||
|
||||
// unescape $
|
||||
return str_replace('\\$', '$', $value);
|
||||
return $value;
|
||||
}
|
||||
|
||||
private function moveCursor($text)
|
||||
|
@ -66,6 +66,20 @@ class DotenvTest extends TestCase
|
||||
$_ENV['REMOTE'] = 'remote';
|
||||
|
||||
$tests = array(
|
||||
// backslashes
|
||||
array('FOO=foo\\\\bar', array('FOO' => 'foo\\bar')),
|
||||
array("FOO='foo\\\\bar'", array('FOO' => 'foo\\\\bar')),
|
||||
array('FOO="foo\\\\bar"', array('FOO' => 'foo\\bar')),
|
||||
|
||||
// escaped backslash in front of variable
|
||||
array("BAR=bar\nFOO=foo\\\\\$BAR", array('BAR' => 'bar', 'FOO' => 'foo\\bar')),
|
||||
array("BAR=bar\nFOO='foo\\\\\$BAR'", array('BAR' => 'bar', 'FOO' => 'foo\\\\$BAR')),
|
||||
array("BAR=bar\nFOO=\"foo\\\\\$BAR\"", array('BAR' => 'bar', 'FOO' => 'foo\\bar')),
|
||||
|
||||
array('FOO=foo\\\\\\$BAR', array('FOO' => 'foo\\$BAR')),
|
||||
array('FOO=\'foo\\\\\\$BAR\'', array('FOO' => 'foo\\\\\\$BAR')),
|
||||
array('FOO="foo\\\\\\$BAR"', array('FOO' => 'foo\\$BAR')),
|
||||
|
||||
// spaces
|
||||
array('FOO=bar', array('FOO' => 'bar')),
|
||||
array(' FOO=bar ', array('FOO' => 'bar')),
|
||||
|
Reference in New Issue
Block a user