Skip to content

Commit 99f3dec

Browse files
authored
Merge pull request #84 from mtolhuys/master
Add check for empty environmental variables
2 parents f046142 + 5436de5 commit 99f3dec

File tree

5 files changed

+462
-229
lines changed

5 files changed

+462
-229
lines changed

config/config.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@
2929
],
3030
\BeyondCode\SelfDiagnosis\Checks\EnvFileExists::class,
3131
\BeyondCode\SelfDiagnosis\Checks\ExampleEnvironmentVariablesAreSet::class,
32+
\BeyondCode\SelfDiagnosis\Checks\UsedEnvironmentVariablesAreDefined::class => [
33+
'directories' => [
34+
config_path(),
35+
app_path(),
36+
],
37+
],
3238
\BeyondCode\SelfDiagnosis\Checks\LocalesAreInstalled::class => [
3339
'required_locales' => [
3440
'en_US',
@@ -65,6 +71,7 @@
6571
\BeyondCode\SelfDiagnosis\Checks\ConfigurationIsNotCached::class,
6672
\BeyondCode\SelfDiagnosis\Checks\RoutesAreNotCached::class,
6773
\BeyondCode\SelfDiagnosis\Checks\ExampleEnvironmentVariablesAreUpToDate::class,
74+
\BeyondCode\SelfDiagnosis\Checks\UsedEnvironmentVariablesAreDefined::class,
6875
],
6976
'production' => [
7077
\BeyondCode\SelfDiagnosis\Checks\ComposerWithoutDevDependenciesIsUpToDate::class,
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
<?php
2+
3+
namespace BeyondCode\SelfDiagnosis\Checks;
4+
5+
use Illuminate\Support\Arr;
6+
use Illuminate\Support\Collection;
7+
use RecursiveDirectoryIterator;
8+
use RecursiveIteratorIterator;
9+
use RegexIterator;
10+
11+
class UsedEnvironmentVariablesAreDefined implements Check
12+
{
13+
/**
14+
* Stores processed var names
15+
*
16+
* @var array
17+
*/
18+
private $processed = [];
19+
20+
/**
21+
* Stores undefined var names
22+
*
23+
* @var array
24+
*/
25+
public $undefined = [];
26+
27+
/**
28+
* The amount of undefined .env variables
29+
*
30+
* @var integer
31+
*/
32+
public $amount = 0;
33+
34+
/**
35+
* The name of the check.
36+
*
37+
* @param array $config
38+
* @return string
39+
*/
40+
public function name(array $config): string
41+
{
42+
return trans('self-diagnosis::checks.used_env_variables_are_defined.name');
43+
}
44+
45+
/**
46+
* The error message to display in case the check does not pass.
47+
*
48+
* @param array $config
49+
* @return string
50+
*/
51+
public function message(array $config): string
52+
{
53+
return trans('self-diagnosis::checks.used_env_variables_are_defined.message', [
54+
'amount' => $this->amount,
55+
'undefined' => implode(PHP_EOL, $this->undefined),
56+
]);
57+
}
58+
59+
/**
60+
* Perform the actual verification of this check.
61+
*
62+
* @param array $config
63+
* @return bool
64+
* @throws \Exception
65+
*/
66+
public function check(array $config): bool
67+
{
68+
$paths = Collection::make(Arr::get($config, 'directories', []));
69+
70+
foreach ($paths as $path) {
71+
$files = $this->recursiveDirSearch($path, '/.*?.php/');
72+
73+
foreach ($files as $file) {
74+
preg_match_all(
75+
'# env\((.*?)\)| getenv\((.*?)\)#',
76+
str_replace(["\n", "\r"], '', file_get_contents($file)),
77+
$values
78+
);
79+
80+
$values = array_filter(
81+
array_merge($values[1], $values[2])
82+
);
83+
84+
foreach ($values as $value) {
85+
$result = $this->getResult(
86+
explode(',', str_replace(["'", '"', ' '], '', $value))
87+
);
88+
89+
if (!$result) {
90+
continue;
91+
}
92+
93+
$this->storeResult($result);
94+
}
95+
}
96+
}
97+
98+
return $this->amount === 0;
99+
}
100+
101+
/**
102+
* Get result based on comma separated env() or getenv() parameters
103+
*
104+
* @param array $values
105+
* @return object|bool
106+
*/
107+
private function getResult(array $values)
108+
{
109+
$envVar = $values[0];
110+
111+
if (in_array($envVar, $this->processed, true)) {
112+
return false;
113+
}
114+
115+
$this->processed[] = $envVar;
116+
117+
return (object)[
118+
'envVar' => $envVar,
119+
'hasValue' => env($envVar) !== null,
120+
'hasDefault' => isset($values[1]),
121+
];
122+
}
123+
124+
/**
125+
* Store result based on getResult's return value
126+
*
127+
* @param $result
128+
*/
129+
private function storeResult($result)
130+
{
131+
if (!$result->hasValue && !$result->hasDefault) {
132+
$this->undefined[] = $result->envVar;
133+
$this->amount++;
134+
}
135+
}
136+
137+
/**
138+
* Recursively search folder(s) for files matching pattern
139+
*
140+
* @param string $folder
141+
* @param string $pattern
142+
* @return array
143+
*/
144+
private function recursiveDirSearch(string $folder, string $pattern): array
145+
{
146+
if (!file_exists($folder)) {
147+
return [];
148+
}
149+
150+
$files = new RegexIterator(
151+
new RecursiveIteratorIterator(
152+
new RecursiveDirectoryIterator($folder)
153+
),
154+
$pattern, RegexIterator::GET_MATCH
155+
);
156+
157+
$list = [[]];
158+
159+
foreach ($files as $file) {
160+
$list[] = $file;
161+
}
162+
163+
$list = array_merge(...$list);
164+
165+
return $list;
166+
}
167+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
namespace BeyondCode\SelfDiagnosis\Tests;
4+
5+
use BeyondCode\SelfDiagnosis\Checks\UsedEnvironmentVariablesAreDefined;
6+
use BeyondCode\SelfDiagnosis\SelfDiagnosisServiceProvider;
7+
use Orchestra\Testbench\TestCase;
8+
9+
class UsedEnvironmentVariablesAreDefinedTest extends TestCase
10+
{
11+
public function getPackageProviders($app)
12+
{
13+
return [
14+
SelfDiagnosisServiceProvider::class,
15+
];
16+
}
17+
18+
/** @test
19+
* @throws \Exception
20+
*/
21+
public function it_checks_if_used_env_vars_are_defined()
22+
{
23+
env('FILLED');
24+
env('NOT_FILLED');
25+
env('FILLED_WITH_FALSE');
26+
getenv('GET_FILLED');
27+
28+
env('DEPENDING_ON_DEFAULT', 'default');
29+
env('DEFAULT_IS_FALSE', false);
30+
getenv('GET_DEPENDING_ON_DEFAULT', 'default');
31+
32+
env('UNDEFINED');
33+
getenv('GET_UNDEFINED');
34+
// Doubles should be ignored
35+
env('UNDEFINED');
36+
getenv('GET_UNDEFINED');
37+
38+
$config = [
39+
'directories' => [
40+
__DIR__
41+
],
42+
];
43+
44+
$check = new UsedEnvironmentVariablesAreDefined();
45+
46+
$this->assertFalse($check->check($config));
47+
$this->assertSame($check->amount, 2);
48+
$this->assertContains('UNDEFINED', $check->undefined);
49+
$this->assertContains('GET_UNDEFINED', $check->undefined);
50+
$this->assertSame(
51+
"2 used environmental variables are undefined: \nUNDEFINED\nGET_UNDEFINED",
52+
$check->message($config)
53+
);
54+
}
55+
}

0 commit comments

Comments
 (0)