From f37904af1f5edb9caa7cf2ae038fe357eb565ffd Mon Sep 17 00:00:00 2001 From: "richard.gooding" Date: Thu, 23 Jul 2015 13:53:00 +0100 Subject: [PATCH] Added support for using environment variables in INI files --- src/Provider/Ini/IniConfigProvider.php | 64 ++++++++++++++---- testData/envtest.ini | 15 ++++ tests/IniConfigProviderTest.php | 94 ++++++++++++++++++++++++++ 3 files changed, 161 insertions(+), 12 deletions(-) create mode 100644 testData/envtest.ini diff --git a/src/Provider/Ini/IniConfigProvider.php b/src/Provider/Ini/IniConfigProvider.php index 98f984e..849e87b 100644 --- a/src/Provider/Ini/IniConfigProvider.php +++ b/src/Provider/Ini/IniConfigProvider.php @@ -6,13 +6,14 @@ class IniConfigProvider extends AbstractConfigProvider { /** - * @param null|string $file Full path of ini file to create configuration from + * @param null|string $file Full path of ini file to create configuration from + * @param bool $parseEnv If true then parse environment variables in the INI file */ - public function __construct($file = null) + public function __construct($file = null, $parseEnv = false) { if($file !== null) { - $this->loadFile($file); + $this->loadFile($file, $parseEnv); } } @@ -20,27 +21,36 @@ public function __construct($file = null) * Add items from an ini file to the configuration * * @param string $fullPath full path to the ini file to load + * @param bool $parseEnv If true then parse environment variables in the INI file * * @return $this * @throws \RuntimeException */ - public function loadFile($fullPath) + public function loadFile($fullPath, $parseEnv = false) { if(!file_exists($fullPath)) { throw new \RuntimeException("Config file '$fullPath' could not be found"); } - $data = parse_ini_file($fullPath, true); - - if(!$data) + if($parseEnv) { - throw new \RuntimeException( - "The ini file '$fullPath' is corrupt or invalid" - ); + $this->loadString(file_get_contents($fullPath), true); + } + else + { + $data = parse_ini_file($fullPath, true); + + if(!$data) + { + throw new \RuntimeException( + "The ini file '$fullPath' is corrupt or invalid" + ); + } + + $this->_buildFromData($data); } - $this->_buildFromData($data); return $this; } @@ -48,12 +58,17 @@ public function loadFile($fullPath) * Add items from an ini string to the configuration * * @param string $iniString valid ini string + * @param bool $parseEnv If true then parse environment variables in the INI file * * @return $this * @throws \RuntimeException */ - public function loadString($iniString) + public function loadString($iniString, $parseEnv = false) { + if($parseEnv) + { + $iniString = $this->_parseEnvVars($iniString); + } $data = parse_ini_string($iniString, true); if(!$data) @@ -87,4 +102,29 @@ protected function _buildFromData(array $iniData) } } } + + /** + * Parse environment variable markers in a string and replace them with the + * variable's value. + * Variables are expected to be in this format: {{ENV:VARNAME:defaultValue}} + * The ":defaultValue" part is optional and defaults to an empty string + * + * @param string $iniString + * + * @return string + */ + private function _parseEnvVars($iniString) + { + return preg_replace_callback( + '/{{ENV:([0-9A-Za-z]*)(:([^{}]*))?}}/', + function ($matches) + { + $varName = $matches[1]; + $default = isset($matches[3]) ? $matches[3] : ''; + $value = getenv($varName); + return $value === false ? $default : $value; + }, + $iniString + ); + } } diff --git a/testData/envtest.ini b/testData/envtest.ini new file mode 100644 index 0000000..7922ba1 --- /dev/null +++ b/testData/envtest.ini @@ -0,0 +1,15 @@ +invalid_item = will not be processed + +[default] +item = value +var1 = {{ENV:TESTVAR1}} +var2 = {{ENV:TESTVAR2:defaultvalue}} +var1and2 = {{ENV:TESTVAR1}}-{{ENV:TESTVAR2}} +nonexistentDefault = {{ENV:NONEXISTENT:defaultValue}} +nonexistentNoDefault = {{ENV:NONEXISTENT}} + +[database] +username = root +password = "fjkh%$(@££!£!@fwwejg" +hostname = localhost +database = packaged diff --git a/tests/IniConfigProviderTest.php b/tests/IniConfigProviderTest.php index e06985f..d99bc52 100644 --- a/tests/IniConfigProviderTest.php +++ b/tests/IniConfigProviderTest.php @@ -65,4 +65,98 @@ public function testLoadString() $provider->loadString(file_get_contents($file)); $this->assertEquals("packaged", $provider->getItem("database", "database")); } + + public function testLoadFileEnv() + { + putenv('TESTVAR1=fileTestValue1'); + putenv('TESTVAR2=fileTestValue2'); + + $file = dirname(__DIR__) . '/testData/envtest.ini'; + $provider = $this->getConfigProvider(); + $provider->loadFile($file, true); + + $this->assertEquals( + 'fileTestValue1', + $provider->getItem('default', 'var1') + ); + $this->assertEquals( + 'fileTestValue2', + $provider->getItem('default', 'var2') + ); + $this->assertEquals( + 'fileTestValue1-fileTestValue2', + $provider->getItem('default', 'var1and2') + ); + $this->assertEquals( + 'defaultValue', + $provider->getItem('default', 'nonexistentDefault') + ); + $this->assertEquals( + '', + $provider->getItem('default', 'nonexistentNoDefault') + ); + } + + public function testLoadStringEnv() + { + putenv('TESTVAR1=stringTestValue1'); + putenv('TESTVAR2=stringTestValue2'); + + $file = dirname(__DIR__) . '/testData/envtest.ini'; + $provider = $this->getConfigProvider(); + $provider->loadString(file_get_contents($file), true); + + $this->assertEquals( + 'stringTestValue1', + $provider->getItem('default', 'var1') + ); + $this->assertEquals( + 'stringTestValue2', + $provider->getItem('default', 'var2') + ); + $this->assertEquals( + 'stringTestValue1-stringTestValue2', + $provider->getItem('default', 'var1and2') + ); + $this->assertEquals( + 'defaultValue', + $provider->getItem('default', 'nonexistentDefault') + ); + $this->assertEquals( + '', + $provider->getItem('default', 'nonexistentNoDefault') + ); + } + + public function testLoadFileConstructEnv() + { + putenv('TESTVAR1=constructTestValue1'); + putenv('TESTVAR2=constructTestValue2'); + + $file = dirname(__DIR__) . '/testData/envtest.ini'; + $provider = new \Packaged\Config\Provider\Ini\IniConfigProvider( + $file, true + ); + + $this->assertEquals( + 'constructTestValue1', + $provider->getItem('default', 'var1') + ); + $this->assertEquals( + 'constructTestValue2', + $provider->getItem('default', 'var2') + ); + $this->assertEquals( + 'constructTestValue1-constructTestValue2', + $provider->getItem('default', 'var1and2') + ); + $this->assertEquals( + 'defaultValue', + $provider->getItem('default', 'nonexistentDefault') + ); + $this->assertEquals( + '', + $provider->getItem('default', 'nonexistentNoDefault') + ); + } }