1
0

提交代码

This commit is contained in:
2020-08-06 14:50:07 +08:00
parent 9d0d5f4be9
commit d7a848c824
11299 changed files with 1321854 additions and 0 deletions

30
vendor/vlucas/phpdotenv/LICENSE vendored Normal file
View File

@@ -0,0 +1,30 @@
BSD 3-Clause License
Copyright (c) 2014, Graham Campbell.
Copyright (c) 2013, Vance Lucas.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

36
vendor/vlucas/phpdotenv/composer.json vendored Normal file
View File

@@ -0,0 +1,36 @@
{
"name": "vlucas/phpdotenv",
"description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.",
"keywords": ["env", "dotenv", "environment"],
"license" : "BSD-3-Clause",
"authors" : [
{
"name": "Graham Campbell",
"email": "graham@alt-three.com",
"homepage": "https://gjcampbell.co.uk/"
},
{
"name": "Vance Lucas",
"email": "vance@vancelucas.com",
"homepage": "https://vancelucas.com/"
}
],
"require": {
"php": "^5.4 || ^7.0",
"phpoption/phpoption": "^1.5",
"symfony/polyfill-ctype": "^1.9"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35 || ^5.0 || ^6.0 || ^7.0"
},
"autoload": {
"psr-4": {
"Dotenv\\": "src/"
}
},
"extra": {
"branch-alias": {
"dev-master": "3.6-dev"
}
}
}

159
vendor/vlucas/phpdotenv/src/Dotenv.php vendored Normal file
View File

@@ -0,0 +1,159 @@
<?php
namespace Dotenv;
use Dotenv\Environment\DotenvFactory;
use Dotenv\Environment\FactoryInterface;
use Dotenv\Exception\InvalidPathException;
/**
* This is the dotenv class.
*
* It's responsible for loading a `.env` file in the given directory and
* setting the environment variables.
*/
class Dotenv
{
/**
* The loader instance.
*
* @var \Dotenv\Loader
*/
protected $loader;
/**
* Create a new dotenv instance.
*
* @param \Dotenv\Loader $loader
*
* @return void
*/
public function __construct(Loader $loader)
{
$this->loader = $loader;
}
/**
* Create a new dotenv instance.
*
* @param string|string[] $paths
* @param string|null $file
* @param \Dotenv\Environment\FactoryInterface|null $envFactory
*
* @return \Dotenv\Dotenv
*/
public static function create($paths, $file = null, FactoryInterface $envFactory = null)
{
$loader = new Loader(
self::getFilePaths((array) $paths, $file ?: '.env'),
$envFactory ?: new DotenvFactory(),
true
);
return new self($loader);
}
/**
* Returns the full paths to the files.
*
* @param string[] $paths
* @param string $file
*
* @return string[]
*/
private static function getFilePaths(array $paths, $file)
{
return array_map(function ($path) use ($file) {
return rtrim($path, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.$file;
}, $paths);
}
/**
* Load environment file in given directory.
*
* @throws \Dotenv\Exception\InvalidPathException|\Dotenv\Exception\InvalidFileException
*
* @return array<string|null>
*/
public function load()
{
return $this->loadData();
}
/**
* Load environment file in given directory, silently failing if it doesn't exist.
*
* @throws \Dotenv\Exception\InvalidFileException
*
* @return array<string|null>
*/
public function safeLoad()
{
try {
return $this->loadData();
} catch (InvalidPathException $e) {
// suppressing exception
return [];
}
}
/**
* Load environment file in given directory.
*
* @throws \Dotenv\Exception\InvalidPathException|\Dotenv\Exception\InvalidFileException
*
* @return array<string|null>
*/
public function overload()
{
return $this->loadData(true);
}
/**
* Actually load the data.
*
* @param bool $overload
*
* @throws \Dotenv\Exception\InvalidPathException|\Dotenv\Exception\InvalidFileException
*
* @return array<string|null>
*/
protected function loadData($overload = false)
{
return $this->loader->setImmutable(!$overload)->load();
}
/**
* Required ensures that the specified variables exist, and returns a new validator object.
*
* @param string|string[] $variables
*
* @return \Dotenv\Validator
*/
public function required($variables)
{
return new Validator((array) $variables, $this->loader);
}
/**
* Returns a new validator object that won't check if the specified variables exist.
*
* @param string|string[] $variables
*
* @return \Dotenv\Validator
*/
public function ifPresent($variables)
{
return new Validator((array) $variables, $this->loader, false);
}
/**
* Get the list of environment variables declared inside the 'env' file.
*
* @return string[]
*/
public function getEnvironmentVariableNames()
{
return $this->loader->getEnvironmentVariableNames();
}
}

View File

@@ -0,0 +1,190 @@
<?php
namespace Dotenv\Environment;
use Dotenv\Environment\Adapter\ArrayAdapter;
use InvalidArgumentException;
/**
* This is the abstract variables implementation.
*
* Extend this as required, implementing "get", "set", and "clear".
*/
abstract class AbstractVariables implements VariablesInterface
{
/**
* Are we immutable?
*
* @var bool
*/
private $immutable;
/**
* The record of loaded variables.
*
* @var \Dotenv\Environment\Adapter\ArrayAdapter
*/
private $loaded;
/**
* Create a new environment variables instance.
*
* @param bool $immutable
*
* @return void
*/
public function __construct($immutable)
{
$this->immutable = $immutable;
$this->loaded = new ArrayAdapter();
}
/**
* Get an environment variable.
*
* @param string $name
*
* @throws \InvalidArgumentException
*
* @return string|null
*/
public function get($name)
{
if (!is_string($name)) {
throw new InvalidArgumentException('Expected name to be a string.');
}
return $this->getInternal($name);
}
/**
* Get an environment variable.
*
* @param string $name
*
* @return string|null
*/
protected abstract function getInternal($name);
/**
* Set an environment variable.
*
* @param string $name
* @param string|null $value
*
* @throws \InvalidArgumentException
*
* @return void
*/
public function set($name, $value = null)
{
if (!is_string($name)) {
throw new InvalidArgumentException('Expected name to be a string.');
}
// Don't overwrite existing environment variables if we're immutable
// Ruby's dotenv does this with `ENV[key] ||= value`.
if ($this->isImmutable() && $this->get($name) !== null && $this->loaded->get($name)->isEmpty()) {
return;
}
$this->setInternal($name, $value);
$this->loaded->set($name, '');
}
/**
* Set an environment variable.
*
* @param string $name
* @param string|null $value
*
* @return void
*/
protected abstract function setInternal($name, $value = null);
/**
* Clear an environment variable.
*
* @param string $name
*
* @throws \InvalidArgumentException
*
* @return void
*/
public function clear($name)
{
if (!is_string($name)) {
throw new InvalidArgumentException('Expected name to be a string.');
}
// Don't clear anything if we're immutable.
if ($this->isImmutable()) {
return;
}
$this->clearInternal($name);
}
/**
* Clear an environment variable.
*
* @param string $name
*
* @return void
*/
protected abstract function clearInternal($name);
/**
* Determine if the environment is immutable.
*
* @return bool
*/
public function isImmutable()
{
return $this->immutable;
}
/**
* Tells whether environment variable has been defined.
*
* @param string $name
*
* @return bool
*/
public function has($name)
{
return is_string($name) && $this->get($name) !== null;
}
/**
* {@inheritdoc}
*/
public function offsetExists($offset)
{
return $this->has($offset);
}
/**
* {@inheritdoc}
*/
public function offsetGet($offset)
{
return $this->get($offset);
}
/**
* {@inheritdoc}
*/
public function offsetSet($offset, $value)
{
$this->set($offset, $value);
}
/**
* {@inheritdoc}
*/
public function offsetUnset($offset)
{
$this->clear($offset);
}
}

View File

@@ -0,0 +1,41 @@
<?php
namespace Dotenv\Environment\Adapter;
interface AdapterInterface
{
/**
* Determines if the adapter is supported.
*
* @return bool
*/
public function isSupported();
/**
* Get an environment variable, if it exists.
*
* @param string $name
*
* @return \PhpOption\Option
*/
public function get($name);
/**
* Set an environment variable.
*
* @param string $name
* @param string|null $value
*
* @return void
*/
public function set($name, $value = null);
/**
* Clear an environment variable.
*
* @param string $name
*
* @return void
*/
public function clear($name);
}

View File

@@ -0,0 +1,64 @@
<?php
namespace Dotenv\Environment\Adapter;
use PhpOption\None;
class ApacheAdapter implements AdapterInterface
{
/**
* Determines if the adapter is supported.
*
* This happens if PHP is running as an Apache module.
*
* @return bool
*/
public function isSupported()
{
return function_exists('apache_getenv') && function_exists('apache_setenv');
}
/**
* Get an environment variable, if it exists.
*
* This is intentionally not implemented, since this adapter exists only as
* a means to overwrite existing apache environment variables.
*
* @param string $name
*
* @return \PhpOption\Option
*/
public function get($name)
{
return None::create();
}
/**
* Set an environment variable.
*
* Only if an existing apache variable exists do we overwrite it.
*
* @param string $name
* @param string|null $value
*
* @return void
*/
public function set($name, $value = null)
{
if (apache_getenv($name) !== false) {
apache_setenv($name, (string) $value);
}
}
/**
* Clear an environment variable.
*
* @param string $name
*
* @return void
*/
public function clear($name)
{
// Nothing to do here.
}
}

View File

@@ -0,0 +1,67 @@
<?php
namespace Dotenv\Environment\Adapter;
use PhpOption\None;
use PhpOption\Some;
class ArrayAdapter implements AdapterInterface
{
/**
* The variables and their values.
*
* @return array<string|null>
*/
private $variables = [];
/**
* Determines if the adapter is supported.
*
* @return bool
*/
public function isSupported()
{
return true;
}
/**
* Get an environment variable, if it exists.
*
* @param string $name
*
* @return \PhpOption\Option
*/
public function get($name)
{
if (array_key_exists($name, $this->variables)) {
return Some::create($this->variables[$name]);
}
return None::create();
}
/**
* Set an environment variable.
*
* @param string $name
* @param string|null $value
*
* @return void
*/
public function set($name, $value = null)
{
$this->variables[$name] = $value;
}
/**
* Clear an environment variable.
*
* @param string $name
*
* @return void
*/
public function clear($name)
{
unset($this->variables[$name]);
}
}

View File

@@ -0,0 +1,60 @@
<?php
namespace Dotenv\Environment\Adapter;
use PhpOption\None;
use PhpOption\Some;
class EnvConstAdapter implements AdapterInterface
{
/**
* Determines if the adapter is supported.
*
* @return bool
*/
public function isSupported()
{
return true;
}
/**
* Get an environment variable, if it exists.
*
* @param string $name
*
* @return \PhpOption\Option
*/
public function get($name)
{
if (array_key_exists($name, $_ENV)) {
return Some::create($_ENV[$name]);
}
return None::create();
}
/**
* Set an environment variable.
*
* @param string $name
* @param string|null $value
*
* @return void
*/
public function set($name, $value = null)
{
$_ENV[$name] = $value;
}
/**
* Clear an environment variable.
*
* @param string $name
*
* @return void
*/
public function clear($name)
{
unset($_ENV[$name]);
}
}

View File

@@ -0,0 +1,55 @@
<?php
namespace Dotenv\Environment\Adapter;
use PhpOption\Option;
class PutenvAdapter implements AdapterInterface
{
/**
* Determines if the adapter is supported.
*
* @return bool
*/
public function isSupported()
{
return function_exists('putenv');
}
/**
* Get an environment variable, if it exists.
*
* @param string $name
*
* @return \PhpOption\Option
*/
public function get($name)
{
return Option::fromValue(getenv($name), false);
}
/**
* Set an environment variable.
*
* @param string $name
* @param string|null $value
*
* @return void
*/
public function set($name, $value = null)
{
putenv("$name=$value");
}
/**
* Clear an environment variable.
*
* @param string $name
*
* @return void
*/
public function clear($name)
{
putenv($name);
}
}

View File

@@ -0,0 +1,60 @@
<?php
namespace Dotenv\Environment\Adapter;
use PhpOption\None;
use PhpOption\Some;
class ServerConstAdapter implements AdapterInterface
{
/**
* Determines if the adapter is supported.
*
* @return bool
*/
public function isSupported()
{
return true;
}
/**
* Get an environment variable, if it exists.
*
* @param string $name
*
* @return \PhpOption\Option
*/
public function get($name)
{
if (array_key_exists($name, $_SERVER)) {
return Some::create($_SERVER[$name]);
}
return None::create();
}
/**
* Set an environment variable.
*
* @param string $name
* @param string|null $value
*
* @return void
*/
public function set($name, $value = null)
{
$_SERVER[$name] = $value;
}
/**
* Clear an environment variable.
*
* @param string $name
*
* @return void
*/
public function clear($name)
{
unset($_SERVER[$name]);
}
}

View File

@@ -0,0 +1,58 @@
<?php
namespace Dotenv\Environment;
use Dotenv\Environment\Adapter\AdapterInterface;
use Dotenv\Environment\Adapter\ApacheAdapter;
use Dotenv\Environment\Adapter\EnvConstAdapter;
use Dotenv\Environment\Adapter\PutenvAdapter;
use Dotenv\Environment\Adapter\ServerConstAdapter;
/**
* The default implementation of the environment factory interface.
*/
class DotenvFactory implements FactoryInterface
{
/**
* The set of adapters to use.
*
* @var \Dotenv\Environment\Adapter\AdapterInterface[]
*/
protected $adapters;
/**
* Create a new dotenv environment factory instance.
*
* If no adapters are provided, then the defaults will be used.
*
* @param \Dotenv\Environment\Adapter\AdapterInterface[]|null $adapters
*
* @return void
*/
public function __construct(array $adapters = null)
{
$this->adapters = array_filter($adapters === null ? [new ApacheAdapter(), new EnvConstAdapter(), new ServerConstAdapter(), new PutenvAdapter()] : $adapters, function (AdapterInterface $adapter) {
return $adapter->isSupported();
});
}
/**
* Creates a new mutable environment variables instance.
*
* @return \Dotenv\Environment\VariablesInterface
*/
public function create()
{
return new DotenvVariables($this->adapters, false);
}
/**
* Creates a new immutable environment variables instance.
*
* @return \Dotenv\Environment\VariablesInterface
*/
public function createImmutable()
{
return new DotenvVariables($this->adapters, true);
}
}

View File

@@ -0,0 +1,78 @@
<?php
namespace Dotenv\Environment;
/**
* The default implementation of the environment variables interface.
*/
class DotenvVariables extends AbstractVariables
{
/**
* The set of adapters to use.
*
* @var \Dotenv\Environment\Adapter\AdapterInterface[]
*/
protected $adapters;
/**
* Create a new dotenv environment variables instance.
*
* @param \Dotenv\Environment\Adapter\AdapterInterface[] $adapters
* @param bool $immutable
*
* @return void
*/
public function __construct(array $adapters, $immutable)
{
$this->adapters = $adapters;
parent::__construct($immutable);
}
/**
* Get an environment variable.
*
* We do this by querying our adapters sequentially.
*
* @param string $name
*
* @return string|null
*/
protected function getInternal($name)
{
foreach ($this->adapters as $adapter) {
$result = $adapter->get($name);
if ($result->isDefined()) {
return $result->get();
}
}
}
/**
* Set an environment variable.
*
* @param string $name
* @param string|null $value
*
* @return void
*/
protected function setInternal($name, $value = null)
{
foreach ($this->adapters as $adapter) {
$adapter->set($name, $value);
}
}
/**
* Clear an environment variable.
*
* @param string $name
*
* @return void
*/
protected function clearInternal($name)
{
foreach ($this->adapters as $adapter) {
$adapter->clear($name);
}
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace Dotenv\Environment;
/**
* This environment factory interface.
*
* If you need custom implementations of the variables interface, implement
* this interface, and use your implementation in the loader.
*/
interface FactoryInterface
{
/**
* Creates a new mutable environment variables instance.
*
* @return \Dotenv\Environment\VariablesInterface
*/
public function create();
/**
* Creates a new immutable environment variables instance.
*
* @return \Dotenv\Environment\VariablesInterface
*/
public function createImmutable();
}

View File

@@ -0,0 +1,61 @@
<?php
namespace Dotenv\Environment;
use ArrayAccess;
/**
* This environment variables interface.
*/
interface VariablesInterface extends ArrayAccess
{
/**
* Determine if the environment is immutable.
*
* @return bool
*/
public function isImmutable();
/**
* Tells whether environment variable has been defined.
*
* @param string $name
*
* @return bool
*/
public function has($name);
/**
* Get an environment variable.
*
* @param string $name
*
* @throws \InvalidArgumentException
*
* @return string|null
*/
public function get($name);
/**
* Set an environment variable.
*
* @param string $name
* @param string|null $value
*
* @throws \InvalidArgumentException
*
* @return void
*/
public function set($name, $value = null);
/**
* Clear an environment variable.
*
* @param string $name
*
* @throws \InvalidArgumentException
*
* @return void
*/
public function clear($name);
}

View File

@@ -0,0 +1,11 @@
<?php
namespace Dotenv\Exception;
/**
* This is the exception interface.
*/
interface ExceptionInterface
{
//
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Dotenv\Exception;
use InvalidArgumentException;
/**
* This is the invalid file exception class.
*/
class InvalidFileException extends InvalidArgumentException implements ExceptionInterface
{
//
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Dotenv\Exception;
use InvalidArgumentException;
/**
* This is the invalid path exception class.
*/
class InvalidPathException extends InvalidArgumentException implements ExceptionInterface
{
//
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Dotenv\Exception;
use RuntimeException;
/**
* This is the validation exception class.
*/
class ValidationException extends RuntimeException implements ExceptionInterface
{
//
}

142
vendor/vlucas/phpdotenv/src/Lines.php vendored Normal file
View File

@@ -0,0 +1,142 @@
<?php
namespace Dotenv;
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::isComment($line) && self::isSetter($line)) {
$output[] = $line;
}
}
return $output;
}
/**
* Used to make all multiline variable process.
*
* @param bool $multiline
* @param string $line
* @param string[] $buffer
*
* @return array
*/
private static function multilineProcess($multiline, $line, array $buffer)
{
// check if $line can be multiline variable
if ($started = self::looksLikeMultilineStart($line)) {
$multiline = true;
}
if ($multiline) {
array_push($buffer, $line);
if (self::looksLikeMultilineStop($line, $started)) {
$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 bool
*/
private static function getCharPairs($line)
{
$chars = str_split($line);
return array_map(null, $chars, array_slice($chars, 1));
}
/**
* Determine if the line in the file is a comment, e.g. begins with a #.
*
* @param string $line
*
* @return bool
*/
private static function isComment($line)
{
$line = ltrim($line);
return isset($line[0]) && $line[0] === '#';
}
/**
* Determine if the given line looks like it's setting a variable.
*
* @param string $line
*
* @return bool
*/
private static function isSetter($line)
{
return strpos($line, '=') !== false;
}
}

255
vendor/vlucas/phpdotenv/src/Loader.php vendored Normal file
View File

@@ -0,0 +1,255 @@
<?php
namespace Dotenv;
use Dotenv\Environment\FactoryInterface;
use Dotenv\Exception\InvalidPathException;
use Dotenv\Regex\Regex;
use PhpOption\Option;
/**
* This is the loader class.
*
* It's responsible for loading variables by reading a file from disk and:
* - stripping comments beginning with a `#`,
* - parsing lines that look shell variable setters, e.g `export key = value`, `key="value"`.
* - multiline variable look always start with a " and end with it, e.g: `key="value
* value"`
*/
class Loader
{
/**
* The file paths.
*
* @var string[]
*/
protected $filePaths;
/**
* The environment factory instance.
*
* @var \Dotenv\Environment\FactoryInterface
*/
protected $envFactory;
/**
* The environment variables instance.
*
* @var \Dotenv\Environment\VariablesInterface
*/
protected $envVariables;
/**
* The list of environment variables declared inside the 'env' file.
*
* @var string[]
*/
protected $variableNames = [];
/**
* Create a new loader instance.
*
* @param string[] $filePaths
* @param \Dotenv\Environment\FactoryInterface $envFactory
* @param bool $immutable
*
* @return void
*/
public function __construct(array $filePaths, FactoryInterface $envFactory, $immutable = false)
{
$this->filePaths = $filePaths;
$this->envFactory = $envFactory;
$this->setImmutable($immutable);
}
/**
* Set immutable value.
*
* @param bool $immutable
*
* @return $this
*/
public function setImmutable($immutable = false)
{
$this->envVariables = $immutable
? $this->envFactory->createImmutable()
: $this->envFactory->create();
return $this;
}
/**
* Load the environment file from disk.
*
* @throws \Dotenv\Exception\InvalidPathException|\Dotenv\Exception\InvalidFileException
*
* @return array<string|null>
*/
public function load()
{
return $this->loadDirect(
self::findAndRead($this->filePaths)
);
}
/**
* Directly load the given string.
*
* @param string $content
*
* @throws \Dotenv\Exception\InvalidFileException
*
* @return array<string|null>
*/
public function loadDirect($content)
{
return $this->processEntries(
Lines::process(preg_split("/(\r\n|\n|\r)/", $content))
);
}
/**
* Attempt to read the files in order.
*
* @param string[] $filePaths
*
* @throws \Dotenv\Exception\InvalidPathException
*
* @return string[]
*/
private static function findAndRead(array $filePaths)
{
if ($filePaths === []) {
throw new InvalidPathException('At least one environment file path must be provided.');
}
foreach ($filePaths as $filePath) {
$lines = self::readFromFile($filePath);
if ($lines->isDefined()) {
return $lines->get();
}
}
throw new InvalidPathException(
sprintf('Unable to read any of the environment file(s) at [%s].', implode(', ', $filePaths))
);
}
/**
* Read the given file.
*
* @param string $filePath
*
* @return \PhpOption\Option
*/
private static function readFromFile($filePath)
{
$content = @file_get_contents($filePath);
return Option::fromValue($content, false);
}
/**
* Process the environment variable entries.
*
* We'll fill out any nested variables, and acually set the variable using
* the underlying environment variables instance.
*
* @param string[] $entries
*
* @throws \Dotenv\Exception\InvalidFileException
*
* @return array<string|null>
*/
private function processEntries(array $entries)
{
$vars = [];
foreach ($entries as $entry) {
list($name, $value) = Parser::parse($entry);
$vars[$name] = $this->resolveNestedVariables($value);
$this->setEnvironmentVariable($name, $vars[$name]);
}
return $vars;
}
/**
* Resolve the nested variables.
*
* Look for ${varname} patterns in the variable value and replace with an
* existing environment variable.
*
* @param string|null $value
*
* @return string|null
*/
private function resolveNestedVariables($value = null)
{
return Option::fromValue($value)
->filter(function ($str) {
return strpos($str, '$') !== false;
})
->flatMap(function ($str) {
return Regex::replaceCallback(
'/\${([a-zA-Z0-9_.]+)}/',
function (array $matches) {
return Option::fromValue($this->getEnvironmentVariable($matches[1]))
->getOrElse($matches[0]);
},
$str
)->success();
})
->getOrElse($value);
}
/**
* Search the different places for environment variables and return first value found.
*
* @param string $name
*
* @return string|null
*/
public function getEnvironmentVariable($name)
{
return $this->envVariables->get($name);
}
/**
* Set an environment variable.
*
* @param string $name
* @param string|null $value
*
* @return void
*/
public function setEnvironmentVariable($name, $value = null)
{
$this->variableNames[] = $name;
$this->envVariables->set($name, $value);
}
/**
* Clear an environment variable.
*
* This method only expects names in normal form.
*
* @param string $name
*
* @return void
*/
public function clearEnvironmentVariable($name)
{
$this->envVariables->clear($name);
}
/**
* Get the list of environment variables names.
*
* @return string[]
*/
public function getEnvironmentVariableNames()
{
return $this->variableNames;
}
}

176
vendor/vlucas/phpdotenv/src/Parser.php vendored Normal file
View File

@@ -0,0 +1,176 @@
<?php
namespace Dotenv;
use Dotenv\Exception\InvalidFileException;
class Parser
{
const INITIAL_STATE = 0;
const UNQUOTED_STATE = 1;
const QUOTED_STATE = 2;
const ESCAPE_STATE = 3;
const WHITESPACE_STATE = 4;
const COMMENT_STATE = 5;
/**
* Parse the given environment variable entry into a name and value.
*
* @param string $entry
*
* @throws \Dotenv\Exception\InvalidFileException
*
* @return array
*/
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
*/
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 preg_match('~\A[a-zA-Z0-9_.]+\z~', $name) === 1;
}
/**
* Strips quotes and comments from the environment variable value.
*
* @param string|null $value
*
* @throws \Dotenv\Exception\InvalidFileException
*
* @return string|null
*/
private static function parseValue($value)
{
if ($value === null || trim($value) === '') {
return $value;
}
return array_reduce(str_split($value), function ($data, $char) use ($value) {
switch ($data[1]) {
case self::INITIAL_STATE:
if ($char === '"' || $char === '\'') {
return [$data[0], self::QUOTED_STATE];
} elseif ($char === '#') {
return [$data[0], self::COMMENT_STATE];
} else {
return [$data[0].$char, self::UNQUOTED_STATE];
}
case self::UNQUOTED_STATE:
if ($char === '#') {
return [$data[0], self::COMMENT_STATE];
} elseif (ctype_space($char)) {
return [$data[0], self::WHITESPACE_STATE];
} else {
return [$data[0].$char, self::UNQUOTED_STATE];
}
case self::QUOTED_STATE:
if ($char === $value[0]) {
return [$data[0], self::WHITESPACE_STATE];
} elseif ($char === '\\') {
return [$data[0], self::ESCAPE_STATE];
} else {
return [$data[0].$char, self::QUOTED_STATE];
}
case self::ESCAPE_STATE:
if ($char === $value[0] || $char === '\\') {
return [$data[0].$char, self::QUOTED_STATE];
} elseif (in_array($char, ['f', 'n', 'r', 't', 'v'], true)) {
return [$data[0].stripcslashes('\\' . $char), self::QUOTED_STATE];
} else {
throw new InvalidFileException(
self::getErrorMessage('an unexpected escape sequence', $value)
);
}
case self::WHITESPACE_STATE:
if ($char === '#') {
return [$data[0], self::COMMENT_STATE];
} elseif (!ctype_space($char)) {
throw new InvalidFileException(
self::getErrorMessage('unexpected whitespace', $value)
);
} else {
return [$data[0], self::WHITESPACE_STATE];
}
case self::COMMENT_STATE:
return [$data[0], self::COMMENT_STATE];
}
}, ['', self::INITIAL_STATE])[0];
}
/**
* 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,82 @@
<?php
namespace Dotenv\Regex;
use PhpOption\None;
use PhpOption\Some;
class Error extends Result
{
/**
* @var string
*/
private $value;
/**
* Internal constructor for an error value.
*
* @param string $value
*
* @return void
*/
private function __construct($value)
{
$this->value = $value;
}
/**
* Create a new error value.
*
* @param string $value
*
* @return \Dotenv\Regex\Result
*/
public static function create($value)
{
return new self($value);
}
/**
* Get the success option value.
*
* @return \PhpOption\Option
*/
public function success()
{
return None::create();
}
/**
* Map over the success value.
*
* @param callable $f
*
* @return \Dotenv\Regex\Result
*/
public function mapSuccess(callable $f)
{
return self::create($this->value);
}
/**
* Get the error option value.
*
* @return \PhpOption\Option
*/
public function error()
{
return Some::create($this->value);
}
/**
* Map over the error value.
*
* @param callable $f
*
* @return \Dotenv\Regex\Result
*/
public function mapError(callable $f)
{
return self::create($f($this->value));
}
}

View File

@@ -0,0 +1,100 @@
<?php
namespace Dotenv\Regex;
use PhpOption\Option;
class Regex
{
/**
* Perform a preg match, wrapping up the result.
*
* @param string $pattern
* @param string $subject
*
* @return \Dotenv\Regex\Result
*/
public static function match($pattern, $subject)
{
return self::pregAndWrap(function ($subject) use ($pattern) {
return (int) @preg_match($pattern, $subject);
}, $subject);
}
/**
* Perform a preg replace, wrapping up the result.
*
* @param string $pattern
* @param string $replacement
* @param string $subject
*
* @return \Dotenv\Regex\Result
*/
public static function replace($pattern, $replacement, $subject)
{
return self::pregAndWrap(function ($subject) use ($pattern, $replacement) {
return (string) @preg_replace($pattern, $replacement, $subject);
}, $subject);
}
/**
* Perform a preg replace callback, wrapping up the result.
*
* @param string $pattern
* @param callable $callback
* @param string $subject
*
* @return \Dotenv\Regex\Result
*/
public static function replaceCallback($pattern, callable $callback, $subject)
{
return self::pregAndWrap(function ($subject) use ($pattern, $callback) {
return (string) @preg_replace_callback($pattern, $callback, $subject);
}, $subject);
}
/**
* Perform a preg operation, wrapping up the result.
*
* @param callable $operation
* @param string $subject
*
* @return \Dotenv\Regex\Result
*/
private static function pregAndWrap(callable $operation, $subject)
{
$result = $operation($subject);
if (($e = preg_last_error()) !== PREG_NO_ERROR) {
return Error::create(self::lookupError($e));
}
return Success::create($result);
}
/**
* Lookup the preg error code.
*
* @param int $code
*
* @return string
*/
private static function lookupError($code)
{
return Option::fromValue(get_defined_constants(true))
->filter(function (array $consts) {
return isset($consts['pcre']) && defined('ARRAY_FILTER_USE_KEY');
})
->map(function (array $consts) {
return array_filter($consts['pcre'], function ($msg) {
return substr($msg, -6) === '_ERROR';
}, ARRAY_FILTER_USE_KEY);
})
->flatMap(function (array $errors) use ($code) {
return Option::fromValue(
array_search($code, $errors, true)
);
})
->getOrElse('PREG_ERROR');
}
}

View File

@@ -0,0 +1,58 @@
<?php
namespace Dotenv\Regex;
abstract class Result
{
/**
* Get the success option value.
*
* @return \PhpOption\Option
*/
abstract public function success();
/**
* Get the error value, if possible.
*
* @return string|int
*/
public function getSuccess()
{
return $this->success()->get();
}
/**
* Map over the success value.
*
* @param callable $f
*
* @return \Dotenv\Regex\Result
*/
abstract public function mapSuccess(callable $f);
/**
* Get the error option value.
*
* @return \PhpOption\Option
*/
abstract public function error();
/**
* Get the error value, if possible.
*
* @return string
*/
public function getError()
{
return $this->error()->get();
}
/**
* Map over the error value.
*
* @param callable $f
*
* @return \Dotenv\Regex\Result
*/
abstract public function mapError(callable $f);
}

View File

@@ -0,0 +1,82 @@
<?php
namespace Dotenv\Regex;
use PhpOption\None;
use PhpOption\Some;
class Success extends Result
{
/**
* @var string|int
*/
private $value;
/**
* Internal constructor for a success value.
*
* @param string|int $value
*
* @return void
*/
private function __construct($value)
{
$this->value = $value;
}
/**
* Create a new success value.
*
* @param string|int $value
*
* @return \Dotenv\Regex\Result
*/
public static function create($value)
{
return new self($value);
}
/**
* Get the success option value.
*
* @return \PhpOption\Option
*/
public function success()
{
return Some::create($this->value);
}
/**
* Map over the success value.
*
* @param callable $f
*
* @return \Dotenv\Regex\Result
*/
public function mapSuccess(callable $f)
{
return self::create($f($this->value));
}
/**
* Get the error option value.
*
* @return \PhpOption\Option
*/
public function error()
{
return None::create();
}
/**
* Map over the error value.
*
* @param callable $f
*
* @return \Dotenv\Regex\Result
*/
public function mapError(callable $f)
{
return self::create($this->value);
}
}

View File

@@ -0,0 +1,195 @@
<?php
namespace Dotenv;
use Dotenv\Exception\ValidationException;
use Dotenv\Regex\Regex;
/**
* This is the validator class.
*
* It's responsible for applying validations against a number of variables.
*/
class Validator
{
/**
* The variables to validate.
*
* @var string[]
*/
protected $variables;
/**
* The loader instance.
*
* @var \Dotenv\Loader
*/
protected $loader;
/**
* Create a new validator instance.
*
* @param string[] $variables
* @param \Dotenv\Loader $loader
* @param bool $required
*
* @throws \Dotenv\Exception\ValidationException
*
* @return void
*/
public function __construct(array $variables, Loader $loader, $required = true)
{
$this->variables = $variables;
$this->loader = $loader;
if ($required) {
$this->assertCallback(
function ($value) {
return $value !== null;
},
'is missing'
);
}
}
/**
* Assert that each variable is not empty.
*
* @throws \Dotenv\Exception\ValidationException
*
* @return \Dotenv\Validator
*/
public function notEmpty()
{
return $this->assertCallback(
function ($value) {
if ($value === null) {
return true;
}
return strlen(trim($value)) > 0;
},
'is empty'
);
}
/**
* Assert that each specified variable is an integer.
*
* @throws \Dotenv\Exception\ValidationException
*
* @return \Dotenv\Validator
*/
public function isInteger()
{
return $this->assertCallback(
function ($value) {
if ($value === null) {
return true;
}
return ctype_digit($value);
},
'is not an integer'
);
}
/**
* Assert that each specified variable is a boolean.
*
* @throws \Dotenv\Exception\ValidationException
*
* @return \Dotenv\Validator
*/
public function isBoolean()
{
return $this->assertCallback(
function ($value) {
if ($value === null) {
return true;
}
if ($value === '') {
return false;
}
return filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) !== null;
},
'is not a boolean'
);
}
/**
* Assert that each variable is amongst the given choices.
*
* @param string[] $choices
*
* @throws \Dotenv\Exception\ValidationException
*
* @return \Dotenv\Validator
*/
public function allowedValues(array $choices)
{
return $this->assertCallback(
function ($value) use ($choices) {
return in_array($value, $choices, true);
},
sprintf('is not one of [%s]', implode(', ', $choices))
);
}
/**
* Assert that each variable matches the given regular expression.
*
* @param string $regex
*
* @throws \Dotenv\Exception\ValidationException
*
* @return \Dotenv\Validator
*/
public function allowedRegexValues($regex)
{
return $this->assertCallback(
function ($value) use ($regex)
{
if ($value === null) {
return true;
}
return Regex::match($regex, $value)->success()->getOrElse(0) === 1;
},
sprintf('does not match "%s"' , $regex)
);
}
/**
* Assert that the callback returns true for each variable.
*
* @param callable $callback
* @param string $message
*
* @throws \Dotenv\Exception\ValidationException
*
* @return \Dotenv\Validator
*/
protected function assertCallback(callable $callback, $message = 'failed callback assertion')
{
$failing = [];
foreach ($this->variables as $variable) {
if ($callback($this->loader->getEnvironmentVariable($variable)) === false) {
$failing[] = sprintf('%s %s', $variable, $message);
}
}
if (count($failing) > 0) {
throw new ValidationException(sprintf(
'One or more environment variables failed assertions: %s.',
implode(', ', $failing)
));
}
return $this;
}
}