Skip to content

Prefix calls to getenv() during config resolution #4561

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion system/Config/BaseConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ protected function initEnvValue(&$property, string $name, string $prefix, string
protected function getEnvValue(string $property, string $prefix, string $shortPrefix)
{
$shortPrefix = ltrim($shortPrefix, '\\');

switch (true)
{
case array_key_exists("{$shortPrefix}.{$property}", $_ENV):
Expand All @@ -145,7 +146,9 @@ protected function getEnvValue(string $property, string $prefix, string $shortPr
case array_key_exists("{$prefix}.{$property}", $_SERVER):
return $_SERVER["{$prefix}.{$property}"];
default:
$value = getenv($property);
$value = getenv("{$shortPrefix}.{$property}");
$value = $value === false ? getenv("{$prefix}.{$property}") : $value;

return $value === false ? null : $value;
}
}
Expand Down
104 changes: 36 additions & 68 deletions tests/system/Config/BaseConfigTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,8 @@

class BaseConfigTest extends CIUnitTestCase
{

protected $fixturesFolder;

//--------------------------------------------------------------------

protected function setUp(): void
{
parent::setUp();
Expand All @@ -37,21 +34,16 @@ protected function setUp(): void
}
}

//--------------------------------------------------------------------

public function testBasicValues()
{
$dotenv = new DotEnv($this->fixturesFolder, '.env');
$dotenv->load();
$config = new SimpleConfig();

$this->assertEquals('bar', $config->FOO);
// empty treated as boolean false
$this->assertEquals(false, $config->echo);
// 'true' should be treated as boolean true
$this->assertNull($config->FOO);
$this->assertSame('', $config->echo);
$this->assertTrue($config->foxtrot);
// numbers should be treated properly
$this->assertEquals(18, $config->golf);
$this->assertSame(18, $config->golf);
}

/**
Expand All @@ -68,12 +60,10 @@ public function testServerValues()
$dotenv->load();
$config = new SimpleConfig();

$this->assertEquals(123, $config->shortie);
$this->assertEquals(456, $config->longie);
$this->assertSame('123', $config->shortie);
$this->assertSame('456', $config->longie);
}

//--------------------------------------------------------------------

public function testEnvironmentOverrides()
{
$dotenv = new DotEnv($this->fixturesFolder, '.env');
Expand All @@ -82,81 +72,69 @@ public function testEnvironmentOverrides()
$config = new SimpleConfig();

// override config with ENV var
$this->assertEquals('pow', $config->alpha);
$this->assertSame('pow', $config->alpha);
// config should not be over-written by wrongly named ENV var
$this->assertEquals('three', $config->charlie);
$this->assertSame('three', $config->charlie);
// override config with shortPrefix ENV var
$this->assertEquals('hubbahubba', $config->delta);
$this->assertSame('hubbahubba', $config->delta);
// incorrect env name should not inject property
$this->assertObjectNotHasAttribute('notthere', $config);
// same ENV var as property, but not namespaced, still over-rides
$this->assertEquals('kazaam', $config->bravo);
// empty ENV var should not affect config setting
$this->assertEquals('pineapple', $config->fruit);
$this->assertSame('pineapple', $config->fruit);
// non-empty ENV var should overrideconfig setting
$this->assertEquals('banana', $config->dessert);
$this->assertSame('banana', $config->dessert);
// null property should not be affected
$this->assertNull($config->QEMPTYSTR);
}

//--------------------------------------------------------------------

public function testPrefixedValues()
{
$dotenv = new DotEnv($this->fixturesFolder, '.env');
$dotenv->load();

$config = new SimpleConfig();

$this->assertEquals('baz', $config->onedeep);
$this->assertSame('baz', $config->onedeep);
}

//--------------------------------------------------------------------

public function testPrefixedArrayValues()
{
$dotenv = new DotEnv($this->fixturesFolder, '.env');
$dotenv->load();

$config = new SimpleConfig();

$this->assertEquals('ci4', $config->default['name']);
$this->assertEquals('Malcolm', $config->crew['captain']);
$this->assertEquals('Spock', $config->crew['science']);
$this->assertFalse(array_key_exists('pilot', $config->crew));
$this->assertSame('ci4', $config->default['name']);
$this->assertSame('Malcolm', $config->crew['captain']);
$this->assertSame('Spock', $config->crew['science']);
$this->assertArrayNotHasKey('pilot', $config->crew);
$this->assertTrue($config->crew['comms']);
$this->assertFalse($config->crew['doctor']);
}

//--------------------------------------------------------------------

public function testArrayValues()
{
$dotenv = new DotEnv($this->fixturesFolder, '.env');
$dotenv->load();

$config = new SimpleConfig();

$this->assertEquals('complex', $config->simple['name']);
$this->assertEquals('foo', $config->first);
$this->assertEquals('bar', $config->second);
$this->assertSame('complex', $config->simple['name']);
$this->assertSame('foo', $config->first);
$this->assertSame('bar', $config->second);
}

//--------------------------------------------------------------------

public function testSetsDefaultValues()
{
$dotenv = new DotEnv($this->fixturesFolder, 'commented.env');
$dotenv->load();

$config = new SimpleConfig();

$this->assertEquals('foo', $config->first);
$this->assertEquals('bar', $config->second);
$this->assertSame('foo', $config->first);
$this->assertSame('bar', $config->second);
}

//--------------------------------------------------------------------

/**
* @runInSeparateProcess
* @preserveGlobalState disabled
Expand All @@ -168,12 +146,10 @@ public function testSetsDefaultValuesEncryptionUsingHex2Bin()
$config = new Encryption();

// override config with ENV var
$this->assertEquals('f699c7fd18a8e082d0228932f3acd40e1ef5ef92efcedda32842a211d62f0aa6', bin2hex($config->key));
$this->assertEquals('OpenSSL', $config->driver);
$this->assertSame('f699c7fd18a8e082d0228932f3acd40e1ef5ef92efcedda32842a211d62f0aa6', bin2hex($config->key));
$this->assertSame('OpenSSL', $config->driver);
}

//--------------------------------------------------------------------

/**
* @runInSeparateProcess
* @preserveGlobalState disabled
Expand All @@ -184,37 +160,31 @@ public function testSetDefaultValuesEncryptionUsingBase64()
$dotenv->load();
$config = new Encryption('base64');

$this->assertEquals('L40bKo6b8Nu541LeVeZ1i5RXfGgnkar42CPTfukhGhw=', base64_encode($config->key));
$this->assertEquals('OpenSSL', $config->driver);
$this->assertSame('L40bKo6b8Nu541LeVeZ1i5RXfGgnkar42CPTfukhGhw=', base64_encode($config->key));
$this->assertSame('OpenSSL', $config->driver);
}

//--------------------------------------------------------------------

public function testSetsDefaultValuesHex2Bin()
{
$dotenv = new DotEnv($this->fixturesFolder, 'commented.env');
$dotenv->load();
$config = new Encryption();

// override config with ENV var
$this->assertEquals('84cf2c0811d5daf9e1c897825a3debce91f9a33391e639f72f7a4740b30675a2', bin2hex($config->key));
$this->assertEquals('MCrypt', $config->driver);
$this->assertSame('84cf2c0811d5daf9e1c897825a3debce91f9a33391e639f72f7a4740b30675a2', bin2hex($config->key));
$this->assertSame('MCrypt', $config->driver);
}

//--------------------------------------------------------------------

public function testSetDefaultValuesBase64()
{
$dotenv = new DotEnv($this->fixturesFolder, 'commented.env');
$dotenv->load();
$config = new Encryption('base64');

$this->assertEquals('Psf8bUHRh1UJYG2M7e+5ec3MdjpKpzAr0twamcAvOcI=', base64_encode($config->key));
$this->assertEquals('MCrypt', $config->driver);
$this->assertSame('Psf8bUHRh1UJYG2M7e+5ec3MdjpKpzAr0twamcAvOcI=', base64_encode($config->key));
$this->assertSame('MCrypt', $config->driver);
}

//--------------------------------------------------------------------

public function testRecognizesLooseValues()
{
$dotenv = new DotEnv($this->fixturesFolder, 'loose.env');
Expand All @@ -224,12 +194,10 @@ public function testRecognizesLooseValues()

$this->assertEquals(0, $config->QZERO);
$this->assertSame('0', $config->QZEROSTR);
$this->assertEquals(' ', $config->QEMPTYSTR);
$this->assertSame(' ', $config->QEMPTYSTR);
$this->assertFalse($config->QFALSE);
}

//--------------------------------------------------------------------

public function testRegistrars()
{
$config = new RegistrarConfig();
Expand All @@ -239,13 +207,13 @@ public function testRegistrars()
$method();

// no change to unmodified property
$this->assertEquals('bar', $config->foo);
$this->assertSame('bar', $config->foo);
// add to an existing array property
$this->assertEquals(['baz', 'first', 'second'], $config->bar);
$this->assertSame(['baz', 'first', 'second'], $config->bar);
// add a new property
$this->assertEquals('nice', $config->format);
$this->assertSame('nice', $config->format);
// add a new array property
$this->assertEquals(['apple', 'banana'], $config->fruit);
$this->assertSame(['apple', 'banana'], $config->fruit);
}

public function testBadRegistrar()
Expand All @@ -259,7 +227,7 @@ public function testBadRegistrar()
$method = $this->getPrivateMethodInvoker($config, 'registerProperties');
$method();

$this->assertEquals('bar', $config->foo);
$this->assertSame('bar', $config->foo);
}

public function testNotEnabled()
Expand All @@ -274,7 +242,7 @@ public function testNotEnabled()
$method = $this->getPrivateMethodInvoker($config, 'registerProperties');
$method();

$this->assertEquals($expected, $config::$registrars);
$this->assertSame($expected, $config::$registrars);
}

public function testDidDiscovery()
Expand All @@ -289,7 +257,7 @@ public function testDidDiscovery()
$method = $this->getPrivateMethodInvoker($config, 'registerProperties');
$method();

$this->assertEquals(true, $this->getPrivateProperty($config, 'didDiscovery'));
$this->assertSame(true, $this->getPrivateProperty($config, 'didDiscovery'));
}

}
2 changes: 1 addition & 1 deletion tests/system/Config/DotEnvTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ public function testNamespacedVariables()
$dotenv = new Dotenv($this->fixturesFolder, '.env');
$dotenv->load();

$this->assertEquals('complex', $_SERVER['simple.name']);
$this->assertEquals('complex', $_SERVER['SimpleConfig.simple.name']);
}

//--------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion tests/system/Config/fixtures/.env
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ NULL=

SimpleConfig.onedeep=baz
SimpleConfig.default.name=ci4
simple.name=complex
SimpleConfig.simple.name=complex

# for environment override testing
SimpleConfig.alpha=pow
Expand Down
8 changes: 4 additions & 4 deletions tests/system/Config/fixtures/loose.env
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
QZERO=0
QZEROSTR="0"
QEMPTYSTR=" "
QFALSE=false
SimpleConfig.QZERO=0
SimpleConfig.QZEROSTR="0"
SimpleConfig.QEMPTYSTR=" "
SimpleConfig.QFALSE=false
1 change: 1 addition & 0 deletions user_guide_src/source/changelogs/v4.1.2.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Changes:
- Entity. Timestamp casting now throws an exception when an invalid value is passed
- ``Entity::castAsJson`` uses external cast handler ``JsonCast::get``.
- ``Entity::mutateDate`` uses external cast handler ``DatetimeCast::get``.
- In order for ``Config\**`` classes to get their respective properties' values from the ``.env``, it is now necessary to namespace the property with the name of the class. Previously, the property names are enough but now disallowed because it can get system environment variables, like ``PATH``.

Deprecations:

Expand Down