Passed
Push — master ( 8055a6...9f064f )
by Enjoys
13:37
created

Dotenv::getEnvRawArray()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
6
namespace Enjoys\Dotenv;
7
8
use Webmozart\Assert\Assert;
9
10
class Dotenv
11
{
12
    private string $baseDirectory;
13
    /**
14
     * @var string[]
15
     */
16
    private array $envRawArray = [];
17
    private array $envArray = [];
18
19 23
    public function __construct(
20
        string $baseDirectory,
21
        private string $envFilename = '.env',
22
        private string $distEnvFilename = '.env.dist'
23
    ) {
24 23
        $this->baseDirectory = rtrim($baseDirectory, "/") . DIRECTORY_SEPARATOR;
25
    }
26
27 22
    public function loadEnv(bool $usePutEnv = false): void
28
    {
29 22
        $this->doMerge($this->getGeneralPaths());
30 21
        $this->doMerge($this->getExtraPaths());
31 21
        $this->doLoad($usePutEnv);
32
    }
33
34
    /**
35
     * @return string[]
36
     */
37 21
    private function getExtraPaths(): array
38
    {
39 21
        $env = (getenv('APP_ENV') ?: null) ?? $this->envRawArray['APP_ENV'] ?? null;
40
41 21
        if ($env === '' || $env === null) {
42 15
            return [];
43
        }
44 6
        $path = realpath($this->baseDirectory . $this->envFilename . '.' . $env);
45
46 6
        if ($path === false) {
47 1
            return [];
48
        }
49
50 5
        return [$path];
51
    }
52
53
    /**
54
     * @return string[]
55
     */
56 22
    private function getGeneralPaths(): array
57
    {
58 22
        $paths = [
59 22
            realpath($this->baseDirectory . $this->distEnvFilename),
60 22
            realpath($this->baseDirectory . $this->envFilename)
61
        ];
62
63 22
        return array_filter($paths, function ($item) {
64 22
            return is_string($item);
65
        });
66
    }
67
68
    /**
69
     * @param string[] $array
70
     */
71 22
    private function doMerge(array $array): void
72
    {
73 22
        foreach ($array as $path) {
74 22
            $this->envRawArray = array_merge($this->envRawArray, $this->getArrayData($path));
75
        }
76
    }
77
78
    /**
79
     * @return string[]
80
     */
81 22
    private function getArrayData(string $path): array
82
    {
83 22
        $result = [];
84
85 22
        $data = file_get_contents($path);
86
87
        /**
88
         * @var string $key
89
         * @var string $value
90
         */
91 22
        foreach ($this->parseToArray($data) as $key => $value) {
92 21
            $result[$key] = $value;
93
        }
94 21
        return $result;
95
    }
96
97
98 22
    private function parseToArray(string $input): \Generator
99
    {
100 22
        foreach (preg_split("/\R/", $input) as $line) {
101 22
            $line = trim($line);
102
103 22
            if ($this->isComment($line)) {
104 4
                continue;
105
            }
106 22
            if (empty($line)) {
107 9
                continue;
108
            }
109
110 22
            $fields = array_map('trim', explode('=', $line, 2));
111 22
            $fields[1] ??= null;
112
113 22
            [$key, $value] = $fields;
114
            /** @psalm-suppress PossiblyNullArgument*/
115 22
            Assert::regex(
116
                $key,
117
                '/^([A-Z_0-9]+)$/i',
118
                'The key %s have invalid chars. The key must have only letters (A-Z) digits (0-9) and _'
119
            );
120
121 21
            yield $key => $this->parseValue($value);
122
        }
123
    }
124
125
126 21
    private function doLoad(bool $usePutEnv): void
127
    {
128
        /** @var string $key */
129 21
        foreach ($this->envRawArray as $key => $value) {
130 21
            $value = ValuesHandler::quotes($value);
131 21
            $value = ValuesHandler::handleVariables($key, $value, $this);
132
133 21
            $value = stripslashes($value);
134
135 21
            if (getenv($key)) {
136 5
                $value = getenv($key);
137
            }
138
139
            /** @var string $value */
140 21
            $_ENV[$key] = ValuesHandler::cast($value);
141
142 16
            if (!getenv($key) && $usePutEnv === true) {
143 1
                putenv("$key=$value");
144
            }
145
146 16
            $this->envArray[$key] = $_ENV[$key];
147
        }
148
    }
149
150 22
    private function isComment(string $line): bool
151
    {
152 22
        return str_starts_with($line, '#');
153
    }
154
155 21
    private function parseValue(?string $value): string
156
    {
157 21
        if ($value === null) {
158 1
            return '*null';
159
        }
160
161 21
        preg_match('/^([\'"])((?<value>.*?)(?<!\\\\)\1)/', $value, $matches);
162 21
        if (isset($matches['value'])) {
163 9
            return $matches['value'];
164
        }
165 20
        return array_map('trim', explode('#', $value, 2))[0];
166
    }
167
168
    /**
169
     * @return string[]
170
     */
171 9
    public function getEnvRawArray(): array
172
    {
173 9
        return $this->envRawArray;
174
    }
175
176 1
    public function getEnvArray(): array
177
    {
178 1
        return $this->envArray;
179
    }
180
181
}