Skip to content

Commit 3484227

Browse files
committed
special chars, quotes fix, key name validation & tests
1 parent f861b9d commit 3484227

File tree

7 files changed

+111
-21
lines changed

7 files changed

+111
-21
lines changed

src/Commands/EnvGetCommand.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@ public function handle()
8585
private function _getEntireEnvContent()
8686
{
8787
return ($this->json) ? json_encode($this->env->getVariables()) : $this->env->getEnvContent();
88-
;
8988
}
9089

9190
private function _printKeyValue()
@@ -104,7 +103,7 @@ private function _printOutput(): void
104103
}
105104

106105
if (strlen($this->key) && $this->env->exists($this->key)) {
107-
$this->line($this->_printKeyValue());
106+
$this->output->writeln($this->_printKeyValue());
108107
} else {
109108
$this->line("There is no variable '{$this->key}'");
110109
}

src/Commands/EnvSetCommand.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,11 @@ public function handle()
5252
$this->info("Environment variable with key '{$key}' has been set to '{$value}'");
5353
} catch (\InvalidArgumentException $e) {
5454
$this->error($e->getMessage());
55+
56+
return 1;
5557
}
5658

57-
return;
59+
return 0;
5860
}
5961

6062

src/Commands/Traits/CommandValidator.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66

77
trait CommandValidator
88
{
9+
10+
private $invalidKeyException = 'Invalid environment key. Only use upper letters, digits, and underscores. A variable must start with the letter.';
11+
912
/**
1013
* Check if a given string is valid as an environment variable key.
1114
*
@@ -14,8 +17,8 @@ trait CommandValidator
1417
*/
1518
protected function isValidKey(string $key): bool
1619
{
17-
if (!preg_match('/^[a-zA-Z_0-9]+$/', $key)) {
18-
throw new InvalidArgumentException('Invalid environment key. Only use digits, letters and underscores');
20+
if (!preg_match('/^[A-Z_]\w*$/', $key)) {
21+
throw new InvalidArgumentException($this->invalidKeyException);
1922
}
2023

2124
return true;

src/Env.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ private function _parse(): void
2727

2828
foreach ($env_lines as $line) {
2929
if (strlen(trim($line)) && !(strpos(trim($line), '#') === 0)) {
30-
[$key, $val] = explode('=', (string)$line);
30+
[$key, $val] = explode('=', (string)$line, 2);
3131
$this->_envVars[$key] = $this->_stripValue($val);
3232
}
3333
}
@@ -152,11 +152,11 @@ private function _preg_quote_except(string $str, string $exclude, ?string $delim
152152
*/
153153
private function _prepareValue(string $value): string
154154
{
155-
if (false !== strpos($value, ' ') || (strlen($value) && in_array($value[0], ['=', '$']))) {
155+
if (false !== strpos($value, ' ')) {
156156
$value = '"' . $value . '"';
157157
}
158158

159-
return $this->_preg_quote_except($value, ':.-');
159+
return $this->_preg_quote_except($value, ':.-+=');
160160
}
161161

162162
private function _stripQuotes(string $value): string
@@ -173,7 +173,7 @@ private function _stripValue(string $value): string
173173
{
174174
$val = trim(explode('#', trim($value))[0]);
175175

176-
return stripslashes($this->_stripQuotes($val));
176+
return $this->_stripQuotes($val);
177177
}
178178

179179
/**

tests/.env.example

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,5 @@ PUSHER_APP_CLUSTER=mt1
5353
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
5454
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
5555

56-
dummy_variable="Adf4$r-Ac\""
56+
DUMMY_VARIABLE="Adf4$r-Ac\""
57+

tests/EnvArtisanTest.php

Lines changed: 92 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99

1010
final class EnvArtisanTest extends TestCase
1111
{
12-
private $env_vars_empty = ['APP_NAME', 'APP_ENV', 'APP_KEY', 'APP_DEBUG', 'APP_URL', 'LOG_CHANNEL', 'DB_CONNECTION', 'DB_HOST', 'DB_PORT', 'DB_DATABASE', 'DB_USERNAME', 'DB_PASSWORD', 'BROADCAST_DRIVER', 'CACHE_DRIVER', 'QUEUE_CONNECTION', 'SESSION_DRIVER', 'SESSION_LIFETIME', 'REDIS_HOST', 'REDIS_PASSWORD', 'REDIS_PORT', 'MAIL_MAILER', 'MAIL_HOST', 'MAIL_PORT', 'MAIL_USERNAME', 'MAIL_PASSWORD', 'MAIL_ENCRYPTION', 'MAIL_FROM_ADDRESS', 'MAIL_FROM_NAME', 'AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY', 'AWS_DEFAULT_REGION', 'AWS_BUCKET', 'PUSHER_APP_ID', 'PUSHER_APP_KEY', 'PUSHER_APP_SECRET', 'PUSHER_APP_CLUSTER', 'MIX_PUSHER_APP_KEY', 'MIX_PUSHER_APP_CLUSTER', 'dummy_variable'];
13-
private $_env_vars = ['APP_NAME' => 'Laravel', 'APP_ENV' => 'local', 'APP_KEY' => '', 'APP_DEBUG' => 'true', 'APP_URL' => 'http://localhost', 'LOG_CHANNEL' => 'stack', 'DB_CONNECTION' => 'mysql', 'DB_HOST' => '127.0.0.1', 'DB_PORT' => '3306', 'DB_DATABASE' => 'laravel', 'DB_USERNAME' => 'root', 'DB_PASSWORD' => '', 'BROADCAST_DRIVER' => 'log', 'CACHE_DRIVER' => 'file', 'QUEUE_CONNECTION' => 'sync', 'SESSION_DRIVER' => 'file', 'SESSION_LIFETIME' => '120', 'REDIS_HOST' => '127.0.0.1', 'REDIS_PASSWORD' => 'null', 'REDIS_PORT' => '6379', 'MAIL_MAILER' => 'smtp', 'MAIL_HOST' => 'smtp.mailtrap.io', 'MAIL_PORT' => '2525', 'MAIL_USERNAME' => 'null', 'MAIL_PASSWORD' => 'null', 'MAIL_ENCRYPTION' => 'null', 'MAIL_FROM_ADDRESS' => 'null', 'MAIL_FROM_NAME' => '${APP_NAME}', 'AWS_ACCESS_KEY_ID' => '', 'AWS_SECRET_ACCESS_KEY' => '', 'AWS_DEFAULT_REGION' => 'us-east-1', 'AWS_BUCKET' => '', 'PUSHER_APP_ID' => '', 'PUSHER_APP_KEY' => '', 'PUSHER_APP_SECRET' => '', 'PUSHER_APP_CLUSTER' => 'mt1', 'MIX_PUSHER_APP_KEY' => '${PUSHER_APP_KEY}', 'MIX_PUSHER_APP_CLUSTER' => '${PUSHER_APP_CLUSTER}', 'dummy_variable' => 'Adf4$r-Ac"'];
12+
private $env_vars_empty = ['APP_NAME', 'APP_ENV', 'APP_KEY', 'APP_DEBUG', 'APP_URL', 'LOG_CHANNEL', 'DB_CONNECTION', 'DB_HOST', 'DB_PORT', 'DB_DATABASE', 'DB_USERNAME', 'DB_PASSWORD', 'BROADCAST_DRIVER', 'CACHE_DRIVER', 'QUEUE_CONNECTION', 'SESSION_DRIVER', 'SESSION_LIFETIME', 'REDIS_HOST', 'REDIS_PASSWORD', 'REDIS_PORT', 'MAIL_MAILER', 'MAIL_HOST', 'MAIL_PORT', 'MAIL_USERNAME', 'MAIL_PASSWORD', 'MAIL_ENCRYPTION', 'MAIL_FROM_ADDRESS', 'MAIL_FROM_NAME', 'AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY', 'AWS_DEFAULT_REGION', 'AWS_BUCKET', 'PUSHER_APP_ID', 'PUSHER_APP_KEY', 'PUSHER_APP_SECRET', 'PUSHER_APP_CLUSTER', 'MIX_PUSHER_APP_KEY', 'MIX_PUSHER_APP_CLUSTER', 'DUMMY_VARIABLE'];
13+
private $_env_vars = ['APP_NAME' => 'Laravel', 'APP_ENV' => 'local', 'APP_KEY' => '', 'APP_DEBUG' => 'true', 'APP_URL' => 'http://localhost', 'LOG_CHANNEL' => 'stack', 'DB_CONNECTION' => 'mysql', 'DB_HOST' => '127.0.0.1', 'DB_PORT' => '3306', 'DB_DATABASE' => 'laravel', 'DB_USERNAME' => 'root', 'DB_PASSWORD' => '', 'BROADCAST_DRIVER' => 'log', 'CACHE_DRIVER' => 'file', 'QUEUE_CONNECTION' => 'sync', 'SESSION_DRIVER' => 'file', 'SESSION_LIFETIME' => '120', 'REDIS_HOST' => '127.0.0.1', 'REDIS_PASSWORD' => 'null', 'REDIS_PORT' => '6379', 'MAIL_MAILER' => 'smtp', 'MAIL_HOST' => 'smtp.mailtrap.io', 'MAIL_PORT' => '2525', 'MAIL_USERNAME' => 'null', 'MAIL_PASSWORD' => 'null', 'MAIL_ENCRYPTION' => 'null', 'MAIL_FROM_ADDRESS' => 'null', 'MAIL_FROM_NAME' => '${APP_NAME}', 'AWS_ACCESS_KEY_ID' => '', 'AWS_SECRET_ACCESS_KEY' => '', 'AWS_DEFAULT_REGION' => 'us-east-1', 'AWS_BUCKET' => '', 'PUSHER_APP_ID' => '', 'PUSHER_APP_KEY' => '', 'PUSHER_APP_SECRET' => '', 'PUSHER_APP_CLUSTER' => 'mt1', 'MIX_PUSHER_APP_KEY' => '${PUSHER_APP_KEY}', 'MIX_PUSHER_APP_CLUSTER' => '${PUSHER_APP_CLUSTER}', 'DUMMY_VARIABLE' => 'Adf4$r-Ac\"'];
1414

1515
public function setUp(): void
1616
{
@@ -99,11 +99,11 @@ public function testEnvArtisanSetAllKeyValueArgs(): void
9999
}
100100

101101
foreach ($this->env_vars_empty as $key => $val) {
102-
$this->artisan('env:set', ['key' => $key, 'value' => $val])
103-
->expectsOutput("Environment variable with key '{$key}' has been set to '{$val}'")
102+
$this->artisan('env:set', ['key' => 'A_' . $key, 'value' => $val])
103+
->expectsOutput("Environment variable with key 'A_{$key}' has been set to '{$val}'")
104104
->assertExitCode(0);
105105

106-
$this->artisan('env:get', ['key' => $key])
106+
$this->artisan('env:get', ['key' => 'A_' . $key])
107107
->expectsOutput($val)
108108
->assertExitCode(0);
109109
}
@@ -116,11 +116,11 @@ public function testEnvArtisanSetAllKeyEqualsValueArgs(): void
116116
}
117117

118118
foreach ($this->env_vars_empty as $key => $val) {
119-
$this->artisan('env:set', ['key' => $key .'=' .$val])
120-
->expectsOutput("Environment variable with key '{$key}' has been set to '{$val}'")
119+
$this->artisan('env:set', ['key' => 'A_' . $key .'=' .$val])
120+
->expectsOutput("Environment variable with key 'A_{$key}' has been set to '{$val}'")
121121
->assertExitCode(0);
122122

123-
$this->artisan('env:get', ['key' => $key])
123+
$this->artisan('env:get', ['key' => 'A_' . $key])
124124
->expectsOutput($val)
125125
->assertExitCode(0);
126126
}
@@ -177,4 +177,88 @@ public function testSetValueWithHyphen(): void
177177
->expectsOutput($app_name)
178178
->assertExitCode(0);
179179
}
180+
181+
public function testSetSpecialCharacters(): void
182+
{
183+
$app_key = '=t+++=.,hHya:df';
184+
185+
$this->artisan('env:set', ['key' => 'APP_KEY' .'=' . $app_key])
186+
->expectsOutput("Environment variable with key 'APP_KEY' has been set to '{$app_key}'")
187+
->assertExitCode(0);
188+
189+
$this->artisan('env:get', ['key' => 'APP_KEY'])
190+
->expectsOutput($app_key)
191+
->assertExitCode(0);
192+
}
193+
194+
public function testSetSpecialCharactersExtended(): void
195+
{
196+
$app_key = '1"=t+++/\\//\=.,h\"Hya:df';
197+
198+
$this->artisan('env:set', ['key' => 'APP_KEY' .'=' . $app_key])
199+
->expectsOutput("Environment variable with key 'APP_KEY' has been set to '{$app_key}'")
200+
->assertExitCode(0);
201+
202+
$this->artisan('env:get', ['key' => 'APP_KEY'])
203+
->expectsOutput($app_key)
204+
->assertExitCode(0);
205+
}
206+
207+
public function testKeyNames(): void
208+
{
209+
$valid_key1 = 'A';
210+
$valid_key2 = 'ABC';
211+
$valid_key3 = 'ABC123';
212+
$valid_key4 = 'ABC_123';
213+
$valid_key5 = '_ABC__123';
214+
215+
$this->artisan('env:set', ['key' => $valid_key1 .'=testvalue'])
216+
->expectsOutput("Environment variable with key '$valid_key1' has been set to 'testvalue'")
217+
->assertExitCode(0);
218+
219+
$this->artisan('env:set', ['key' => $valid_key2 .'=testvalue'])
220+
->expectsOutput("Environment variable with key '$valid_key2' has been set to 'testvalue'")
221+
->assertExitCode(0);
222+
223+
$this->artisan('env:set', ['key' => $valid_key3 .'=testvalue'])
224+
->expectsOutput("Environment variable with key '$valid_key3' has been set to 'testvalue'")
225+
->assertExitCode(0);
226+
227+
$this->artisan('env:set', ['key' => $valid_key4 .'=testvalue'])
228+
->expectsOutput("Environment variable with key '$valid_key4' has been set to 'testvalue'")
229+
->assertExitCode(0);
230+
231+
$this->artisan('env:set', ['key' => $valid_key5 .'=testvalue'])
232+
->expectsOutput("Environment variable with key '$valid_key5' has been set to 'testvalue'")
233+
->assertExitCode(0);
234+
235+
236+
$invalid_key1 = '1';
237+
$invalid_key2 = '123';
238+
$invalid_key3 = 'TEST KEY';
239+
$invalid_key4 = 'test';
240+
$invalid_key5 = 'test_key';
241+
242+
243+
$this->artisan('env:set', ['key' => $invalid_key1 .'=testvalue'])
244+
->expectsOutput('Invalid environment key. Only use upper letters, digits, and underscores. A variable must start with the letter.')
245+
->assertExitCode(1);
246+
247+
$this->artisan('env:set', ['key' => $invalid_key2 .'=testvalue'])
248+
->expectsOutput('Invalid environment key. Only use upper letters, digits, and underscores. A variable must start with the letter.')
249+
->assertExitCode(1);
250+
251+
$this->artisan('env:set', ['key' => $invalid_key3 .'=testvalue'])
252+
->expectsOutput('Invalid environment key. Only use upper letters, digits, and underscores. A variable must start with the letter.')
253+
->assertExitCode(1);
254+
255+
$this->artisan('env:set', ['key' => $invalid_key4 .'=testvalue'])
256+
->expectsOutput('Invalid environment key. Only use upper letters, digits, and underscores. A variable must start with the letter.')
257+
->assertExitCode(1);
258+
259+
$this->artisan('env:set', ['key' => $invalid_key5 .'=testvalue'])
260+
->expectsOutput('Invalid environment key. Only use upper letters, digits, and underscores. A variable must start with the letter.')
261+
->assertExitCode(1);
262+
263+
}
180264
}

tests/EnvClassTest.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ public function testEnvGetAll(): void
9090
'PUSHER_APP_CLUSTER' => 'mt1',
9191
'MIX_PUSHER_APP_KEY' => '${PUSHER_APP_KEY}',
9292
'MIX_PUSHER_APP_CLUSTER' => '${PUSHER_APP_CLUSTER}',
93-
'dummy_variable' => 'Adf4$r-Ac"',
93+
'DUMMY_VARIABLE' => 'Adf4$r-Ac\"',
9494
];
9595

9696
$env = new Env();
@@ -146,7 +146,7 @@ public function testEnvSetAll(): void
146146
'PUSHER_APP_CLUSTER' => '',
147147
'MIX_PUSHER_APP_KEY' => '',
148148
'MIX_PUSHER_APP_CLUSTER' => '',
149-
'dummy_variable' => '',
149+
'DUMMY_VARIABLE' => '',
150150
];
151151

152152
function genRandomString($length = 8)
@@ -163,14 +163,15 @@ function genRandomString($length = 8)
163163
foreach ($env_vars as $key => $val) {
164164
$new_val = $env->setValue($key, $val);
165165
$ver_val = $env->getValue($key);
166+
166167
$this->assertTrue($new_val === $ver_val);
167168
$this->assertEquals($val, $ver_val);
168169
}
169170
}
170171

171172
public function testEnvDelAll(): void
172173
{
173-
$env_vars = ['APP_NAME', 'APP_ENV', 'APP_KEY', 'APP_DEBUG', 'APP_URL', 'LOG_CHANNEL', 'DB_CONNECTION', 'DB_HOST', 'DB_PORT', 'DB_DATABASE', 'DB_USERNAME', 'DB_PASSWORD', 'BROADCAST_DRIVER', 'CACHE_DRIVER', 'QUEUE_CONNECTION', 'SESSION_DRIVER', 'SESSION_LIFETIME', 'REDIS_HOST', 'REDIS_PASSWORD', 'REDIS_PORT', 'MAIL_MAILER', 'MAIL_HOST', 'MAIL_PORT', 'MAIL_USERNAME', 'MAIL_PASSWORD', 'MAIL_ENCRYPTION', 'MAIL_FROM_ADDRESS', 'MAIL_FROM_NAME', 'AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY', 'AWS_DEFAULT_REGION', 'AWS_BUCKET', 'PUSHER_APP_ID', 'PUSHER_APP_KEY', 'PUSHER_APP_SECRET', 'PUSHER_APP_CLUSTER', 'MIX_PUSHER_APP_KEY', 'MIX_PUSHER_APP_CLUSTER', 'dummy_variable'];
174+
$env_vars = ['APP_NAME', 'APP_ENV', 'APP_KEY', 'APP_DEBUG', 'APP_URL', 'LOG_CHANNEL', 'DB_CONNECTION', 'DB_HOST', 'DB_PORT', 'DB_DATABASE', 'DB_USERNAME', 'DB_PASSWORD', 'BROADCAST_DRIVER', 'CACHE_DRIVER', 'QUEUE_CONNECTION', 'SESSION_DRIVER', 'SESSION_LIFETIME', 'REDIS_HOST', 'REDIS_PASSWORD', 'REDIS_PORT', 'MAIL_MAILER', 'MAIL_HOST', 'MAIL_PORT', 'MAIL_USERNAME', 'MAIL_PASSWORD', 'MAIL_ENCRYPTION', 'MAIL_FROM_ADDRESS', 'MAIL_FROM_NAME', 'AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY', 'AWS_DEFAULT_REGION', 'AWS_BUCKET', 'PUSHER_APP_ID', 'PUSHER_APP_KEY', 'PUSHER_APP_SECRET', 'PUSHER_APP_CLUSTER', 'MIX_PUSHER_APP_KEY', 'MIX_PUSHER_APP_CLUSTER', 'DUMMY_VARIABLE'];
174175

175176
foreach ($env_vars as $key) {
176177
$env = new Env();

0 commit comments

Comments
 (0)