dependencies-upgrade

This commit is contained in:
RafficMohammed
2023-01-08 02:20:59 +05:30
parent 7870479b18
commit 49021a4497
1711 changed files with 74994 additions and 70803 deletions

View File

@@ -1,137 +0,0 @@
<?php
namespace Dotenv\Loader;
class Lines
{
/**
* Process the array of lines of environment variables.
*
* This will produce an array of entries, one per variable.
*
* @param string[] $lines
*
* @return string[]
*/
public static function process(array $lines)
{
$output = [];
$multiline = false;
$multilineBuffer = [];
foreach ($lines as $line) {
list($multiline, $line, $multilineBuffer) = self::multilineProcess($multiline, $line, $multilineBuffer);
if (!$multiline && !self::isCommentOrWhitespace($line)) {
$output[] = $line;
}
}
return $output;
}
/**
* Used to make all multiline variable process.
*
* @param bool $multiline
* @param string $line
* @param string[] $buffer
*
* @return array{bool,string,string[]}
*/
private static function multilineProcess($multiline, $line, array $buffer)
{
$startsOnCurrentLine = $multiline ? false : self::looksLikeMultilineStart($line);
// check if $line can be multiline variable
if ($startsOnCurrentLine) {
$multiline = true;
}
if ($multiline) {
array_push($buffer, $line);
if (self::looksLikeMultilineStop($line, $startsOnCurrentLine)) {
$multiline = false;
$line = implode("\n", $buffer);
$buffer = [];
}
}
return [$multiline, $line, $buffer];
}
/**
* Determine if the given line can be the start of a multiline variable.
*
* @param string $line
*
* @return bool
*/
private static function looksLikeMultilineStart($line)
{
if (strpos($line, '="') === false) {
return false;
}
return self::looksLikeMultilineStop($line, true) === false;
}
/**
* Determine if the given line can be the start of a multiline variable.
*
* @param string $line
* @param bool $started
*
* @return bool
*/
private static function looksLikeMultilineStop($line, $started)
{
if ($line === '"') {
return true;
}
$seen = $started ? 0 : 1;
foreach (self::getCharPairs(str_replace('\\\\', '', $line)) as $pair) {
if ($pair[0] !== '\\' && $pair[1] === '"') {
$seen++;
}
}
return $seen > 1;
}
/**
* Get all pairs of adjacent characters within the line.
*
* @param string $line
*
* @return array{array{string,string|null}}
*/
private static function getCharPairs($line)
{
$chars = str_split($line);
/** @var array{array{string,string|null}} */
return array_map(null, $chars, array_slice($chars, 1));
}
/**
* Determine if the line in the file is a comment or whitespace.
*
* @param string $line
*
* @return bool
*/
private static function isCommentOrWhitespace($line)
{
if (trim($line) === '') {
return true;
}
$line = ltrim($line);
return isset($line[0]) && $line[0] === '#';
}
}

View File

@@ -1,122 +1,47 @@
<?php
declare(strict_types=1);
namespace Dotenv\Loader;
use Dotenv\Regex\Regex;
use Dotenv\Parser\Entry;
use Dotenv\Parser\Value;
use Dotenv\Repository\RepositoryInterface;
use PhpOption\Option;
class Loader implements LoaderInterface
final class Loader implements LoaderInterface
{
/**
* The variable name whitelist.
* Load the given entries into the repository.
*
* @var string[]|null
*/
protected $whitelist;
/**
* Create a new loader instance.
*
* @param string[]|null $whitelist
*
* @return void
*/
public function __construct(array $whitelist = null)
{
$this->whitelist = $whitelist;
}
/**
* Load the given environment file content into the repository.
* We'll substitute any nested variables, and send each variable to the
* repository, with the effect of actually mutating the environment.
*
* @param \Dotenv\Repository\RepositoryInterface $repository
* @param string $content
*
* @throws \Dotenv\Exception\InvalidFileException
* @param \Dotenv\Parser\Entry[] $entries
*
* @return array<string,string|null>
*/
public function load(RepositoryInterface $repository, $content)
public function load(RepositoryInterface $repository, array $entries)
{
return $this->processEntries(
$repository,
Lines::process(Regex::split("/(\r\n|\n|\r)/", $content)->getSuccess())
);
}
return \array_reduce($entries, static function (array $vars, Entry $entry) use ($repository) {
$name = $entry->getName();
/**
* Process the environment variable entries.
*
* We'll fill out any nested variables, and acually set the variable using
* the underlying environment variables instance.
*
* @param \Dotenv\Repository\RepositoryInterface $repository
* @param string[] $entries
*
* @throws \Dotenv\Exception\InvalidFileException
*
* @return array<string,string|null>
*/
private function processEntries(RepositoryInterface $repository, array $entries)
{
$vars = [];
$value = $entry->getValue()->map(static function (Value $value) use ($repository) {
return Resolver::resolve($repository, $value);
});
foreach ($entries as $entry) {
list($name, $value) = Parser::parse($entry);
if ($this->whitelist === null || in_array($name, $this->whitelist, true)) {
$vars[$name] = self::resolveNestedVariables($repository, $value);
$repository->set($name, $vars[$name]);
if ($value->isDefined()) {
$inner = $value->get();
if ($repository->set($name, $inner)) {
return \array_merge($vars, [$name => $inner]);
}
} else {
if ($repository->clear($name)) {
return \array_merge($vars, [$name => null]);
}
}
}
return $vars;
}
/**
* Resolve the nested variables.
*
* Look for ${varname} patterns in the variable value and replace with an
* existing environment variable.
*
* @param \Dotenv\Repository\RepositoryInterface $repository
* @param \Dotenv\Loader\Value|null $value
*
* @return string|null
*/
private static function resolveNestedVariables(RepositoryInterface $repository, Value $value = null)
{
/** @var Option<Value> */
$option = Option::fromValue($value);
return $option
->map(function (Value $v) use ($repository) {
/** @var string */
return array_reduce($v->getVars(), function ($s, $i) use ($repository) {
return substr($s, 0, $i).self::resolveNestedVariable($repository, substr($s, $i));
}, $v->getChars());
})
->getOrElse(null);
}
/**
* Resolve a single nested variable.
*
* @param \Dotenv\Repository\RepositoryInterface $repository
* @param string $str
*
* @return string
*/
private static function resolveNestedVariable(RepositoryInterface $repository, $str)
{
return Regex::replaceCallback(
'/\A\${([a-zA-Z0-9_.]+)}/',
function (array $matches) use ($repository) {
return Option::fromValue($repository->get($matches[1]))
->getOrElse($matches[0]);
},
$str,
1
)->success()->getOrElse($str);
return $vars;
}, []);
}
}

View File

@@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace Dotenv\Loader;
use Dotenv\Repository\RepositoryInterface;
@@ -7,14 +9,12 @@ use Dotenv\Repository\RepositoryInterface;
interface LoaderInterface
{
/**
* Load the given environment file content into the repository.
* Load the given entries into the repository.
*
* @param \Dotenv\Repository\RepositoryInterface $repository
* @param string $content
*
* @throws \Dotenv\Exception\InvalidFileException
* @param \Dotenv\Parser\Entry[] $entries
*
* @return array<string,string|null>
*/
public function load(RepositoryInterface $repository, $content);
public function load(RepositoryInterface $repository, array $entries);
}

View File

@@ -1,249 +0,0 @@
<?php
namespace Dotenv\Loader;
use Dotenv\Exception\InvalidFileException;
use Dotenv\Regex\Regex;
use Dotenv\Result\Error;
use Dotenv\Result\Success;
use RuntimeException;
class Parser
{
const INITIAL_STATE = 0;
const UNQUOTED_STATE = 1;
const SINGLE_QUOTED_STATE = 2;
const DOUBLE_QUOTED_STATE = 3;
const ESCAPE_SEQUENCE_STATE = 4;
const WHITESPACE_STATE = 5;
const COMMENT_STATE = 6;
/**
* Parse the given environment variable entry into a name and value.
*
* @param string $entry
*
* @throws \Dotenv\Exception\InvalidFileException
*
* @return array{string,\Dotenv\Loader\Value|null}
*/
public static function parse($entry)
{
list($name, $value) = self::splitStringIntoParts($entry);
return [self::parseName($name), self::parseValue($value)];
}
/**
* Split the compound string into parts.
*
* @param string $line
*
* @throws \Dotenv\Exception\InvalidFileException
*
* @return array{string,string|null}
*/
private static function splitStringIntoParts($line)
{
$name = $line;
$value = null;
if (strpos($line, '=') !== false) {
list($name, $value) = array_map('trim', explode('=', $line, 2));
}
if ($name === '') {
throw new InvalidFileException(
self::getErrorMessage('an unexpected equals', $line)
);
}
return [$name, $value];
}
/**
* Strips quotes and the optional leading "export " from the variable name.
*
* @param string $name
*
* @throws \Dotenv\Exception\InvalidFileException
*
* @return string
*/
private static function parseName($name)
{
$name = trim(str_replace(['export ', '\'', '"'], '', $name));
if (!self::isValidName($name)) {
throw new InvalidFileException(
self::getErrorMessage('an invalid name', $name)
);
}
return $name;
}
/**
* Is the given variable name valid?
*
* @param string $name
*
* @return bool
*/
private static function isValidName($name)
{
return Regex::match('~\A[a-zA-Z0-9_.]+\z~', $name)->success()->getOrElse(0) === 1;
}
/**
* Strips quotes and comments from the environment variable value.
*
* @param string|null $value
*
* @throws \Dotenv\Exception\InvalidFileException
*
* @return \Dotenv\Loader\Value|null
*/
private static function parseValue($value)
{
if ($value === null) {
return null;
}
if (trim($value) === '') {
return Value::blank();
}
$result = array_reduce(str_split($value), function ($data, $char) use ($value) {
return self::processChar($data[1], $char)->mapError(function ($err) use ($value) {
throw new InvalidFileException(
self::getErrorMessage($err, $value)
);
})->mapSuccess(function ($val) use ($data) {
return [$data[0]->append($val[0], $val[1]), $val[2]];
})->getSuccess();
}, [Value::blank(), self::INITIAL_STATE]);
if (in_array($result[1], [self::SINGLE_QUOTED_STATE, self::DOUBLE_QUOTED_STATE, self::ESCAPE_SEQUENCE_STATE], true)) {
throw new InvalidFileException(
self::getErrorMessage('a missing closing quote', $value)
);
}
return $result[0];
}
/**
* Process the given character.
*
* @param int $state
* @param string $char
*
* @return \Dotenv\Result\Result<array{string,bool,int},string>
*/
private static function processChar($state, $char)
{
switch ($state) {
case self::INITIAL_STATE:
if ($char === '\'') {
/** @var \Dotenv\Result\Result<array{string,bool,int},string> */
return Success::create(['', false, self::SINGLE_QUOTED_STATE]);
} elseif ($char === '"') {
/** @var \Dotenv\Result\Result<array{string,bool,int},string> */
return Success::create(['', false, self::DOUBLE_QUOTED_STATE]);
} elseif ($char === '#') {
/** @var \Dotenv\Result\Result<array{string,bool,int},string> */
return Success::create(['', false, self::COMMENT_STATE]);
} elseif ($char === '$') {
/** @var \Dotenv\Result\Result<array{string,bool,int},string> */
return Success::create([$char, true, self::UNQUOTED_STATE]);
} else {
/** @var \Dotenv\Result\Result<array{string,bool,int},string> */
return Success::create([$char, false, self::UNQUOTED_STATE]);
}
case self::UNQUOTED_STATE:
if ($char === '#') {
/** @var \Dotenv\Result\Result<array{string,bool,int},string> */
return Success::create(['', false, self::COMMENT_STATE]);
} elseif (ctype_space($char)) {
/** @var \Dotenv\Result\Result<array{string,bool,int},string> */
return Success::create(['', false, self::WHITESPACE_STATE]);
} elseif ($char === '$') {
/** @var \Dotenv\Result\Result<array{string,bool,int},string> */
return Success::create([$char, true, self::UNQUOTED_STATE]);
} else {
/** @var \Dotenv\Result\Result<array{string,bool,int},string> */
return Success::create([$char, false, self::UNQUOTED_STATE]);
}
case self::SINGLE_QUOTED_STATE:
if ($char === '\'') {
/** @var \Dotenv\Result\Result<array{string,bool,int},string> */
return Success::create(['', false, self::WHITESPACE_STATE]);
} else {
/** @var \Dotenv\Result\Result<array{string,bool,int},string> */
return Success::create([$char, false, self::SINGLE_QUOTED_STATE]);
}
case self::DOUBLE_QUOTED_STATE:
if ($char === '"') {
/** @var \Dotenv\Result\Result<array{string,bool,int},string> */
return Success::create(['', false, self::WHITESPACE_STATE]);
} elseif ($char === '\\') {
/** @var \Dotenv\Result\Result<array{string,bool,int},string> */
return Success::create(['', false, self::ESCAPE_SEQUENCE_STATE]);
} elseif ($char === '$') {
/** @var \Dotenv\Result\Result<array{string,bool,int},string> */
return Success::create([$char, true, self::DOUBLE_QUOTED_STATE]);
} else {
/** @var \Dotenv\Result\Result<array{string,bool,int},string> */
return Success::create([$char, false, self::DOUBLE_QUOTED_STATE]);
}
case self::ESCAPE_SEQUENCE_STATE:
if ($char === '"' || $char === '\\') {
/** @var \Dotenv\Result\Result<array{string,bool,int},string> */
return Success::create([$char, false, self::DOUBLE_QUOTED_STATE]);
} elseif ($char === '$') {
/** @var \Dotenv\Result\Result<array{string,bool,int},string> */
return Success::create([$char, false, self::DOUBLE_QUOTED_STATE]);
} elseif (in_array($char, ['f', 'n', 'r', 't', 'v'], true)) {
/** @var \Dotenv\Result\Result<array{string,bool,int},string> */
return Success::create([stripcslashes('\\'.$char), false, self::DOUBLE_QUOTED_STATE]);
} else {
/** @var \Dotenv\Result\Result<array{string,bool,int},string> */
return Error::create('an unexpected escape sequence');
}
case self::WHITESPACE_STATE:
if ($char === '#') {
/** @var \Dotenv\Result\Result<array{string,bool,int},string> */
return Success::create(['', false, self::COMMENT_STATE]);
} elseif (!ctype_space($char)) {
/** @var \Dotenv\Result\Result<array{string,bool,int},string> */
return Error::create('unexpected whitespace');
} else {
/** @var \Dotenv\Result\Result<array{string,bool,int},string> */
return Success::create(['', false, self::WHITESPACE_STATE]);
}
case self::COMMENT_STATE:
/** @var \Dotenv\Result\Result<array{string,bool,int},string> */
return Success::create(['', false, self::COMMENT_STATE]);
default:
throw new RuntimeException('Parser entered invalid state.');
}
}
/**
* Generate a friendly error message.
*
* @param string $cause
* @param string $subject
*
* @return string
*/
private static function getErrorMessage($cause, $subject)
{
return sprintf(
'Failed to parse dotenv file due to %s. Failed at [%s].',
$cause,
strtok($subject, "\n")
);
}
}

View File

@@ -0,0 +1,65 @@
<?php
declare(strict_types=1);
namespace Dotenv\Loader;
use Dotenv\Parser\Value;
use Dotenv\Repository\RepositoryInterface;
use Dotenv\Util\Regex;
use Dotenv\Util\Str;
use PhpOption\Option;
final class Resolver
{
/**
* This class is a singleton.
*
* @codeCoverageIgnore
*
* @return void
*/
private function __construct()
{
//
}
/**
* Resolve the nested variables in the given value.
*
* Replaces ${varname} patterns in the allowed positions in the variable
* value by an existing environment variable.
*
* @param \Dotenv\Repository\RepositoryInterface $repository
* @param \Dotenv\Parser\Value $value
*
* @return string
*/
public static function resolve(RepositoryInterface $repository, Value $value)
{
return \array_reduce($value->getVars(), static function (string $s, int $i) use ($repository) {
return Str::substr($s, 0, $i).self::resolveVariable($repository, Str::substr($s, $i));
}, $value->getChars());
}
/**
* Resolve a single nested variable.
*
* @param \Dotenv\Repository\RepositoryInterface $repository
* @param string $str
*
* @return string
*/
private static function resolveVariable(RepositoryInterface $repository, string $str)
{
return Regex::replaceCallback(
'/\A\${([a-zA-Z0-9_.]+)}/',
static function (array $matches) use ($repository) {
return Option::fromValue($repository->get($matches[1]))
->getOrElse($matches[0]);
},
$str,
1
)->success()->getOrElse($str);
}
}

View File

@@ -1,83 +0,0 @@
<?php
namespace Dotenv\Loader;
class Value
{
/**
* The string representation of the parsed value.
*
* @var string
*/
private $chars;
/**
* The locations of the variables in the value.
*
* @var int[]
*/
private $vars;
/**
* Internal constructor for a value.
*
* @param string $chars
* @param int[] $vars
*
* @return void
*/
private function __construct($chars, array $vars)
{
$this->chars = $chars;
$this->vars = $vars;
}
/**
* Create an empty value instance.
*
* @return \Dotenv\Loader\Value
*/
public static function blank()
{
return new self('', []);
}
/**
* Create a new value instance, appending the character.
*
* @param string $char
* @param bool $var
*
* @return \Dotenv\Loader\Value
*/
public function append($char, $var)
{
return new self(
$this->chars.$char,
$var ? array_merge($this->vars, [strlen($this->chars)]) : $this->vars
);
}
/**
* Get the string representation of the parsed value.
*
* @return string
*/
public function getChars()
{
return $this->chars;
}
/**
* Get the locations of the variables in the value.
*
* @return int[]
*/
public function getVars()
{
$vars = $this->vars;
rsort($vars);
return $vars;
}
}