diff options
author | 2022-08-23 21:19:53 +0200 | |
---|---|---|
committer | 2022-08-23 21:19:53 +0200 | |
commit | 5165ea265dbf73064a13c285cf08c7445839d196 (patch) | |
tree | f6402a157d245af32684b76b4ece6346df294975 /lib/Configuration.php | |
parent | edbafc614430d42789209bde3930cfe14bd8a8f0 (diff) | |
download | rss-bridge-5165ea265dbf73064a13c285cf08c7445839d196.tar.gz rss-bridge-5165ea265dbf73064a13c285cf08c7445839d196.tar.zst rss-bridge-5165ea265dbf73064a13c285cf08c7445839d196.zip |
fix: case-insensitive config from env, fix #2935 (#2973)
* refactor
* fix: case-sensitive config from env, fix #2935
* lowercase all config section and keys
* test: add test for case-insensitivity
Diffstat (limited to 'lib/Configuration.php')
-rw-r--r-- | lib/Configuration.php | 178 |
1 files changed, 44 insertions, 134 deletions
diff --git a/lib/Configuration.php b/lib/Configuration.php index 9f8b76bc..739c4ff4 100644 --- a/lib/Configuration.php +++ b/lib/Configuration.php @@ -19,27 +19,9 @@ */ final class Configuration { - /** - * Holds the current release version of RSS-Bridge. - * - * Do not access this property directly! - * Use {@see Configuration::getVersion()} instead. - * - * @var string - * - * @todo Replace this property by a constant. - */ - public static $VERSION = 'dev.2022-06-14'; + private const VERSION = 'dev.2022-06-14'; - /** - * Holds the configuration data. - * - * Do not access this property directly! - * Use {@see Configuration::getConfig()} instead. - * - * @var array|null - */ - private static $config = null; + private static array $config = []; private function __construct() { @@ -56,7 +38,7 @@ final class Configuration public static function verifyInstallation() { if (version_compare(\PHP_VERSION, '7.4.0') === -1) { - self::reportError('RSS-Bridge requires at least PHP version 7.4.0!'); + throw new \Exception('RSS-Bridge requires at least PHP version 7.4.0!'); } $errors = []; @@ -97,158 +79,114 @@ final class Configuration } } - /** - * Loads the configuration from disk and checks if the parameters are valid. - * - * Returns an error message and aborts execution if the configuration is invalid. - * - * The RSS-Bridge configuration is split into two files: - * - {@see FILE_CONFIG_DEFAULT} The default configuration file that ships - * with every release of RSS-Bridge (do not modify this file!). - * - {@see FILE_CONFIG} The local configuration file that can be modified - * by server administrators. - * - * RSS-Bridge will first load {@see FILE_CONFIG_DEFAULT} into memory and then - * replace parameters with the contents of {@see FILE_CONFIG}. That way new - * parameters are automatically initialized with default values and custom - * configurations can be reduced to the minimum set of parametes necessary - * (only the ones that changed). - * - * The configuration files must be placed in the root folder of RSS-Bridge - * (next to `index.php`). - * - * _Notice_: The configuration is stored in {@see Configuration::$config}. - * - * @return void - */ - public static function loadConfiguration() + public static function loadConfiguration(array $customConfig = [], array $env = []) { - if (!file_exists(FILE_CONFIG_DEFAULT)) { - self::reportError('The default configuration file is missing at ' . FILE_CONFIG_DEFAULT); + if (!file_exists(__DIR__ . '/../config.default.ini.php')) { + throw new \Exception('The default configuration file is missing'); } - - $config = parse_ini_file(FILE_CONFIG_DEFAULT, true, INI_SCANNER_TYPED); + $config = parse_ini_file(__DIR__ . '/../config.default.ini.php', true, INI_SCANNER_TYPED); if (!$config) { - self::reportError('Error parsing ' . FILE_CONFIG_DEFAULT); + throw new \Exception('Error parsing config'); } - - if (file_exists(FILE_CONFIG)) { - // Replace default configuration with custom settings - foreach (parse_ini_file(FILE_CONFIG, true, INI_SCANNER_TYPED) as $header => $section) { - foreach ($section as $key => $value) { - $config[$header][$key] = $value; - } + foreach ($config as $header => $section) { + foreach ($section as $key => $value) { + self::setConfig($header, $key, $value); } } - - foreach (getenv() as $envName => $envValue) { - // Replace all settings with their respective environment variable if available - $keyArray = explode('_', $envName); - if ($keyArray[0] === 'RSSBRIDGE') { - $header = strtolower($keyArray[1]); - $key = strtolower($keyArray[2]); + foreach ($customConfig as $header => $section) { + foreach ($section as $key => $value) { + self::setConfig($header, $key, $value); + } + } + foreach ($env as $envName => $envValue) { + $nameParts = explode('_', $envName); + if ($nameParts[0] === 'RSSBRIDGE') { + $header = $nameParts[1]; + $key = $nameParts[2]; if ($envValue === 'true' || $envValue === 'false') { $envValue = filter_var($envValue, FILTER_VALIDATE_BOOLEAN); } - $config[$header][$key] = $envValue; + self::setConfig($header, $key, $envValue); } } - self::$config = $config; - if ( !is_string(self::getConfig('system', 'timezone')) || !in_array(self::getConfig('system', 'timezone'), timezone_identifiers_list(DateTimeZone::ALL_WITH_BC)) ) { - self::reportConfigurationError('system', 'timezone'); + self::throwConfigError('system', 'timezone'); } if (!is_string(self::getConfig('proxy', 'url'))) { - self::reportConfigurationError('proxy', 'url', 'Is not a valid string'); + self::throwConfigError('proxy', 'url', 'Is not a valid string'); } if (!is_bool(self::getConfig('proxy', 'by_bridge'))) { - self::reportConfigurationError('proxy', 'by_bridge', 'Is not a valid Boolean'); + self::throwConfigError('proxy', 'by_bridge', 'Is not a valid Boolean'); } if (!is_string(self::getConfig('proxy', 'name'))) { /** Name of the proxy server */ - self::reportConfigurationError('proxy', 'name', 'Is not a valid string'); + self::throwConfigError('proxy', 'name', 'Is not a valid string'); } if (!is_string(self::getConfig('cache', 'type'))) { - self::reportConfigurationError('cache', 'type', 'Is not a valid string'); + self::throwConfigError('cache', 'type', 'Is not a valid string'); } if (!is_bool(self::getConfig('cache', 'custom_timeout'))) { - self::reportConfigurationError('cache', 'custom_timeout', 'Is not a valid Boolean'); + self::throwConfigError('cache', 'custom_timeout', 'Is not a valid Boolean'); } if (!is_bool(self::getConfig('authentication', 'enable'))) { - self::reportConfigurationError('authentication', 'enable', 'Is not a valid Boolean'); + self::throwConfigError('authentication', 'enable', 'Is not a valid Boolean'); } if (!self::getConfig('authentication', 'username')) { - self::reportConfigurationError('authentication', 'username', 'Is not a valid string'); + self::throwConfigError('authentication', 'username', 'Is not a valid string'); } if (! self::getConfig('authentication', 'password')) { - self::reportConfigurationError('authentication', 'password', 'Is not a valid string'); + self::throwConfigError('authentication', 'password', 'Is not a valid string'); } if ( !empty(self::getConfig('admin', 'email')) && !filter_var(self::getConfig('admin', 'email'), FILTER_VALIDATE_EMAIL) ) { - self::reportConfigurationError('admin', 'email', 'Is not a valid email address'); + self::throwConfigError('admin', 'email', 'Is not a valid email address'); } if (!is_bool(self::getConfig('admin', 'donations'))) { - self::reportConfigurationError('admin', 'donations', 'Is not a valid Boolean'); + self::throwConfigError('admin', 'donations', 'Is not a valid Boolean'); } if (!is_string(self::getConfig('error', 'output'))) { - self::reportConfigurationError('error', 'output', 'Is not a valid String'); + self::throwConfigError('error', 'output', 'Is not a valid String'); } if ( !is_numeric(self::getConfig('error', 'report_limit')) || self::getConfig('error', 'report_limit') < 1 ) { - self::reportConfigurationError('admin', 'report_limit', 'Value is invalid'); + self::throwConfigError('admin', 'report_limit', 'Value is invalid'); } } - /** - * Returns the value of a parameter identified by section and key. - * - * @param string $section The section name. - * @param string $key The property name (key). - * @return mixed|null The parameter value. - */ - public static function getConfig($section, $key) + public static function getConfig(string $section, string $key) { - if (array_key_exists($section, self::$config) && array_key_exists($key, self::$config[$section])) { - return self::$config[$section][$key]; - } + return self::$config[strtolower($section)][strtolower($key)] ?? null; + } - return null; + private static function setConfig(string $section, string $key, $value): void + { + self::$config[strtolower($section)][strtolower($key)] = $value; } - /** - * Returns the current version string of RSS-Bridge. - * - * This function returns the contents of {@see Configuration::$VERSION} for - * regular installations and the git branch name and commit id for instances - * running in a git environment. - * - * @return string The version string. - */ public static function getVersion() { $headFile = __DIR__ . '/../.git/HEAD'; - // '@' is used to mute open_basedir warning if (@is_readable($headFile)) { $revisionHashFile = '.git/' . substr(file_get_contents($headFile), 5, -1); $parts = explode('/', $revisionHashFile); @@ -260,39 +198,11 @@ final class Configuration } } } - - return Configuration::$VERSION; - } - - /** - * Reports an configuration error for the specified section and key to the - * user and ends execution - * - * @param string $section The section name - * @param string $key The configuration key - * @param string $message An optional message to the user - * - * @return void - */ - private static function reportConfigurationError($section, $key, $message = '') - { - $report = "Parameter [{$section}] => \"{$key}\" is invalid!" . PHP_EOL; - - if (file_exists(FILE_CONFIG)) { - $report .= 'Please check your configuration file at ' . FILE_CONFIG . PHP_EOL; - } elseif (!file_exists(FILE_CONFIG_DEFAULT)) { - $report .= 'The default configuration file is missing at ' . FILE_CONFIG_DEFAULT . PHP_EOL; - } else { - $report .= 'The default configuration file is broken.' . PHP_EOL - . 'Restore the original file from ' . REPOSITORY . PHP_EOL; - } - - $report .= $message; - self::reportError($report); + return self::VERSION; } - private static function reportError($message) + private static function throwConfigError($section, $key, $message = '') { - throw new \Exception(sprintf('Configuration error: %s', $message)); + throw new \Exception("Config [$section] => [$key] is invalid. $message"); } } |