From: Philipp Holzer Date: Sun, 24 Mar 2019 11:54:26 +0000 (+0100) Subject: Adding ConfigFileSaver and tests X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=49def0dc27285557e91d7f8cf4c4ff97bac1489c;p=friendica.git Adding ConfigFileSaver and tests --- diff --git a/mod/admin.php b/mod/admin.php index 7808a87ef8..851dd0b093 100644 --- a/mod/admin.php +++ b/mod/admin.php @@ -1087,8 +1087,9 @@ function admin_page_site_post(App $a) update_table($a, "gcontact", ['connect', 'addr'], $old_host, $new_host); // update config - $configCacheSaver = new \Friendica\Util\Config\ConfigCacheSaver($a->getBasePath()); - $configCacheSaver->saveToConfigFile('system', 'hostname', parse_url($new_url, PHP_URL_HOST)); + $configFileSaver = new \Friendica\Util\Config\ConfigFileSaver($a->getBasePath()); + $configFileSaver->addConfigValue('system', 'hostname', parse_url($new_url, PHP_URL_HOST)); + $configFileSaver->saveToConfigFile(); Config::set('system', 'hostname', parse_url($new_url, PHP_URL_HOST)); Config::set('system', 'url', $new_url); $a->setBaseURL($new_url); diff --git a/src/App.php b/src/App.php index 7c88f0f021..3a96182b1e 100644 --- a/src/App.php +++ b/src/App.php @@ -13,7 +13,7 @@ use Friendica\Core\Config\Configuration; use Friendica\Database\DBA; use Friendica\Model\Profile; use Friendica\Network\HTTPException\InternalServerErrorException; -use Friendica\Util\Config\ConfigCacheLoader; +use Friendica\Util\Config\ConfigFileLoader; use Friendica\Util\HTTPSignature; use Friendica\Util\Profiler; use Psr\Log\LoggerInterface; @@ -355,7 +355,7 @@ class App $this->getMode()->determine($this->getBasePath()); if ($this->getMode()->has(App\Mode::DBAVAILABLE)) { - $loader = new ConfigCacheLoader($this->getBasePath(), $this->getMode()); + $loader = new ConfigFileLoader($this->getBasePath(), $this->getMode()); $this->config->getCache()->load($loader->loadCoreConfig('addon'), true); $this->profiler->update( @@ -363,7 +363,7 @@ class App $this->config->get('rendertime', 'callstack', false)); Core\Hook::loadHooks(); - $loader = new ConfigCacheLoader($this->getBasePath(), $this->mode); + $loader = new ConfigFileLoader($this->getBasePath(), $this->mode); Core\Hook::callAll('load_config', $loader); } diff --git a/src/Core/Config/Cache/ConfigCache.php b/src/Core/Config/Cache/ConfigCache.php index cb299eb330..f61865cee6 100644 --- a/src/Core/Config/Cache/ConfigCache.php +++ b/src/Core/Config/Cache/ConfigCache.php @@ -5,7 +5,7 @@ namespace Friendica\Core\Config\Cache; /** * The Friendica config cache for the application * Initial, all *.config.php files are loaded into this cache with the - * ConfigCacheLoader ( @see ConfigCacheLoader ) + * ConfigFileLoader ( @see ConfigFileLoader ) */ class ConfigCache implements IConfigCache, IPConfigCache { diff --git a/src/Core/Console/AutomaticInstallation.php b/src/Core/Console/AutomaticInstallation.php index 0c73c82b1b..911c1c00a8 100644 --- a/src/Core/Console/AutomaticInstallation.php +++ b/src/Core/Console/AutomaticInstallation.php @@ -7,7 +7,7 @@ use Friendica\BaseObject; use Friendica\Core\Config; use Friendica\Core\Installer; use Friendica\Core\Theme; -use Friendica\Util\Config\ConfigCacheLoader; +use Friendica\Util\Config\ConfigFileLoader; use RuntimeException; class AutomaticInstallation extends Console @@ -104,8 +104,8 @@ HELP; } //reload the config cache - $loader = new ConfigCacheLoader($a->getBasePath(), $a->getMode()); - $loader->loadConfigFiles($configCache); + $loader = new ConfigFileLoader($a->getBasePath(), $a->getMode()); + $loader->setupCache($configCache); } else { // Creating config file diff --git a/src/Factory/ConfigFactory.php b/src/Factory/ConfigFactory.php index 7a281d97a5..1f9662bddb 100644 --- a/src/Factory/ConfigFactory.php +++ b/src/Factory/ConfigFactory.php @@ -6,19 +6,19 @@ use Friendica\Core; use Friendica\Core\Config; use Friendica\Core\Config\Adapter; use Friendica\Core\Config\Cache; -use Friendica\Util\Config\ConfigCacheLoader; +use Friendica\Util\Config\ConfigFileLoader; class ConfigFactory { /** - * @param ConfigCacheLoader $loader The Config Cache loader (INI/config/.htconfig) + * @param ConfigFileLoader $loader The Config Cache loader (INI/config/.htconfig) * * @return Cache\ConfigCache */ - public static function createCache(ConfigCacheLoader $loader) + public static function createCache(ConfigFileLoader $loader) { $configCache = new Cache\ConfigCache(); - $loader->loadConfigFiles($configCache); + $loader->setupCache($configCache); return $configCache; } diff --git a/src/Factory/DependencyFactory.php b/src/Factory/DependencyFactory.php index 9322a44cfe..65bdf37140 100644 --- a/src/Factory/DependencyFactory.php +++ b/src/Factory/DependencyFactory.php @@ -24,7 +24,7 @@ class DependencyFactory { $basePath = BasePath::create($directory, $_SERVER); $mode = new App\Mode($basePath); - $configLoader = new Config\ConfigCacheLoader($basePath, $mode); + $configLoader = new Config\ConfigFileLoader($basePath, $mode); $configCache = Factory\ConfigFactory::createCache($configLoader); $profiler = Factory\ProfilerFactory::create($configCache); Factory\DBFactory::init($basePath, $configCache, $profiler, $_SERVER); diff --git a/src/Util/Config/ConfigCacheLoader.php b/src/Util/Config/ConfigCacheLoader.php deleted file mode 100644 index 6eced061ed..0000000000 --- a/src/Util/Config/ConfigCacheLoader.php +++ /dev/null @@ -1,219 +0,0 @@ -appMode = $mode; - } - - /** - * Load the configuration files - * - * First loads the default value for all the configuration keys, then the legacy configuration files, then the - * expected local.config.php - * - * @param IConfigCache The config cache to load to - * - * @throws \Exception - */ - public function loadConfigFiles(IConfigCache $config) - { - $config->load($this->loadCoreConfig('defaults')); - $config->load($this->loadCoreConfig('settings')); - - $config->load($this->loadLegacyConfig('htpreconfig'), true); - $config->load($this->loadLegacyConfig('htconfig'), true); - - $config->load($this->loadCoreConfig('local'), true); - - // In case of install mode, add the found basepath (because there isn't a basepath set yet - if ($this->appMode->isInstall()) { - // Setting at least the basepath we know - $config->set('system', 'basepath', $this->baseDir); - } - } - - /** - * Tries to load the specified core-configuration and returns the config array. - * - * @param string $name The name of the configuration (default is empty, which means 'local') - * - * @return array The config array (empty if no config found) - * - * @throws \Exception if the configuration file isn't readable - */ - public function loadCoreConfig($name = '') - { - if (!empty($this->getConfigFullName($name))) { - return $this->loadConfigFile($this->getConfigFullName($name)); - } elseif (!empty($this->getIniFullName($name))) { - return $this->loadINIConfigFile($this->getIniFullName($name)); - } else { - return []; - } - } - - /** - * Tries to load the specified addon-configuration and returns the config array. - * - * @param string $name The name of the configuration - * - * @return array The config array (empty if no config found) - * - * @throws \Exception if the configuration file isn't readable - */ - public function loadAddonConfig($name) - { - $filepath = $this->baseDir . DIRECTORY_SEPARATOR . // /var/www/html/ - Addon::DIRECTORY . DIRECTORY_SEPARATOR . // addon/ - $name . DIRECTORY_SEPARATOR . // openstreetmap/ - self::SUBDIRECTORY . DIRECTORY_SEPARATOR . // config/ - $name . ".config.php"; // openstreetmap.config.php - - if (file_exists($filepath)) { - return $this->loadConfigFile($filepath); - } else { - return []; - } - } - - /** - * Tries to load the legacy config files (.htconfig.php, .htpreconfig.php) and returns the config array. - * - * @param string $name The name of the config file (default is empty, which means .htconfig.php) - * - * @return array The configuration array (empty if no config found) - * - * @deprecated since version 2018.09 - */ - private function loadLegacyConfig($name = '') - { - $config = []; - if (!empty($this->getHtConfigFullName($name))) { - $a = new \stdClass(); - $a->config = []; - include $this->getHtConfigFullName($name); - - $htConfigCategories = array_keys($a->config); - - // map the legacy configuration structure to the current structure - foreach ($htConfigCategories as $htConfigCategory) { - if (is_array($a->config[$htConfigCategory])) { - $keys = array_keys($a->config[$htConfigCategory]); - - foreach ($keys as $key) { - $config[$htConfigCategory][$key] = $a->config[$htConfigCategory][$key]; - } - } else { - $config['config'][$htConfigCategory] = $a->config[$htConfigCategory]; - } - } - - unset($a); - - if (isset($db_host)) { - $config['database']['hostname'] = $db_host; - unset($db_host); - } - if (isset($db_user)) { - $config['database']['username'] = $db_user; - unset($db_user); - } - if (isset($db_pass)) { - $config['database']['password'] = $db_pass; - unset($db_pass); - } - if (isset($db_data)) { - $config['database']['database'] = $db_data; - unset($db_data); - } - if (isset($config['system']['db_charset'])) { - $config['database']['charset'] = $config['system']['db_charset']; - } - if (isset($pidfile)) { - $config['system']['pidfile'] = $pidfile; - unset($pidfile); - } - if (isset($default_timezone)) { - $config['system']['default_timezone'] = $default_timezone; - unset($default_timezone); - } - if (isset($lang)) { - $config['system']['language'] = $lang; - unset($lang); - } - } - - return $config; - } - - /** - * Tries to load the specified legacy configuration file and returns the config array. - * - * @deprecated since version 2018.12 - * @param string $filepath - * - * @return array The configuration array - * @throws \Exception - */ - private function loadINIConfigFile($filepath) - { - $contents = include($filepath); - - $config = parse_ini_string($contents, true, INI_SCANNER_TYPED); - - if ($config === false) { - throw new \Exception('Error parsing INI config file ' . $filepath); - } - - return $config; - } - - /** - * Tries to load the specified configuration file and returns the config array. - * - * The config format is PHP array and the template for configuration files is the following: - * - * [ - * 'key' => 'value', - * ], - * ]; - * - * @param string $filepath The filepath of the - * @return array The config array0 - * - * @throws \Exception if the config cannot get loaded. - */ - private function loadConfigFile($filepath) - { - $config = include($filepath); - - if (!is_array($config)) { - throw new \Exception('Error loading config file ' . $filepath); - } - - return $config; - } -} diff --git a/src/Util/Config/ConfigCacheManager.php b/src/Util/Config/ConfigCacheManager.php deleted file mode 100644 index 8fb923216c..0000000000 --- a/src/Util/Config/ConfigCacheManager.php +++ /dev/null @@ -1,87 +0,0 @@ -baseDir = $baseDir; - $this->configDir = $baseDir . DIRECTORY_SEPARATOR . self::SUBDIRECTORY; - } - - /** - * Gets the full name (including the path) for a *.config.php (default is local.config.php) - * - * @param string $name The config name (default is empty, which means local.config.php) - * - * @return string The full name or empty if not found - */ - protected function getConfigFullName($name = '') - { - $name = !empty($name) ? $name : self::CONFIG_LOCAL; - - $fullName = $this->configDir . DIRECTORY_SEPARATOR . $name . '.config.php'; - return file_exists($fullName) ? $fullName : ''; - } - - /** - * Gets the full name (including the path) for a *.ini.php (default is local.ini.php) - * - * @param string $name The config name (default is empty, which means local.ini.php) - * - * @return string The full name or empty if not found - */ - protected function getIniFullName($name = '') - { - $name = !empty($name) ? $name : self::CONFIG_INI; - - $fullName = $this->configDir . DIRECTORY_SEPARATOR . $name . '.ini.php'; - return file_exists($fullName) ? $fullName : ''; - } - - /** - * Gets the full name (including the path) for a .*.php (default is .htconfig.php) - * - * @param string $name The config name (default is empty, which means .htconfig.php) - * - * @return string The full name or empty if not found - */ - protected function getHtConfigFullName($name = '') - { - $name = !empty($name) ? $name : self::CONFIG_HTCONFIG; - - $fullName = $this->baseDir . DIRECTORY_SEPARATOR . '.' . $name . '.php'; - return file_exists($fullName) ? $fullName : ''; - } -} diff --git a/src/Util/Config/ConfigCacheSaver.php b/src/Util/Config/ConfigCacheSaver.php deleted file mode 100644 index 41ebca140f..0000000000 --- a/src/Util/Config/ConfigCacheSaver.php +++ /dev/null @@ -1,229 +0,0 @@ -settings[$cat][$key] = $value; - } - - public function reset() - { - $this->settings = []; - } - - public function saveToConfigFile($name = '') - { - $saved = false; - - if (!empty($this->getConfigFullName($name))) { - $this->saveConfigFile($this->getConfigFullName($name)); - $saved = true; - } - - if (!empty($this->getIniFullName($name))) { - $this->saveINIConfigFile($this->getIniFullName($name)); - $saved = true; - } - - if (!empty($this->getHtConfigFullName($name))) { - $this->saveToLegacyConfig($this->getHtConfigFullName($name)); - $saved = true; - } - - return $saved; - } - - /** - * Saves a value to either an config or an ini file - * - * @param string $name The configuration file name ('local', 'addon', ..) - * @param string $cat The configuration category - * @param string $key The configuration key - * @param string $value The new value - */ - private function saveToCoreConfig($name, $cat, $key, $value) - { - if (!empty($this->getConfigFullName($name))) { - $this->saveConfigFile($this->getConfigFullName($name), $cat, $key, $value); - } elseif (!empty($this->getIniFullName($name))) { - $this->saveINIConfigFile($this->getIniFullName($name), $cat, $key, $value); - } else { - return; - } - } - - /** - * Saves a value to a config file - * - * @param string $fullName The configuration full name (including the path) - * @param string $cat The configuration category - * @param string $key The configuration key - * @param string $value The new value - * - * @throws \Exception In case a file operation doesn't work - */ - private function saveConfigFile($fullName, $cat, $key, $value) - { - $reading = fopen($fullName, 'r'); - if (!$reading) { - throw new \Exception('Cannot open config file \'' . $fullName . '\'.'); - } - $writing = fopen($fullName . '.tmp', 'w'); - if (!$writing) { - throw new \Exception('Cannot create temporary config file \'' . $fullName . '.tmp\'.'); - } - $categoryFound = false; - $categoryBracketFound = false; - $lineFound = false; - $lineArrowFound = false; - while (!feof($reading)) { - $line = fgets($reading); - // find the first line like "'system' =>" - if (!$categoryFound && stristr($line, sprintf('\'%s\'', $cat))) { - $categoryFound = true; - } - // find the first line with a starting bracket ( "[" ) - if ($categoryFound && !$categoryBracketFound && stristr($line, '[')) { - $categoryBracketFound = true; - } - // find the first line with the key like "'value'" - if ($categoryBracketFound && !$lineFound && stristr($line, sprintf('\'%s\'', $key))) { - $lineFound = true; - } - // find the first line with an arrow ("=>") after finding the key - if ($lineFound && !$lineArrowFound && stristr($line, '=>')) { - $lineArrowFound = true; - } - // find the current value and replace it - if ($lineArrowFound && preg_match_all('/\'(.*?)\'/', $line, $matches, PREG_SET_ORDER)) { - $lineVal = end($matches)[0]; - $writeLine = str_replace($lineVal, '\'' . $value . '\'', $line); - $categoryFound = false; - $categoryBracketFound = false; - $lineFound = false; - $lineArrowFound = false; - // if a line contains a closing bracket for the category ( "]" ) and we didn't find the key/value pair, - // add it as a new line before the closing bracket - } elseif ($categoryBracketFound && !$lineArrowFound && stristr($line, ']')) { - $categoryFound = false; - $categoryBracketFound = false; - $lineFound = false; - $lineArrowFound = false; - $writeLine = sprintf(self::INDENT . self::INDENT .'\'%s\' => \'%s\',' . PHP_EOL, $key, $value); - $writeLine .= $line; - } else { - $writeLine = $line; - } - fputs($writing, $writeLine); - } - if (!fclose($reading)) { - throw new \Exception('Cannot close config file \'' . $fullName . '\'.'); - }; - if (!fclose($writing)) { - throw new \Exception('Cannot close temporary config file \'' . $fullName . '.tmp\'.'); - }; - if (!rename($fullName, $fullName . '.old')) { - throw new \Exception('Cannot backup current config file \'' . $fullName . '\'.'); - } - if (!rename($fullName . '.tmp', $fullName)) { - throw new \Exception('Cannot move temporary config file \'' . $fullName . '.tmp\' to current.'); - } - } - - /** - * Saves a value to a ini file - * - * @param string $fullName The configuration full name (including the path) - * @param string $cat The configuration category - * @param string $key The configuration key - * @param string $value The new value - */ - private function saveINIConfigFile($fullName, $cat, $key, $value) - { - $reading = fopen($fullName, 'r'); - $writing = fopen($fullName . '.tmp', 'w'); - $categoryFound = false; - while (!feof($reading)) { - $line = fgets($reading); - if (!$categoryFound && stristr($line, sprintf('[%s]', $cat))) { - $categoryFound = true; - $writeLine = $line; - } elseif ($categoryFound && preg_match_all('/^' . $key . '\s*=\s*(.*?)$/', $line, $matches, PREG_SET_ORDER)) { - $writeLine = $key . ' = ' . $value . PHP_EOL; - $categoryFound = false; - } elseif ($categoryFound && (preg_match_all('/^\[.*?\]$/', $line) || preg_match_all('/^INI;.*$/', $line))) { - $categoryFound = false; - $writeLine = $key . ' = ' . $value . PHP_EOL; - $writeLine .= $line; - } else { - $writeLine = $line; - } - fputs($writing, $writeLine); - } - fclose($reading); - fclose($writing); - rename($fullName, $fullName . '.old'); - rename($fullName . '.tmp', $fullName); - } - - private function saveToLegacyConfig($name, $cat, $key, $value) - { - if (empty($this->getHtConfigFullName($name))) { - return; - } - $fullName = $this->getHtConfigFullName($name); - $reading = fopen($fullName, 'r'); - $writing = fopen($fullName . '.tmp', 'w'); - $found = false; - while (!feof($reading)) { - $line = fgets($reading); - if (preg_match_all('/^\$a\-\>config\[\'' . $cat . '\',\'' . $key . '\'\]\s*=\s\'*(.*?)\'$/', $line, $matches, PREG_SET_ORDER)) { - $writeLine = $key . ' = ' . $value . PHP_EOL; - $found = true; - } else { - $writeLine = $line; - } - fputs($writing, $writeLine); - } - if (!$found) { - $writeLine = $key . ' = ' . $value . PHP_EOL; - fputs($writing, $writeLine); - } - fclose($reading); - fclose($writing); - rename($fullName, $fullName . '.old'); - rename($fullName . '.tmp', $fullName); - } -} diff --git a/src/Util/Config/ConfigFileLoader.php b/src/Util/Config/ConfigFileLoader.php new file mode 100644 index 0000000000..67a44a0274 --- /dev/null +++ b/src/Util/Config/ConfigFileLoader.php @@ -0,0 +1,219 @@ +appMode = $mode; + } + + /** + * Load the configuration files into an configuration cache + * + * First loads the default value for all the configuration keys, then the legacy configuration files, then the + * expected local.config.php + * + * @param IConfigCache The config cache to load to + * + * @throws \Exception + */ + public function setupCache(IConfigCache $config) + { + $config->load($this->loadCoreConfig('defaults')); + $config->load($this->loadCoreConfig('settings')); + + $config->load($this->loadLegacyConfig('htpreconfig'), true); + $config->load($this->loadLegacyConfig('htconfig'), true); + + $config->load($this->loadCoreConfig('local'), true); + + // In case of install mode, add the found basepath (because there isn't a basepath set yet + if ($this->appMode->isInstall()) { + // Setting at least the basepath we know + $config->set('system', 'basepath', $this->baseDir); + } + } + + /** + * Tries to load the specified core-configuration and returns the config array. + * + * @param string $name The name of the configuration (default is empty, which means 'local') + * + * @return array The config array (empty if no config found) + * + * @throws \Exception if the configuration file isn't readable + */ + public function loadCoreConfig($name = '') + { + if (!empty($this->getConfigFullName($name))) { + return $this->loadConfigFile($this->getConfigFullName($name)); + } elseif (!empty($this->getIniFullName($name))) { + return $this->loadINIConfigFile($this->getIniFullName($name)); + } else { + return []; + } + } + + /** + * Tries to load the specified addon-configuration and returns the config array. + * + * @param string $name The name of the configuration + * + * @return array The config array (empty if no config found) + * + * @throws \Exception if the configuration file isn't readable + */ + public function loadAddonConfig($name) + { + $filepath = $this->baseDir . DIRECTORY_SEPARATOR . // /var/www/html/ + Addon::DIRECTORY . DIRECTORY_SEPARATOR . // addon/ + $name . DIRECTORY_SEPARATOR . // openstreetmap/ + self::SUBDIRECTORY . DIRECTORY_SEPARATOR . // config/ + $name . ".config.php"; // openstreetmap.config.php + + if (file_exists($filepath)) { + return $this->loadConfigFile($filepath); + } else { + return []; + } + } + + /** + * Tries to load the legacy config files (.htconfig.php, .htpreconfig.php) and returns the config array. + * + * @param string $name The name of the config file (default is empty, which means .htconfig.php) + * + * @return array The configuration array (empty if no config found) + * + * @deprecated since version 2018.09 + */ + private function loadLegacyConfig($name = '') + { + $config = []; + if (!empty($this->getHtConfigFullName($name))) { + $a = new \stdClass(); + $a->config = []; + include $this->getHtConfigFullName($name); + + $htConfigCategories = array_keys($a->config); + + // map the legacy configuration structure to the current structure + foreach ($htConfigCategories as $htConfigCategory) { + if (is_array($a->config[$htConfigCategory])) { + $keys = array_keys($a->config[$htConfigCategory]); + + foreach ($keys as $key) { + $config[$htConfigCategory][$key] = $a->config[$htConfigCategory][$key]; + } + } else { + $config['config'][$htConfigCategory] = $a->config[$htConfigCategory]; + } + } + + unset($a); + + if (isset($db_host)) { + $config['database']['hostname'] = $db_host; + unset($db_host); + } + if (isset($db_user)) { + $config['database']['username'] = $db_user; + unset($db_user); + } + if (isset($db_pass)) { + $config['database']['password'] = $db_pass; + unset($db_pass); + } + if (isset($db_data)) { + $config['database']['database'] = $db_data; + unset($db_data); + } + if (isset($config['system']['db_charset'])) { + $config['database']['charset'] = $config['system']['db_charset']; + } + if (isset($pidfile)) { + $config['system']['pidfile'] = $pidfile; + unset($pidfile); + } + if (isset($default_timezone)) { + $config['system']['default_timezone'] = $default_timezone; + unset($default_timezone); + } + if (isset($lang)) { + $config['system']['language'] = $lang; + unset($lang); + } + } + + return $config; + } + + /** + * Tries to load the specified legacy configuration file and returns the config array. + * + * @deprecated since version 2018.12 + * @param string $filepath + * + * @return array The configuration array + * @throws \Exception + */ + private function loadINIConfigFile($filepath) + { + $contents = include($filepath); + + $config = parse_ini_string($contents, true, INI_SCANNER_TYPED); + + if ($config === false) { + throw new \Exception('Error parsing INI config file ' . $filepath); + } + + return $config; + } + + /** + * Tries to load the specified configuration file and returns the config array. + * + * The config format is PHP array and the template for configuration files is the following: + * + * [ + * 'key' => 'value', + * ], + * ]; + * + * @param string $filepath The filepath of the + * @return array The config array0 + * + * @throws \Exception if the config cannot get loaded. + */ + private function loadConfigFile($filepath) + { + $config = include($filepath); + + if (!is_array($config)) { + throw new \Exception('Error loading config file ' . $filepath); + } + + return $config; + } +} diff --git a/src/Util/Config/ConfigFileManager.php b/src/Util/Config/ConfigFileManager.php new file mode 100644 index 0000000000..729e59d746 --- /dev/null +++ b/src/Util/Config/ConfigFileManager.php @@ -0,0 +1,90 @@ +baseDir = $baseDir; + $this->configDir = $baseDir . DIRECTORY_SEPARATOR . self::SUBDIRECTORY; + } + + /** + * Gets the full name (including the path) for a *.config.php (default is local.config.php) + * + * @param string $name The config name (default is empty, which means local.config.php) + * + * @return string The full name or empty if not found + */ + protected function getConfigFullName($name = '') + { + $name = !empty($name) ? $name : self::CONFIG_LOCAL; + + $fullName = $this->configDir . DIRECTORY_SEPARATOR . $name . '.config.php'; + return file_exists($fullName) ? $fullName : ''; + } + + /** + * Gets the full name (including the path) for a *.ini.php (default is local.ini.php) + * + * @param string $name The config name (default is empty, which means local.ini.php) + * + * @return string The full name or empty if not found + */ + protected function getIniFullName($name = '') + { + $name = !empty($name) ? $name : self::CONFIG_INI; + + $fullName = $this->configDir . DIRECTORY_SEPARATOR . $name . '.ini.php'; + return file_exists($fullName) ? $fullName : ''; + } + + /** + * Gets the full name (including the path) for a .*.php (default is .htconfig.php) + * + * @param string $name The config name (default is empty, which means .htconfig.php) + * + * @return string The full name or empty if not found + */ + protected function getHtConfigFullName($name = '') + { + $name = !empty($name) ? $name : self::CONFIG_HTCONFIG; + + $fullName = $this->baseDir . DIRECTORY_SEPARATOR . '.' . $name . '.php'; + return file_exists($fullName) ? $fullName : ''; + } +} diff --git a/src/Util/Config/ConfigFileSaver.php b/src/Util/Config/ConfigFileSaver.php new file mode 100644 index 0000000000..2c127188f1 --- /dev/null +++ b/src/Util/Config/ConfigFileSaver.php @@ -0,0 +1,294 @@ +settings[] = ['cat' => $cat, 'key' => $key, 'value' => $value]; + } + + /** + * Resetting all added configuration entries so far + */ + public function reset() + { + $this->settings = []; + } + + /** + * Save all added configuration entries to the given config files + * After updating the config entries, all configuration entries will be reseted + * + * @param string $name The name of the configuration file (default is empty, which means the default name each type) + * + * @return bool true, if at least one configuration file was successfully updated + */ + public function saveToConfigFile($name = '') + { + $saved = false; + + // Check for the *.config.php file inside the /config/ path + list($reading, $writing) = $this->openFile($this->getConfigFullName($name)); + if (isset($reading) && isset($writing)) { + $this->saveConfigFile($reading, $writing); + // Close the current file handler and rename them + if ($this->closeFile($this->getConfigFullName($name), $reading, $writing)) { + // just return true, if everything went fine + $saved = true; + } + } + + // Check for the *.ini.php file inside the /config/ path + list($reading, $writing) = $this->openFile($this->getIniFullName($name)); + if (isset($reading) && isset($writing)) { + $this->saveINIConfigFile($reading, $writing); + // Close the current file handler and rename them + if ($this->closeFile($this->getIniFullName($name), $reading, $writing)) { + // just return true, if everything went fine + $saved = true; + } + } + + // Check for the *.php file (normally .htconfig.php) inside the / path + list($reading, $writing) = $this->openFile($this->getHtConfigFullName($name)); + if (isset($reading) && isset($writing)) { + $this->saveToLegacyConfig($reading, $writing); + // Close the current file handler and rename them + if ($this->closeFile($this->getHtConfigFullName($name), $reading, $writing)) { + // just return true, if everything went fine + $saved = true; + } + } + + $this->reset(); + + return $saved; + } + + /** + * Opens a config file and returns two handler for reading and writing + * + * @param string $fullName The full name of the current config + * + * @return array An array containing the two reading and writing handler + */ + private function openFile($fullName) + { + if (empty($fullName)) { + return [null, null]; + } + + $reading = fopen($fullName, 'r'); + + if (!$reading) { + return [null, null]; + } + + $writing = fopen($fullName . '.tmp', 'w'); + + if (!$writing) { + fclose($reading); + return [null, null]; + } + + return [$reading, $writing]; + } + + /** + * Close and rename the config file + * + * @param string $fullName The full name of the current config + * @param resource $reading The reading resource handler + * @param resource $writing The writing resource handler + * + * @return bool True, if the close was successful + */ + private function closeFile($fullName, $reading, $writing) + { + fclose($reading); + fclose($writing); + + if (!rename($fullName, $fullName . '.old')) { + return false; + } + + if (!rename($fullName . '.tmp', $fullName)) { + // revert the move of the current config file to have at least the old config + rename($fullName . '.old', $fullName); + return false; + } + + return true; + } + + /** + * Saves all configuration values to a config file + * + * @param resource $reading The reading handler + * @param resource $writing The writing handler + */ + private function saveConfigFile($reading, $writing) + { + $settingsCount = count(array_keys($this->settings)); + $categoryFound = array_fill(0, $settingsCount, false); + $categoryBracketFound = array_fill(0, $settingsCount, false);; + $lineFound = array_fill(0, $settingsCount, false);; + $lineArrowFound = array_fill(0, $settingsCount, false);; + + while (!feof($reading)) { + + $line = fgets($reading); + + // check for each added setting if we have to replace a config line + for ($i = 0; $i < $settingsCount; $i++) { + + // find the first line like "'system' =>" + if (!$categoryFound[$i] && stristr($line, sprintf('\'%s\'', $this->settings[$i]['cat']))) { + $categoryFound[$i] = true; + } + + // find the first line with a starting bracket ( "[" ) + if ($categoryFound[$i] && !$categoryBracketFound[$i] && stristr($line, '[')) { + $categoryBracketFound[$i] = true; + } + + // find the first line with the key like "'value'" + if ($categoryBracketFound[$i] && !$lineFound[$i] && stristr($line, sprintf('\'%s\'', $this->settings[$i]['key']))) { + $lineFound[$i] = true; + } + + // find the first line with an arrow ("=>") after finding the key + if ($lineFound[$i] && !$lineArrowFound[$i] && stristr($line, '=>')) { + $lineArrowFound[$i] = true; + } + + // find the current value and replace it + if ($lineArrowFound[$i] && preg_match_all('/\'(.*?)\'/', $line, $matches, PREG_SET_ORDER)) { + $lineVal = end($matches)[0]; + $line = str_replace($lineVal, '\'' . $this->settings[$i]['value'] . '\'', $line); + $categoryFound[$i] = false; + $categoryBracketFound[$i] = false; + $lineFound[$i] = false; + $lineArrowFound[$i] = false; + // if a line contains a closing bracket for the category ( "]" ) and we didn't find the key/value pair, + // add it as a new line before the closing bracket + } elseif ($categoryBracketFound[$i] && !$lineArrowFound[$i] && stristr($line, ']')) { + $categoryFound[$i] = false; + $categoryBracketFound[$i] = false; + $lineFound[$i] = false; + $lineArrowFound[$i] = false; + $newLine = sprintf(self::INDENT . self::INDENT . '\'%s\' => \'%s\',' . PHP_EOL, $this->settings[$i]['key'], $this->settings[$i]['value']); + $line = $newLine . $line; + } + } + + fputs($writing, $line); + } + } + + /** + * Saves a value to a ini file + * + * @param resource $reading The reading handler + * @param resource $writing The writing handler + */ + private function saveINIConfigFile($reading, $writing) + { + $settingsCount = count(array_keys($this->settings)); + $categoryFound = array_fill(0, $settingsCount, false); + + while (!feof($reading)) { + + $line = fgets($reading); + + // check for each added setting if we have to replace a config line + for ($i = 0; $i < $settingsCount; $i++) { + + if (!$categoryFound[$i] && stristr($line, sprintf('[%s]', $this->settings[$i]['cat']))) { + $categoryFound[$i] = true; + } elseif ($categoryFound[$i] && preg_match_all('/^' . $this->settings[$i]['key'] . '\s*=\s*(.*?)$/', $line, $matches, PREG_SET_ORDER)) { + $line = $this->settings[$i]['key'] . ' = ' . $this->settings[$i]['value'] . PHP_EOL; + $categoryFound[$i] = false; + } elseif ($categoryFound[$i] && (preg_match_all('/^\[.*?\]$/', $line) || preg_match_all('/^INI;.*$/', $line))) { + $categoryFound[$i] = false; + $newLine = $this->settings[$i]['key'] . ' = ' . $this->settings[$i]['value'] . PHP_EOL; + $line = $newLine . $line; + } + } + + fputs($writing, $line); + } + } + + /** + * Saves a value to a .php file (normally .htconfig.php) + * + * @param resource $reading The reading handler + * @param resource $writing The writing handler + */ + private function saveToLegacyConfig($reading, $writing) + { + $settingsCount = count(array_keys($this->settings)); + $found = array_fill(0, $settingsCount, false); + while (!feof($reading)) { + + $line = fgets($reading); + + // check for each added setting if we have to replace a config line + for ($i = 0; $i < $settingsCount; $i++) { + + if ($this->settings[$i]['cat'] !== 'config' && preg_match_all('/^\$a\-\>config\[\'' . $this->settings[$i]['cat'] . '\'\]\[\'' . $this->settings[$i]['key'] . '\'\]\s*=\s\'*(.*?)\';$/', $line, $matches, PREG_SET_ORDER)) { + $line = '$a->config[\'' . $this->settings[$i]['cat'] . '\'][\'' . $this->settings[$i]['key'] . '\'] = \'' . $this->settings[$i]['value'] . '\';' . PHP_EOL; + $found[$i] = true; + } elseif ($this->settings[$i]['cat'] === 'config' && preg_match_all('/^\$a\-\>config\[\'' . $this->settings[$i]['key'] . '\'\]\s*=\s\'*(.*?)\';$/', $line, $matches, PREG_SET_ORDER)) { + $line = '$a->config[\'' . $this->settings[$i]['key'] . '\'] = \'' . $this->settings[$i]['value'] . '\';' . PHP_EOL; + $found[$i] = true; + } + } + + fputs($writing, $line); + } + + for ($i = 0; $i < $settingsCount; $i++) { + if (!$found[$i]) { + if ($this->settings[$i]['cat'] !== 'config') { + $line = '$a->config[\'' . $this->settings[$i]['cat'] . '\'][\'' . $this->settings[$i]['key'] . '\'] = \'' . $this->settings[$i]['value'] . '\';' . PHP_EOL; + } else { + $line = '$a->config[\'' . $this->settings[$i]['key'] . '\'] = \'' . $this->settings[$i]['value'] . '\';' . PHP_EOL; + } + + fputs($writing, $line); + } + } + } +} diff --git a/tests/DatabaseTest.php b/tests/DatabaseTest.php index d434674061..fec31b05af 100644 --- a/tests/DatabaseTest.php +++ b/tests/DatabaseTest.php @@ -9,7 +9,7 @@ use Friendica\App; use Friendica\Database\DBA; use Friendica\Factory; use Friendica\Util\BasePath; -use Friendica\Util\Config\ConfigCacheLoader; +use Friendica\Util\Config\ConfigFileLoader; use Friendica\Util\Profiler; use PHPUnit\DbUnit\DataSet\YamlDataSet; use PHPUnit\DbUnit\TestCaseTrait; @@ -43,7 +43,7 @@ abstract class DatabaseTest extends MockedTest $basePath = BasePath::create(dirname(__DIR__)); $mode = new App\Mode($basePath); - $configLoader = new ConfigCacheLoader($basePath, $mode); + $configLoader = new ConfigFileLoader($basePath, $mode); $config = Factory\ConfigFactory::createCache($configLoader); $profiler = \Mockery::mock(Profiler::class); diff --git a/tests/datasets/config/.htconfig.test.php b/tests/datasets/config/.htconfig.test.php deleted file mode 100644 index 193142c49c..0000000000 --- a/tests/datasets/config/.htconfig.test.php +++ /dev/null @@ -1,63 +0,0 @@ -config['system']['db_charset'] = "anotherCharset"; - -// Choose a legal default timezone. If you are unsure, use "America/Los_Angeles". -// It can be changed later and only applies to timestamps for anonymous viewers. -$default_timezone = 'Europe/Berlin'; -$lang = 'fr'; - -// What is your site name? -$a->config['sitename'] = "Friendica My Network"; - -// Your choices are REGISTER_OPEN, REGISTER_APPROVE, or REGISTER_CLOSED. -// Be certain to create your own personal account before setting -// REGISTER_CLOSED. 'register_text' (if set) will be displayed prominently on -// the registration page. REGISTER_APPROVE requires you set 'admin_email' -// to the email address of an already registered person who can authorise -// and/or approve/deny the request. -// In order to perform system administration via the admin panel, admin_email -// must precisely match the email address of the person logged in. -$a->config['register_policy'] = REGISTER_OPEN; -$a->config['register_text'] = 'A register text'; -$a->config['admin_email'] = 'admin@friendica.local'; -$a->config['admin_nickname'] = 'Friendly admin'; - -// Maximum size of an imported message, 0 is unlimited -$a->config['max_import_size'] = 999; - -// maximum size of uploaded photos -$a->config['system']['maximagesize'] = 666; - -// Location of PHP command line processor -$a->config['php_path'] = '/another/php'; - -// PuSH - aka pubsubhubbub URL. This makes delivery of public posts as fast as private posts -$a->config['system']['huburl'] = '[internal]'; - -// allowed themes (change this from admin panel after installation) -$a->config['system']['allowed_themes'] = 'quattro,vier,duepuntozero'; - -// default system theme -$a->config['system']['theme'] = 'duepuntozero'; - -// By default allow pseudonyms -$a->config['system']['no_regfullname'] = true; - -//Deny public access to the local directory -//$a->config['system']['block_local_dir'] = false; -// Location of the global directory -$a->config['system']['directory'] = 'http://another.url'; diff --git a/tests/datasets/config/local.config.php b/tests/datasets/config/local.config.php index 8a392909f2..f28e1f2e85 100644 --- a/tests/datasets/config/local.config.php +++ b/tests/datasets/config/local.config.php @@ -23,5 +23,6 @@ return [ 'system' => [ 'default_timezone' => 'UTC', 'language' => 'en', + 'theme' => 'frio', ], ]; diff --git a/tests/datasets/config/local.ini.php b/tests/datasets/config/local.ini.php index 1fea0b028e..a9e462d13e 100644 --- a/tests/datasets/config/local.ini.php +++ b/tests/datasets/config/local.ini.php @@ -11,6 +11,9 @@ username = testuser password = testpw database = testdb +[system] +theme = frio + [config] admin_email = admin@test.it INI; diff --git a/tests/include/ApiTest.php b/tests/include/ApiTest.php index bd1b041082..5c2e1657af 100644 --- a/tests/include/ApiTest.php +++ b/tests/include/ApiTest.php @@ -13,7 +13,7 @@ use Friendica\Core\System; use Friendica\Factory; use Friendica\Network\HTTPException; use Friendica\Util\BasePath; -use Friendica\Util\Config\ConfigCacheLoader; +use Friendica\Util\Config\ConfigFileLoader; use Monolog\Handler\TestHandler; require_once __DIR__ . '/../../include/api.php'; @@ -38,7 +38,7 @@ class ApiTest extends DatabaseTest { $basePath = BasePath::create(dirname(__DIR__) . '/../'); $mode = new App\Mode($basePath); - $configLoader = new ConfigCacheLoader($basePath, $mode); + $configLoader = new ConfigFileLoader($basePath, $mode); $configCache = Factory\ConfigFactory::createCache($configLoader); $profiler = Factory\ProfilerFactory::create($configCache); Factory\DBFactory::init($basePath, $configCache, $profiler, $_SERVER); diff --git a/tests/src/Database/DBATest.php b/tests/src/Database/DBATest.php index 28f5afbd77..bc8743da5b 100644 --- a/tests/src/Database/DBATest.php +++ b/tests/src/Database/DBATest.php @@ -7,7 +7,7 @@ use Friendica\Database\DBA; use Friendica\Factory; use Friendica\Test\DatabaseTest; use Friendica\Util\BasePath; -use Friendica\Util\Config\ConfigCacheLoader; +use Friendica\Util\Config\ConfigFileLoader; class DBATest extends DatabaseTest { @@ -15,7 +15,7 @@ class DBATest extends DatabaseTest { $basePath = BasePath::create(dirname(__DIR__) . '/../../'); $mode = new App\Mode($basePath); - $configLoader = new ConfigCacheLoader($basePath, $mode); + $configLoader = new ConfigFileLoader($basePath, $mode); $configCache = Factory\ConfigFactory::createCache($configLoader); $profiler = Factory\ProfilerFactory::create($configCache); Factory\DBFactory::init($basePath, $configCache, $profiler, $_SERVER); diff --git a/tests/src/Database/DBStructureTest.php b/tests/src/Database/DBStructureTest.php index 65d5c85a42..0c1da172f5 100644 --- a/tests/src/Database/DBStructureTest.php +++ b/tests/src/Database/DBStructureTest.php @@ -7,7 +7,7 @@ use Friendica\Database\DBStructure; use Friendica\Factory; use Friendica\Test\DatabaseTest; use Friendica\Util\BasePath; -use Friendica\Util\Config\ConfigCacheLoader; +use Friendica\Util\Config\ConfigFileLoader; class DBStructureTest extends DatabaseTest { @@ -15,7 +15,7 @@ class DBStructureTest extends DatabaseTest { $basePath = BasePath::create(dirname(__DIR__) . '/../../'); $mode = new App\Mode($basePath); - $configLoader = new ConfigCacheLoader($basePath, $mode); + $configLoader = new ConfigFileLoader($basePath, $mode); $configCache = Factory\ConfigFactory::createCache($configLoader); $profiler = Factory\ProfilerFactory::create($configCache); Factory\DBFactory::init($basePath, $configCache, $profiler, $_SERVER); diff --git a/tests/src/Util/Config/ConfigCacheLoaderTest.php b/tests/src/Util/Config/ConfigCacheLoaderTest.php deleted file mode 100644 index 45245d47cc..0000000000 --- a/tests/src/Util/Config/ConfigCacheLoaderTest.php +++ /dev/null @@ -1,205 +0,0 @@ -setUpVfsDir(); - - $this->mode = \Mockery::mock(App\Mode::class); - $this->mode->shouldReceive('isInstall')->andReturn(true); - } - - /** - * Test the loadConfigFiles() method with default values - */ - public function testLoadConfigFiles() - { - $configCacheLoader = new ConfigCacheLoader($this->root->url(), $this->mode); - $configCache = new ConfigCache(); - - $configCacheLoader->loadConfigFiles($configCache); - - $this->assertEquals($this->root->url(), $configCache->get('system', 'basepath')); - } - - /** - * Test the loadConfigFiles() method with a wrong local.config.php - * @expectedException \Exception - * @expectedExceptionMessageRegExp /Error loading config file \w+/ - */ - public function testLoadConfigWrong() - { - $this->delConfigFile('local.config.php'); - - vfsStream::newFile('local.config.php') - ->at($this->root->getChild('config')) - ->setContent('root->url(), $this->mode); - $configCache = new ConfigCache(); - - $configCacheLoader->loadConfigFiles($configCache); - } - - /** - * Test the loadConfigFiles() method with a local.config.php file - */ - public function testLoadConfigFilesLocal() - { - $this->delConfigFile('local.config.php'); - - $file = dirname(__DIR__) . DIRECTORY_SEPARATOR . - '..' . DIRECTORY_SEPARATOR . - '..' . DIRECTORY_SEPARATOR . - 'datasets' . DIRECTORY_SEPARATOR . - 'config' . DIRECTORY_SEPARATOR . - 'local.config.php'; - - vfsStream::newFile('local.config.php') - ->at($this->root->getChild('config')) - ->setContent(file_get_contents($file)); - - $configCacheLoader = new ConfigCacheLoader($this->root->url(), $this->mode); - $configCache = new ConfigCache(); - - $configCacheLoader->loadConfigFiles($configCache); - - $this->assertEquals('testhost', $configCache->get('database', 'hostname')); - $this->assertEquals('testuser', $configCache->get('database', 'username')); - $this->assertEquals('testpw', $configCache->get('database', 'password')); - $this->assertEquals('testdb', $configCache->get('database', 'database')); - - $this->assertEquals('admin@test.it', $configCache->get('config', 'admin_email')); - $this->assertEquals('Friendica Social Network', $configCache->get('config', 'sitename')); - } - - /** - * Test the loadConfigFile() method with a local.ini.php file - */ - public function testLoadConfigFilesINI() - { - $this->delConfigFile('local.config.php'); - - $file = dirname(__DIR__) . DIRECTORY_SEPARATOR . - '..' . DIRECTORY_SEPARATOR . - '..' . DIRECTORY_SEPARATOR . - 'datasets' . DIRECTORY_SEPARATOR . - 'config' . DIRECTORY_SEPARATOR . - 'local.ini.php'; - - vfsStream::newFile('local.ini.php') - ->at($this->root->getChild('config')) - ->setContent(file_get_contents($file)); - - $configCacheLoader = new ConfigCacheLoader($this->root->url(), $this->mode); - $configCache = new ConfigCache(); - - $configCacheLoader->loadConfigFiles($configCache); - - $this->assertEquals('testhost', $configCache->get('database', 'hostname')); - $this->assertEquals('testuser', $configCache->get('database', 'username')); - $this->assertEquals('testpw', $configCache->get('database', 'password')); - $this->assertEquals('testdb', $configCache->get('database', 'database')); - - $this->assertEquals('admin@test.it', $configCache->get('config', 'admin_email')); - } - - /** - * Test the loadConfigFile() method with a .htconfig.php file - */ - public function testLoadConfigFilesHtconfig() - { - $this->delConfigFile('local.config.php'); - - $file = dirname(__DIR__) . DIRECTORY_SEPARATOR . - '..' . DIRECTORY_SEPARATOR . - '..' . DIRECTORY_SEPARATOR . - 'datasets' . DIRECTORY_SEPARATOR . - 'config' . DIRECTORY_SEPARATOR . - '.htconfig.test.php'; - - vfsStream::newFile('.htconfig.php') - ->at($this->root) - ->setContent(file_get_contents($file)); - - $configCacheLoader = new ConfigCacheLoader($this->root->url(), $this->mode); - $configCache = new ConfigCache(); - - $configCacheLoader->loadConfigFiles($configCache); - - $this->assertEquals('testhost', $configCache->get('database', 'hostname')); - $this->assertEquals('testuser', $configCache->get('database', 'username')); - $this->assertEquals('testpw', $configCache->get('database', 'password')); - $this->assertEquals('testdb', $configCache->get('database', 'database')); - $this->assertEquals('anotherCharset', $configCache->get('database', 'charset')); - - $this->assertEquals('/var/run/friendica.pid', $configCache->get('system', 'pidfile')); - $this->assertEquals('Europe/Berlin', $configCache->get('system', 'default_timezone')); - $this->assertEquals('fr', $configCache->get('system', 'language')); - - $this->assertEquals('admin@friendica.local', $configCache->get('config', 'admin_email')); - $this->assertEquals('Friendly admin', $configCache->get('config', 'admin_nickname')); - - $this->assertEquals('/another/php', $configCache->get('config', 'php_path')); - $this->assertEquals('999', $configCache->get('config', 'max_import_size')); - $this->assertEquals('666', $configCache->get('system', 'maximagesize')); - - $this->assertEquals('quattro,vier,duepuntozero', $configCache->get('system', 'allowed_themes')); - $this->assertEquals('1', $configCache->get('system', 'no_regfullname')); - } - - public function testLoadAddonConfig() - { - $structure = [ - 'addon' => [ - 'test' => [ - 'config' => [], - ], - ], - ]; - - vfsStream::create($structure, $this->root); - - $file = dirname(__DIR__) . DIRECTORY_SEPARATOR . - '..' . DIRECTORY_SEPARATOR . - '..' . DIRECTORY_SEPARATOR . - 'datasets' . DIRECTORY_SEPARATOR . - 'config' . DIRECTORY_SEPARATOR . - 'local.config.php'; - - vfsStream::newFile('test.config.php') - ->at($this->root->getChild('addon')->getChild('test')->getChild('config')) - ->setContent(file_get_contents($file)); - - $configCacheLoader = new ConfigCacheLoader($this->root->url(), $this->mode); - - $conf = $configCacheLoader->loadAddonConfig('test'); - - $this->assertEquals('testhost', $conf['database']['hostname']); - $this->assertEquals('testuser', $conf['database']['username']); - $this->assertEquals('testpw', $conf['database']['password']); - $this->assertEquals('testdb', $conf['database']['database']); - - $this->assertEquals('admin@test.it', $conf['config']['admin_email']); - } -} diff --git a/tests/src/Util/Config/ConfigCacheSaverTest.php b/tests/src/Util/Config/ConfigCacheSaverTest.php deleted file mode 100644 index a0d9502c2a..0000000000 --- a/tests/src/Util/Config/ConfigCacheSaverTest.php +++ /dev/null @@ -1,133 +0,0 @@ -setUpVfsDir(); - $this->mode = \Mockery::mock(App\Mode::class); - $this->mode->shouldReceive('isInstall')->andReturn(true); - } - /** - * Test the saveToConfigFile() method with a local.config.php file - */ - public function testSaveToConfigFileLocal() - { - $this->delConfigFile('local.config.php'); - $file = dirname(__DIR__) . DIRECTORY_SEPARATOR . - '..' . DIRECTORY_SEPARATOR . - '..' . DIRECTORY_SEPARATOR . - 'datasets' . DIRECTORY_SEPARATOR . - 'config' . DIRECTORY_SEPARATOR . - 'local.config.php'; - - vfsStream::newFile('local.config.php') - ->at($this->root->getChild('config')) - ->setContent(file_get_contents($file)); - - $configCacheSaver = new ConfigCacheSaver($this->root->url()); - $configCacheLoader = new ConfigCacheLoader($this->root->url(), $this->mode); - $configCache = new ConfigCache(); - $configCacheLoader->loadConfigFiles($configCache); - - $this->assertEquals('admin@test.it', $configCache->get('config', 'admin_email')); - $this->assertNull($configCache->get('config', 'test_val')); - - $configCacheSaver->saveToConfigFile('config', 'admin_email', 'new@mail.it'); - $configCacheSaver->saveToConfigFile('config', 'test_val', 'Testing$!"$with@all.we can!'); - - $newConfigCache = new ConfigCache(); - $configCacheLoader->loadConfigFiles($newConfigCache); - - $this->assertEquals('new@mail.it', $newConfigCache->get('config', 'admin_email')); - $this->assertEquals('Testing$!"$with@all.we can!', $newConfigCache->get('config', 'test_val')); - $this->assertTrue($this->root->hasChild('config' . DIRECTORY_SEPARATOR . 'local.config.php')); - $this->assertTrue($this->root->hasChild('config' . DIRECTORY_SEPARATOR . 'local.config.php.old')); - $this->assertFalse($this->root->hasChild('config' . DIRECTORY_SEPARATOR . 'local.config.php.tmp')); - - $this->assertEquals(file_get_contents($file), file_get_contents($this->root->getChild('config' . DIRECTORY_SEPARATOR . 'local.config.php.old')->url())); - } - /** - * Test the saveToConfigFile() method with a local.ini.php file - */ - public function testSaveToConfigFileINI() - { - $this->delConfigFile('local.config.php'); - $file = dirname(__DIR__) . DIRECTORY_SEPARATOR . - '..' . DIRECTORY_SEPARATOR . - '..' . DIRECTORY_SEPARATOR . - 'datasets' . DIRECTORY_SEPARATOR . - 'config' . DIRECTORY_SEPARATOR . - 'local.ini.php'; - vfsStream::newFile('local.ini.php') - ->at($this->root->getChild('config')) - ->setContent(file_get_contents($file)); - $configCacheSaver = new ConfigCacheSaver($this->root->url()); - $configCacheLoader = new ConfigCacheLoader($this->root->url(), $this->mode); - $configCache = new ConfigCache(); - $configCacheLoader->loadConfigFiles($configCache); - $this->assertEquals('admin@test.it', $configCache->get('config', 'admin_email')); - $this->assertNull($configCache->get('config', 'test_val')); - $configCacheSaver->saveToConfigFile('config', 'admin_email', 'new@mail.it'); - $configCacheSaver->saveToConfigFile('config', 'test_val', "Testing@with.all we can"); - $newConfigCache = new ConfigCache(); - $configCacheLoader->loadConfigFiles($newConfigCache); - $this->assertEquals('new@mail.it', $newConfigCache->get('config', 'admin_email')); - $this->assertEquals("Testing@with.all we can", $newConfigCache->get('config', 'test_val')); - $this->assertTrue($this->root->hasChild('config' . DIRECTORY_SEPARATOR . 'local.ini.php')); - $this->assertTrue($this->root->hasChild('config' . DIRECTORY_SEPARATOR . 'local.ini.php.old')); - $this->assertFalse($this->root->hasChild('config' . DIRECTORY_SEPARATOR . 'local.ini.php.tmp')); - $this->assertEquals(file_get_contents($file), file_get_contents($this->root->getChild('config' . DIRECTORY_SEPARATOR . 'local.ini.old')->url())); - } - /** - * Test the saveToConfigFile() method with a .htconfig.php file - * @todo fix it after 2019.03 merge to develop - */ - public function testSaveToConfigFileHtconfig() - { - $this->markTestSkipped('Needs 2019.03 merge to develop first'); - $this->delConfigFile('local.config.php'); - $file = dirname(__DIR__) . DIRECTORY_SEPARATOR . - '..' . DIRECTORY_SEPARATOR . - '..' . DIRECTORY_SEPARATOR . - '..' . DIRECTORY_SEPARATOR . - 'datasets' . DIRECTORY_SEPARATOR . - 'config' . DIRECTORY_SEPARATOR . - '.htconfig.test.php'; - vfsStream::newFile('.htconfig.php') - ->at($this->root) - ->setContent(file_get_contents($file)); - $configCacheSaver = new ConfigCacheSaver($this->root->url(), $this->mode); - $configCache = new ConfigCache(); - $configCacheSaver->loadConfigFiles($configCache); - $this->assertEquals('admin@test.it', $configCache->get('config', 'admin_email')); - $this->assertEquals('!!', $configCache->get('config', 'test_val')); - $configCacheSaver->saveToConfigFile('config', 'admin_email', 'new@mail.it'); - $configCacheSaver->saveToConfigFile('config', 'test_val', 'Testing$!"$with@all.we can!'); - $newConfigCache = new ConfigCache(); - $configCacheSaver->loadConfigFiles($newConfigCache); - $this->assertEquals('new@mail.it', $newConfigCache->get('config', 'admin_email')); - $this->assertEquals('Testing$!"$with@all.we can!', $newConfigCache->get('config', 'test_val')); - $this->assertTrue($this->root->hasChild('config' . DIRECTORY_SEPARATOR . '.htconfig.php')); - $this->assertTrue($this->root->hasChild('config' . DIRECTORY_SEPARATOR . '.htconfig.php.old')); - $this->assertFalse($this->root->hasChild('config' . DIRECTORY_SEPARATOR . '.htconfig.php.tmp')); - $this->assertEquals(file_get_contents($file), file_get_contents($this->root->getChild('config' . DIRECTORY_SEPARATOR . '.htconfig.php.old')->url())); - } -} diff --git a/tests/src/Util/Config/ConfigFileLoaderTest.php b/tests/src/Util/Config/ConfigFileLoaderTest.php new file mode 100644 index 0000000000..ad0fe8afca --- /dev/null +++ b/tests/src/Util/Config/ConfigFileLoaderTest.php @@ -0,0 +1,205 @@ +setUpVfsDir(); + + $this->mode = \Mockery::mock(App\Mode::class); + $this->mode->shouldReceive('isInstall')->andReturn(true); + } + + /** + * Test the loadConfigFiles() method with default values + */ + public function testLoadConfigFiles() + { + $configFileLoader = new ConfigFileLoader($this->root->url(), $this->mode); + $configCache = new ConfigCache(); + + $configFileLoader->setupCache($configCache); + + $this->assertEquals($this->root->url(), $configCache->get('system', 'basepath')); + } + + /** + * Test the loadConfigFiles() method with a wrong local.config.php + * @expectedException \Exception + * @expectedExceptionMessageRegExp /Error loading config file \w+/ + */ + public function testLoadConfigWrong() + { + $this->delConfigFile('local.config.php'); + + vfsStream::newFile('local.config.php') + ->at($this->root->getChild('config')) + ->setContent('root->url(), $this->mode); + $configCache = new ConfigCache(); + + $configFileLoader->setupCache($configCache); + } + + /** + * Test the loadConfigFiles() method with a local.config.php file + */ + public function testLoadConfigFilesLocal() + { + $this->delConfigFile('local.config.php'); + + $file = dirname(__DIR__) . DIRECTORY_SEPARATOR . + '..' . DIRECTORY_SEPARATOR . + '..' . DIRECTORY_SEPARATOR . + 'datasets' . DIRECTORY_SEPARATOR . + 'config' . DIRECTORY_SEPARATOR . + 'local.config.php'; + + vfsStream::newFile('local.config.php') + ->at($this->root->getChild('config')) + ->setContent(file_get_contents($file)); + + $configFileLoader = new ConfigFileLoader($this->root->url(), $this->mode); + $configCache = new ConfigCache(); + + $configFileLoader->setupCache($configCache); + + $this->assertEquals('testhost', $configCache->get('database', 'hostname')); + $this->assertEquals('testuser', $configCache->get('database', 'username')); + $this->assertEquals('testpw', $configCache->get('database', 'password')); + $this->assertEquals('testdb', $configCache->get('database', 'database')); + + $this->assertEquals('admin@test.it', $configCache->get('config', 'admin_email')); + $this->assertEquals('Friendica Social Network', $configCache->get('config', 'sitename')); + } + + /** + * Test the loadConfigFile() method with a local.ini.php file + */ + public function testLoadConfigFilesINI() + { + $this->delConfigFile('local.config.php'); + + $file = dirname(__DIR__) . DIRECTORY_SEPARATOR . + '..' . DIRECTORY_SEPARATOR . + '..' . DIRECTORY_SEPARATOR . + 'datasets' . DIRECTORY_SEPARATOR . + 'config' . DIRECTORY_SEPARATOR . + 'local.ini.php'; + + vfsStream::newFile('local.ini.php') + ->at($this->root->getChild('config')) + ->setContent(file_get_contents($file)); + + $configFileLoader = new ConfigFileLoader($this->root->url(), $this->mode); + $configCache = new ConfigCache(); + + $configFileLoader->setupCache($configCache); + + $this->assertEquals('testhost', $configCache->get('database', 'hostname')); + $this->assertEquals('testuser', $configCache->get('database', 'username')); + $this->assertEquals('testpw', $configCache->get('database', 'password')); + $this->assertEquals('testdb', $configCache->get('database', 'database')); + + $this->assertEquals('admin@test.it', $configCache->get('config', 'admin_email')); + } + + /** + * Test the loadConfigFile() method with a .htconfig.php file + */ + public function testLoadConfigFilesHtconfig() + { + $this->delConfigFile('local.config.php'); + + $file = dirname(__DIR__) . DIRECTORY_SEPARATOR . + '..' . DIRECTORY_SEPARATOR . + '..' . DIRECTORY_SEPARATOR . + 'datasets' . DIRECTORY_SEPARATOR . + 'config' . DIRECTORY_SEPARATOR . + '.htconfig.php'; + + vfsStream::newFile('.htconfig.php') + ->at($this->root) + ->setContent(file_get_contents($file)); + + $configFileLoader = new ConfigFileLoader($this->root->url(), $this->mode); + $configCache = new ConfigCache(); + + $configFileLoader->setupCache($configCache); + + $this->assertEquals('testhost', $configCache->get('database', 'hostname')); + $this->assertEquals('testuser', $configCache->get('database', 'username')); + $this->assertEquals('testpw', $configCache->get('database', 'password')); + $this->assertEquals('testdb', $configCache->get('database', 'database')); + $this->assertEquals('anotherCharset', $configCache->get('database', 'charset')); + + $this->assertEquals('/var/run/friendica.pid', $configCache->get('system', 'pidfile')); + $this->assertEquals('Europe/Berlin', $configCache->get('system', 'default_timezone')); + $this->assertEquals('fr', $configCache->get('system', 'language')); + + $this->assertEquals('admin@test.it', $configCache->get('config', 'admin_email')); + $this->assertEquals('Friendly admin', $configCache->get('config', 'admin_nickname')); + + $this->assertEquals('/another/php', $configCache->get('config', 'php_path')); + $this->assertEquals('999', $configCache->get('config', 'max_import_size')); + $this->assertEquals('666', $configCache->get('system', 'maximagesize')); + + $this->assertEquals('quattro,vier,duepuntozero', $configCache->get('system', 'allowed_themes')); + $this->assertEquals('1', $configCache->get('system', 'no_regfullname')); + } + + public function testLoadAddonConfig() + { + $structure = [ + 'addon' => [ + 'test' => [ + 'config' => [], + ], + ], + ]; + + vfsStream::create($structure, $this->root); + + $file = dirname(__DIR__) . DIRECTORY_SEPARATOR . + '..' . DIRECTORY_SEPARATOR . + '..' . DIRECTORY_SEPARATOR . + 'datasets' . DIRECTORY_SEPARATOR . + 'config' . DIRECTORY_SEPARATOR . + 'local.config.php'; + + vfsStream::newFile('test.config.php') + ->at($this->root->getChild('addon')->getChild('test')->getChild('config')) + ->setContent(file_get_contents($file)); + + $configFileLoader = new ConfigFileLoader($this->root->url(), $this->mode); + + $conf = $configFileLoader->loadAddonConfig('test'); + + $this->assertEquals('testhost', $conf['database']['hostname']); + $this->assertEquals('testuser', $conf['database']['username']); + $this->assertEquals('testpw', $conf['database']['password']); + $this->assertEquals('testdb', $conf['database']['database']); + + $this->assertEquals('admin@test.it', $conf['config']['admin_email']); + } +} diff --git a/tests/src/Util/Config/ConfigFileSaverTest.php b/tests/src/Util/Config/ConfigFileSaverTest.php new file mode 100644 index 0000000000..5b472df49f --- /dev/null +++ b/tests/src/Util/Config/ConfigFileSaverTest.php @@ -0,0 +1,139 @@ +setUpVfsDir(); + $this->mode = \Mockery::mock(App\Mode::class); + $this->mode->shouldReceive('isInstall')->andReturn(true); + } + + public function dataConfigFiles() + { + return [ + 'config' => [ + 'fileName' => 'local.config.php', + 'filePath' => dirname(__DIR__) . DIRECTORY_SEPARATOR . + '..' . DIRECTORY_SEPARATOR . + '..' . DIRECTORY_SEPARATOR . + 'datasets' . DIRECTORY_SEPARATOR . + 'config', + 'relativePath' => 'config', + ], + 'ini' => [ + 'fileName' => 'local.ini.php', + 'filePath' => dirname(__DIR__) . DIRECTORY_SEPARATOR . + '..' . DIRECTORY_SEPARATOR . + '..' . DIRECTORY_SEPARATOR . + 'datasets' . DIRECTORY_SEPARATOR . + 'config', + 'relativePath' => 'config', + ], + 'htconfig' => [ + 'fileName' => '.htconfig.php', + 'filePath' => dirname(__DIR__) . DIRECTORY_SEPARATOR . + '..' . DIRECTORY_SEPARATOR . + '..' . DIRECTORY_SEPARATOR . + 'datasets' . DIRECTORY_SEPARATOR . + 'config', + 'relativePath' => '', + ], + ]; + } + + /** + * Test the saveToConfigFile() method + * @dataProvider dataConfigFiles + * + * @todo 20190324 [nupplaphil] for ini-configs, it isn't possible to use $ or ! inside values + */ + public function testSaveToConfig($fileName, $filePath, $relativePath) + { + $this->delConfigFile('local.config.php'); + + if (empty($relativePath)) { + $root = $this->root; + $relativeFullName = $fileName; + } else { + $root = $this->root->getChild($relativePath); + $relativeFullName = $relativePath . DIRECTORY_SEPARATOR . $fileName; + } + + vfsStream::newFile($fileName) + ->at($root) + ->setContent(file_get_contents($filePath . DIRECTORY_SEPARATOR . $fileName)); + + $configFileSaver = new ConfigFileSaver($this->root->url()); + $configFileLoader = new ConfigFileLoader($this->root->url(), $this->mode); + $configCache = new ConfigCache(); + $configFileLoader->setupCache($configCache); + + $this->assertEquals('admin@test.it', $configCache->get('config', 'admin_email')); + $this->assertNull($configCache->get('config', 'test_val')); + $this->assertNull($configCache->get('system', 'test_val2')); + + $configFileSaver->addConfigValue('system', 'theme', 'frio'); + $configFileSaver->addConfigValue('config', 'admin_email', 'new@mail.it'); + $configFileSaver->addConfigValue('config', 'test_val', 'Testingwith@all.we can'); + $configFileSaver->addConfigValue('system', 'theme', 'vier'); + $configFileSaver->addConfigValue('system', 'test_val2', 'TestIt Now'); + $this->assertTrue($configFileSaver->saveToConfigFile()); + + $newConfigCache = new ConfigCache(); + $configFileLoader->setupCache($newConfigCache); + + $this->assertEquals('new@mail.it', $newConfigCache->get('config', 'admin_email')); + $this->assertEquals('Testingwith@all.we can', $newConfigCache->get('config', 'test_val')); + $this->assertEquals('vier', $newConfigCache->get('system', 'theme')); + $this->assertEquals('TestIt Now', $newConfigCache->get('system', 'test_val2')); + + $this->assertTrue($this->root->hasChild($relativeFullName)); + $this->assertTrue($this->root->hasChild($relativeFullName . '.old')); + $this->assertFalse($this->root->hasChild($relativeFullName . '.tmp')); + + $this->assertEquals(file_get_contents($filePath . DIRECTORY_SEPARATOR . $fileName), file_get_contents($this->root->getChild($relativeFullName . '.old')->url())); + } + + /** + * Test the saveToConfigFile() method without permissions + * @dataProvider dataConfigFiles + */ + public function testNoPermission($fileName, $filePath, $relativePath) + { + $this->delConfigFile('local.config.php'); + + if (empty($relativePath)) { + $root = $this->root; + $relativeFullName = $fileName; + } else { + $root = $this->root->getChild($relativePath); + $relativeFullName = $relativePath . DIRECTORY_SEPARATOR . $fileName; + } + + $root->chmod(000); + + vfsStream::newFile($fileName) + ->at($root) + ->setContent(file_get_contents($filePath . DIRECTORY_SEPARATOR . $fileName)); + } +} diff --git a/update.php b/update.php index 140c8fcb58..4ee85739d3 100644 --- a/update.php +++ b/update.php @@ -12,7 +12,7 @@ use Friendica\Model\Contact; use Friendica\Model\GContact; use Friendica\Model\Item; use Friendica\Model\User; -use Friendica\Util\Config\ConfigCacheSaver; +use Friendica\Util\Config\ConfigFileSaver; use Friendica\Util\DateTimeFormat; /** @@ -357,8 +357,9 @@ function update_1303() { $app = \Friendica\BaseObject::getApp(); $configCache = $app->getConfigCache(); - $configCacheSaver = new ConfigCacheSaver($app->getBasePath()); - $updateConfigEntry = function($cat, $key) use ($configCache, $configCacheSaver) { + $configFileSaver = new ConfigFileSaver($app->getBasePath()); + + $updateConfigEntry = function($cat, $key) use ($configCache, $configFileSaver) { // check if the config file differs from the whole configuration (= The db contains other values) $fileConfig = $configCache->get($cat, $key); if ($fileConfig === '!!') { @@ -367,11 +368,14 @@ function update_1303() $savedConfig = Config::get($cat, $key, null, true); if ($fileConfig !== $savedConfig) { Logger::info('Difference in config found', ['cat' => $cat, 'key' => $key, 'file' => $fileConfig, 'saved' => $savedConfig]); - $configCacheSaver->saveToConfigFile($cat, $key, $savedConfig); + $configFileSaver->addConfigValue($cat, $key, $savedConfig); } else { Logger::info('No Difference in config found', ['cat' => $cat, 'key' => $key, 'value' => $fileConfig, 'saved' => $savedConfig]); } }; + + $configFileSaver->saveToConfigFile(); + $updateConfigEntry('config', 'hostname'); $updateConfigEntry('system', 'basepath'); return Update::SUCCESS;