aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Compiler/Compiler.php80
-rw-r--r--src/Compiler/CompilerInterface.php10
-rw-r--r--src/Dotenv.php23
-rw-r--r--src/Exception/RuntimeException.php7
-rw-r--r--src/Loader/FileLoader.php41
-rw-r--r--src/Loader/LoaderInterface.php7
-rw-r--r--src/Parser/Parser.php55
-rw-r--r--src/Parser/ParserInterface.php6
-rw-r--r--src/Types/KeyValue.php11
9 files changed, 232 insertions, 8 deletions
diff --git a/src/Compiler/Compiler.php b/src/Compiler/Compiler.php
new file mode 100644
index 0000000..6a587d2
--- /dev/null
+++ b/src/Compiler/Compiler.php
@@ -0,0 +1,80 @@
+<?php
+declare(strict_types=1);
+
+/**
+ * @author: Alexander Kiryukhin <alexander@kiryukhin.su>
+ * @license: MIT
+ */
+
+namespace NeonXP\Dotenv\Compiler;
+
+use NeonXP\Dotenv\Exception\RuntimeException;
+use NeonXP\Dotenv\Types\KeyValue;
+
+/**
+ * Class Compiler
+ * @package NeonXP\Dotenv\Compiler
+ */
+class Compiler implements CompilerInterface
+{
+ const REGEX_VARIABLE = '/\$\{(.+?)\}/';
+
+ /**
+ * @var KeyValue[]
+ */
+ protected $collection = [];
+
+ /**
+ * @var KeyValue[]
+ */
+ protected $cache = [];
+
+ /**
+ * @inheritdoc
+ * @param KeyValue[] $collection
+ */
+ public function setRawCollection(array $collection): void
+ {
+ $this->collection = [];
+ $this->cache = [];
+ foreach ($collection as $keyValue) {
+ $this->collection[$keyValue->getKey()] = $keyValue;
+ }
+ }
+
+ /**
+ * @inheritdoc
+ * @param KeyValue $keyValue
+ * @return KeyValue
+ */
+ public function compileKeyValue(KeyValue $keyValue): KeyValue
+ {
+ $newValue = preg_replace_callback(self::REGEX_VARIABLE, function ($variable) use ($keyValue) {
+ $variable = $variable[1];
+ if ($variable === $keyValue->getKey()) {
+ throw new RuntimeException('Self referencing');
+ }
+ if (isset($this->cache[$variable])) {
+ return $this->cache[$variable]->getValue();
+ } elseif (isset($this->collection[$variable]) && !$this->needToCompile($this->collection[$variable])) {
+ return $this->collection[$variable]->getValue();
+ } elseif (isset($this->collection[$variable]) && $this->needToCompile($this->collection[$variable])) {
+ return $this->compileKeyValue($this->collection[$variable])->getValue();
+ }
+ return "UNKNOWN VARIABLE {$variable}";
+ }, $keyValue->getValue());
+ $result = new KeyValue($keyValue->getKey(), $newValue);
+ $this->cache[$result->getKey()] = $result;
+
+ return $result;
+ }
+
+ /**
+ * @param KeyValue $keyValue
+ * @return bool
+ */
+ protected function needToCompile(KeyValue $keyValue): bool
+ {
+ return !!preg_match(self::REGEX_VARIABLE, $keyValue->getValue());
+ }
+} \ No newline at end of file
diff --git a/src/Compiler/CompilerInterface.php b/src/Compiler/CompilerInterface.php
index 042a7d0..15b6823 100644
--- a/src/Compiler/CompilerInterface.php
+++ b/src/Compiler/CompilerInterface.php
@@ -1,4 +1,6 @@
<?php
+declare(strict_types=1);
+
/**
* @author: Alexander Kiryukhin <alexander@kiryukhin.su>
* @license: MIT
@@ -8,16 +10,20 @@ namespace NeonXP\Dotenv\Compiler;
use NeonXP\Dotenv\Types\KeyValue;
+/**
+ * Interface CompilerInterface
+ * @package NeonXP\Dotenv\Compiler
+ */
interface CompilerInterface
{
/**
* @param KeyValue[] $collection
*/
- function setRawCollection(array $collection): void;
+ public function setRawCollection(array $collection): void;
/**
* @param KeyValue $keyValue
* @return KeyValue
*/
- function compileKeyValue(KeyValue $keyValue): KeyValue;
+ public function compileKeyValue(KeyValue $keyValue): KeyValue;
} \ No newline at end of file
diff --git a/src/Dotenv.php b/src/Dotenv.php
index 8e7ac10..3f3b0c6 100644
--- a/src/Dotenv.php
+++ b/src/Dotenv.php
@@ -1,4 +1,6 @@
<?php
+declare(strict_types=1);
+
/**
* @author: Alexander Kiryukhin <alexander@kiryukhin.su>
* @license: MIT
@@ -8,10 +10,16 @@ namespace NeonXP\Dotenv;
use NeonXP\Dotenv\Compiler\CompilerInterface;
use NeonXP\Dotenv\Exception\RuntimeException;
+use NeonXP\Dotenv\Loader\FileLoader;
use NeonXP\Dotenv\Loader\LoaderInterface;
+use NeonXP\Dotenv\Parser\Parser;
use NeonXP\Dotenv\Parser\ParserInterface;
use NeonXP\Dotenv\Types\KeyValue;
+/**
+ * Class Dotenv
+ * @package NeonXP\Dotenv
+ */
class Dotenv implements \ArrayAccess, \IteratorAggregate
{
/**
@@ -40,6 +48,13 @@ class Dotenv implements \ArrayAccess, \IteratorAggregate
*/
public function __construct(LoaderInterface $loader = null, ParserInterface $parser = null, CompilerInterface $compiler = null)
{
+ if (!$loader) {
+ $loader = new FileLoader(); // Default loader
+ }
+ if (!$parser) {
+ $parser = new Parser(); // Default parser
+ }
+
$this->loader = $loader;
$this->parser = $parser;
$this->compiler = $compiler;
@@ -63,6 +78,10 @@ class Dotenv implements \ArrayAccess, \IteratorAggregate
},
[]
);
+ foreach ($this->loadedValues as $key => $value) {
+ $_ENV[$key] = $value;
+ putenv($key . "=" . $value);
+ }
return $this;
}
@@ -85,7 +104,7 @@ class Dotenv implements \ArrayAccess, \IteratorAggregate
* @return mixed
* @throws RuntimeException
*/
- public function get(string $key, mixed $default = null): mixed
+ public function get(string $key, $default = null)
{
if (!$this->has($key)) {
return $default;
@@ -122,7 +141,7 @@ class Dotenv implements \ArrayAccess, \IteratorAggregate
* @return bool
* @throws RuntimeException
*/
- public function offsetExists($offset)
+ public function offsetExists($offset): bool
{
return $this->has($offset);
}
diff --git a/src/Exception/RuntimeException.php b/src/Exception/RuntimeException.php
index 1a9be9c..5728623 100644
--- a/src/Exception/RuntimeException.php
+++ b/src/Exception/RuntimeException.php
@@ -1,4 +1,6 @@
<?php
+declare(strict_types=1);
+
/**
* @author: Alexander Kiryukhin <alexander@kiryukhin.su>
* @license: MIT
@@ -6,7 +8,10 @@
namespace NeonXP\Dotenv\Exception;
-
+/**
+ * Class RuntimeException
+ * @package NeonXP\Dotenv\Exception
+ */
class RuntimeException extends \Exception
{
diff --git a/src/Loader/FileLoader.php b/src/Loader/FileLoader.php
new file mode 100644
index 0000000..0702a53
--- /dev/null
+++ b/src/Loader/FileLoader.php
@@ -0,0 +1,41 @@
+<?php
+declare(strict_types=1);
+
+/**
+ * @author: Alexander Kiryukhin <alexander@kiryukhin.su>
+ * @license: MIT
+ */
+
+namespace NeonXP\Dotenv\Loader;
+
+use NeonXP\Dotenv\Exception\RuntimeException;
+
+/**
+ * Class FileLoader
+ * @package NeonXP\Dotenv\Loader
+ */
+class FileLoader implements LoaderInterface
+{
+ const COMMENT_LINE_REGEX = '/^\s*#/';
+
+ /**
+ * @inheritdoc
+ * @param string $filePath
+ * @return array
+ * @throws RuntimeException
+ */
+ public function load(string $filePath = '.env'): array
+ {
+ if (!file_exists($filePath)) {
+ throw new RuntimeException("There is no {$filePath} file!");
+ }
+ $lines = file($filePath);
+ $lines = array_map('trim', $lines);
+ $lines = array_filter($lines, function (string $line) {
+ return trim($line) && !preg_match(self::COMMENT_LINE_REGEX, $line);
+ });
+ $lines = array_values($lines);
+
+ return $lines;
+ }
+} \ No newline at end of file
diff --git a/src/Loader/LoaderInterface.php b/src/Loader/LoaderInterface.php
index 1c4f166..c848e6c 100644
--- a/src/Loader/LoaderInterface.php
+++ b/src/Loader/LoaderInterface.php
@@ -1,4 +1,6 @@
<?php
+declare(strict_types=1);
+
/**
* @author: Alexander Kiryukhin <alexander@kiryukhin.su>
* @license: MIT
@@ -6,9 +8,14 @@
namespace NeonXP\Dotenv\Loader;
+/**
+ * Interface LoaderInterface
+ * @package NeonXP\Dotenv\Loader
+ */
interface LoaderInterface
{
/**
+ * Load not empty lines from file or other source
* @param string $filePath
* @return string[]
*/
diff --git a/src/Parser/Parser.php b/src/Parser/Parser.php
new file mode 100644
index 0000000..7a5c37b
--- /dev/null
+++ b/src/Parser/Parser.php
@@ -0,0 +1,55 @@
+<?php
+declare(strict_types=1);
+
+/**
+ * @author: Alexander Kiryukhin <alexander@kiryukhin.su>
+ * @license: MIT
+ */
+
+namespace NeonXP\Dotenv\Parser;
+
+use NeonXP\Dotenv\Types\KeyValue;
+
+/**
+ * Class Parser
+ * @package NeonXP\Dotenv\Parser
+ */
+class Parser implements ParserInterface
+{
+ const REGEX_EXPORT_PREFIX = '/^\s*export\s/i';
+
+ // Quotes and comments
+ const SINGLE_QUOTED_LINE_WITH_COMMENT = '/^\'(.*?)\'\s+#.*?$/i';
+ const DOUBLE_QUOTED_LINE_WITH_COMMENT = '/^\"(.+?)\"\s+#.*?$/i';
+ const SINGLE_QUOTED_LINE = '/^\'(.+?)\'$/i';
+ const DOUBLE_QUOTED_LINE = '/^\"(.*?)\"$/i';
+
+ // Types
+ const BOOLEAN = '/^(true|false)$/i';
+ const NUMBER = '/^(\d+)$/';
+
+ public function parseLine(string $line): KeyValue
+ {
+ $line = preg_replace(self::REGEX_EXPORT_PREFIX, '', $line);
+ list($key, $value) = explode('=', $line, 2) + ['', ''];
+ $key = trim($key);
+ $value = trim($value);
+ $matches = [];
+ if (
+ preg_match(self::SINGLE_QUOTED_LINE_WITH_COMMENT, $value, $matches) ||
+ preg_match(self::DOUBLE_QUOTED_LINE_WITH_COMMENT, $value, $matches) ||
+ preg_match(self::SINGLE_QUOTED_LINE, $value, $matches) ||
+ preg_match(self::DOUBLE_QUOTED_LINE, $value, $matches)
+ ) {
+ $value = $matches[1];
+ }
+
+ if (preg_match(self::BOOLEAN, $value)) {
+ $value = (strtolower($value) === 'true');
+ } elseif (preg_match(self::NUMBER, $value)) {
+ $value = intval($value);
+ }
+
+ return new KeyValue($key, $value);
+ }
+} \ No newline at end of file
diff --git a/src/Parser/ParserInterface.php b/src/Parser/ParserInterface.php
index b53e29f..f67ffb5 100644
--- a/src/Parser/ParserInterface.php
+++ b/src/Parser/ParserInterface.php
@@ -1,4 +1,6 @@
<?php
+declare(strict_types=1);
+
/**
* @author: Alexander Kiryukhin <alexander@kiryukhin.su>
* @license: MIT
@@ -8,6 +10,10 @@ namespace NeonXP\Dotenv\Parser;
use NeonXP\Dotenv\Types\KeyValue;
+/**
+ * Interface ParserInterface
+ * @package NeonXP\Dotenv\Parser
+ */
interface ParserInterface
{
/**
diff --git a/src/Types/KeyValue.php b/src/Types/KeyValue.php
index e17dc4d..54b0360 100644
--- a/src/Types/KeyValue.php
+++ b/src/Types/KeyValue.php
@@ -1,4 +1,6 @@
<?php
+declare(strict_types=1);
+
/**
* @author: Alexander Kiryukhin <alexander@kiryukhin.su>
* @license: MIT
@@ -6,7 +8,10 @@
namespace NeonXP\Dotenv\Types;
-
+/**
+ * Class KeyValue
+ * @package NeonXP\Dotenv\Types
+ */
class KeyValue
{
/**
@@ -24,7 +29,7 @@ class KeyValue
* @param string $key
* @param mixed $value
*/
- public function __construct(string $key, mixed $value)
+ public function __construct(string $key, $value)
{
$this->key = $key;
$this->value = $value;
@@ -41,7 +46,7 @@ class KeyValue
/**
* @return mixed
*/
- public function getValue(): mixed
+ public function getValue()
{
return $this->value;
}