%PDF- %PDF-
Direktori : /home/emtnaeewxm/www/vendor/symfony/symfony/src/Symfony/Component/Dotenv/ |
Current File : /home/emtnaeewxm/www/vendor/symfony/symfony/src/Symfony/Component/Dotenv/Dotenv.php |
<?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Dotenv; use Symfony\Component\Dotenv\Exception\FormatException; use Symfony\Component\Dotenv\Exception\FormatExceptionContext; use Symfony\Component\Dotenv\Exception\PathException; use Symfony\Component\Process\Exception\ExceptionInterface as ProcessException; use Symfony\Component\Process\Process; /** * Manages .env files. * * @author Fabien Potencier <fabien@symfony.com> */ final class Dotenv { const VARNAME_REGEX = '(?i:[A-Z][A-Z0-9_]*+)'; const STATE_VARNAME = 0; const STATE_VALUE = 1; private $path; private $cursor; private $lineno; private $data; private $end; private $values; /** * Loads one or several .env files. * * @param string $path A file to load * * @throws FormatException when a file has a syntax error * @throws PathException when a file does not exist or is not readable */ public function load($path/*, ...$paths*/) { // func_get_args() to be replaced by a variadic argument for Symfony 4.0 foreach (\func_get_args() as $path) { if (!is_readable($path) || is_dir($path)) { throw new PathException($path); } $this->populate($this->parse(file_get_contents($path), $path)); } } /** * Sets values as environment variables (via putenv, $_ENV, and $_SERVER). * * Note that existing environment variables are not overridden. * * @param array $values An array of env variables */ public function populate($values) { $updateLoadedVars = false; $loadedVars = array_flip(explode(',', isset($_SERVER['SYMFONY_DOTENV_VARS']) ? $_SERVER['SYMFONY_DOTENV_VARS'] : (isset($_ENV['SYMFONY_DOTENV_VARS']) ? $_ENV['SYMFONY_DOTENV_VARS'] : ''))); foreach ($values as $name => $value) { $notHttpName = 0 !== strpos($name, 'HTTP_'); // don't check existence with getenv() because of thread safety issues if (!isset($loadedVars[$name]) && (isset($_ENV[$name]) || (isset($_SERVER[$name]) && $notHttpName))) { continue; } putenv("$name=$value"); $_ENV[$name] = $value; if ($notHttpName) { $_SERVER[$name] = $value; } if (!isset($loadedVars[$name])) { $loadedVars[$name] = $updateLoadedVars = true; } } if ($updateLoadedVars) { unset($loadedVars['']); $loadedVars = implode(',', array_keys($loadedVars)); putenv('SYMFONY_DOTENV_VARS='.$_ENV['SYMFONY_DOTENV_VARS'] = $_SERVER['SYMFONY_DOTENV_VARS'] = $loadedVars); } } /** * Parses the contents of an .env file. * * @param string $data The data to be parsed * @param string $path The original file name where data where stored (used for more meaningful error messages) * * @return array An array of env variables * * @throws FormatException when a file has a syntax error */ public function parse($data, $path = '.env') { $this->path = $path; $this->data = str_replace(["\r\n", "\r"], "\n", $data); $this->lineno = 1; $this->cursor = 0; $this->end = \strlen($this->data); $state = self::STATE_VARNAME; $this->values = []; $name = ''; $this->skipEmptyLines(); while ($this->cursor < $this->end) { switch ($state) { case self::STATE_VARNAME: $name = $this->lexVarname(); $state = self::STATE_VALUE; break; case self::STATE_VALUE: $this->values[$name] = $this->lexValue(); $state = self::STATE_VARNAME; break; } } if (self::STATE_VALUE === $state) { $this->values[$name] = ''; } try { return $this->values; } finally { $this->values = []; $this->data = null; $this->path = null; } } private function lexVarname() { // var name + optional export if (!preg_match('/(export[ \t]++)?('.self::VARNAME_REGEX.')/A', $this->data, $matches, 0, $this->cursor)) { throw $this->createFormatException('Invalid character in variable name'); } $this->moveCursor($matches[0]); if ($this->cursor === $this->end || "\n" === $this->data[$this->cursor] || '#' === $this->data[$this->cursor]) { if ($matches[1]) { throw $this->createFormatException('Unable to unset an environment variable'); } throw $this->createFormatException('Missing = in the environment variable declaration'); } if (' ' === $this->data[$this->cursor] || "\t" === $this->data[$this->cursor]) { throw $this->createFormatException('Whitespace characters are not supported after the variable name'); } if ('=' !== $this->data[$this->cursor]) { throw $this->createFormatException('Missing = in the environment variable declaration'); } ++$this->cursor; return $matches[2]; } private function lexValue() { if (preg_match('/[ \t]*+(?:#.*)?$/Am', $this->data, $matches, 0, $this->cursor)) { $this->moveCursor($matches[0]); $this->skipEmptyLines(); return ''; } if (' ' === $this->data[$this->cursor] || "\t" === $this->data[$this->cursor]) { throw $this->createFormatException('Whitespace are not supported before the value'); } $loadedVars = array_flip(explode(',', isset($_SERVER['SYMFONY_DOTENV_VARS']) ? $_SERVER['SYMFONY_DOTENV_VARS'] : (isset($_ENV['SYMFONY_DOTENV_VARS']) ? $_ENV['SYMFONY_DOTENV_VARS'] : ''))); unset($loadedVars['']); $v = ''; do { if ("'" === $this->data[$this->cursor]) { $len = 0; do { if ($this->cursor + ++$len === $this->end) { $this->cursor += $len; throw $this->createFormatException('Missing quote to end the value'); } } while ("'" !== $this->data[$this->cursor + $len]); $v .= substr($this->data, 1 + $this->cursor, $len - 1); $this->cursor += 1 + $len; } elseif ('"' === $this->data[$this->cursor]) { $value = ''; if (++$this->cursor === $this->end) { throw $this->createFormatException('Missing quote to end the value'); } while ('"' !== $this->data[$this->cursor] || ('\\' === $this->data[$this->cursor - 1] && '\\' !== $this->data[$this->cursor - 2])) { $value .= $this->data[$this->cursor]; ++$this->cursor; if ($this->cursor === $this->end) { throw $this->createFormatException('Missing quote to end the value'); } } if ("\n" === $this->data[$this->cursor]) { throw $this->createFormatException('Missing quote to end the value'); } ++$this->cursor; $value = str_replace(['\\"', '\r', '\n'], ['"', "\r", "\n"], $value); $resolvedValue = $value; $resolvedValue = $this->resolveVariables($resolvedValue, $loadedVars); $resolvedValue = $this->resolveCommands($resolvedValue, $loadedVars); $resolvedValue = str_replace('\\\\', '\\', $resolvedValue); $v .= $resolvedValue; } else { $value = ''; $prevChr = $this->data[$this->cursor - 1]; while ($this->cursor < $this->end && !\in_array($this->data[$this->cursor], ["\n", '"', "'"], true) && !((' ' === $prevChr || "\t" === $prevChr) && '#' === $this->data[$this->cursor])) { if ('\\' === $this->data[$this->cursor] && isset($this->data[$this->cursor + 1]) && ('"' === $this->data[$this->cursor + 1] || "'" === $this->data[$this->cursor + 1])) { ++$this->cursor; } $value .= $prevChr = $this->data[$this->cursor]; if ('$' === $this->data[$this->cursor] && isset($this->data[$this->cursor + 1]) && '(' === $this->data[$this->cursor + 1]) { ++$this->cursor; $value .= '('.$this->lexNestedExpression().')'; } ++$this->cursor; } $value = rtrim($value); $resolvedValue = $value; $resolvedValue = $this->resolveVariables($resolvedValue, $loadedVars); $resolvedValue = $this->resolveCommands($resolvedValue, $loadedVars); $resolvedValue = str_replace('\\\\', '\\', $resolvedValue); if ($resolvedValue === $value && preg_match('/\s+/', $value)) { throw $this->createFormatException('A value containing spaces must be surrounded by quotes'); } $v .= $resolvedValue; if ($this->cursor < $this->end && '#' === $this->data[$this->cursor]) { break; } } } while ($this->cursor < $this->end && "\n" !== $this->data[$this->cursor]); $this->skipEmptyLines(); return $v; } private function lexNestedExpression() { ++$this->cursor; $value = ''; while ("\n" !== $this->data[$this->cursor] && ')' !== $this->data[$this->cursor]) { $value .= $this->data[$this->cursor]; if ('(' === $this->data[$this->cursor]) { $value .= $this->lexNestedExpression().')'; } ++$this->cursor; if ($this->cursor === $this->end) { throw $this->createFormatException('Missing closing parenthesis.'); } } if ("\n" === $this->data[$this->cursor]) { throw $this->createFormatException('Missing closing parenthesis.'); } return $value; } private function skipEmptyLines() { if (preg_match('/(?:\s*+(?:#[^\n]*+)?+)++/A', $this->data, $match, 0, $this->cursor)) { $this->moveCursor($match[0]); } } private function resolveCommands($value, $loadedVars) { if (false === strpos($value, '$')) { return $value; } $regex = '/ (\\\\)? # escaped with a backslash? \$ (?<cmd> \( # require opening parenthesis ([^()]|\g<cmd>)+ # allow any number of non-parens, or balanced parens (by nesting the <cmd> expression recursively) \) # require closing paren ) /x'; return preg_replace_callback($regex, function ($matches) use ($loadedVars) { if ('\\' === $matches[1]) { return substr($matches[0], 1); } if ('\\' === \DIRECTORY_SEPARATOR) { throw new \LogicException('Resolving commands is not supported on Windows.'); } if (!class_exists(Process::class)) { throw new \LogicException('Resolving commands requires the Symfony Process component.'); } $process = new Process('echo '.$matches[0]); $process->inheritEnvironmentVariables(true); $env = []; foreach ($this->values as $name => $value) { if (isset($loadedVars[$name]) || (!isset($_ENV[$name]) && !(isset($_SERVER[$name]) && 0 !== strpos($name, 'HTTP_')))) { $env[$name] = $value; } } $process->setEnv($env); try { $process->mustRun(); } catch (ProcessException $e) { throw $this->createFormatException(sprintf('Issue expanding a command (%s)', $process->getErrorOutput())); } return preg_replace('/[\r\n]+$/', '', $process->getOutput()); }, $value); } private function resolveVariables($value, array $loadedVars) { if (false === strpos($value, '$')) { return $value; } $regex = '/ (?<!\\\\) (?P<backslashes>\\\\*) # escaped with a backslash? \$ (?!\() # 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) use ($loadedVars) { // odd number of backslashes means the $ character is escaped if (1 === \strlen($matches['backslashes']) % 2) { return substr($matches[0], 1); } // 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['name']; if (isset($loadedVars[$name]) && isset($this->values[$name])) { $value = $this->values[$name]; } elseif (isset($_ENV[$name])) { $value = $_ENV[$name]; } elseif (isset($_SERVER[$name]) && 0 !== strpos($name, 'HTTP_')) { $value = $_SERVER[$name]; } elseif (isset($this->values[$name])) { $value = $this->values[$name]; } else { $value = (string) getenv($name); } if (!$matches['opening_brace'] && isset($matches['closing_brace'])) { $value .= '}'; } return $matches['backslashes'].$value; }, $value); return $value; } private function moveCursor($text) { $this->cursor += \strlen($text); $this->lineno += substr_count($text, "\n"); } private function createFormatException($message) { return new FormatException($message, new FormatExceptionContext($this->data, $this->path, $this->lineno, $this->cursor)); } }