From 318a3ca785474fa27fbff9b3ee19fd4c04261ecd Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Mon, 8 Apr 2019 21:12:10 +0200 Subject: [PATCH] Create own base URL class which holds the whole base url business logic --- boot.php | 11 - config/defaults.config.php | 5 - mod/admin.php | 14 +- src/App.php | 189 +++------- src/Core/Authentication.php | 3 +- src/Core/Session.php | 3 +- src/Core/System.php | 2 +- src/Core/Update.php | 141 +------ src/Factory/DependencyFactory.php | 4 +- src/Model/Contact.php | 5 +- src/Network/Probe.php | 30 +- src/Protocol/DFRN.php | 7 +- src/Util/BaseURL.php | 344 ++++++++++++++++++ src/Util/Config/ConfigFileSaver.php | 341 ----------------- src/Util/Network.php | 22 ++ tests/src/Util/Config/ConfigFileSaverTest.php | 189 ---------- 16 files changed, 434 insertions(+), 876 deletions(-) create mode 100644 src/Util/BaseURL.php delete mode 100644 src/Util/Config/ConfigFileSaver.php delete mode 100644 tests/src/Util/Config/ConfigFileSaverTest.php diff --git a/boot.php b/boot.php index e75b2abd91..dfedcdbbbe 100644 --- a/boot.php +++ b/boot.php @@ -82,17 +82,6 @@ define('MAX_IMAGE_LENGTH', -1); */ define('DEFAULT_DB_ENGINE', 'InnoDB'); -/** - * @name SSL Policy - * - * SSL redirection policies - * @{ - */ -define('SSL_POLICY_NONE', 0); -define('SSL_POLICY_FULL', 1); -define('SSL_POLICY_SELFSIGN', 2); -/* @}*/ - /** @deprecated since version 2019.03, please use \Friendica\Module\Register::CLOSED instead */ define('REGISTER_CLOSED', \Friendica\Module\Register::CLOSED); /** @deprecated since version 2019.03, please use \Friendica\Module\Register::APPROVE instead */ diff --git a/config/defaults.config.php b/config/defaults.config.php index 0d9e55c7d9..b42bc8c628 100644 --- a/config/defaults.config.php +++ b/config/defaults.config.php @@ -377,11 +377,6 @@ return [ // Maximum number of posts that a user can send per month with the API. 0 to disable monthly throttling. 'throttle_limit_month' => 0, - // urlpath (String) - // If you are using a subdirectory of your domain you will need to put the relative path (from the root of your domain) here. - // For instance if your URL is 'http://example.com/directory/subdirectory', set urlpath to 'directory/subdirectory'. - 'urlpath' => '', - // username_min_length (Integer) // The minimum character length a username can be. // This length is check once the username has been trimmed and multiple spaces have been collapsed into one. diff --git a/mod/admin.php b/mod/admin.php index 0df907cbaa..db8bb403c1 100644 --- a/mod/admin.php +++ b/mod/admin.php @@ -32,6 +32,7 @@ use Friendica\Module\Tos; use Friendica\Protocol\PortableContact; use Friendica\Util\Arrays; use Friendica\Util\BasePath; +use Friendica\Util\BaseURL; use Friendica\Util\DateTimeFormat; use Friendica\Util\Network; use Friendica\Util\Strings; @@ -1041,9 +1042,6 @@ function admin_page_site_post(App $a) update_table($a, "gcontact", ['connect', 'addr'], $old_host, $new_host); // update config - $configFileSaver = new \Friendica\Util\Config\ConfigFileSaver($a->getBasePath()); - $configFileSaver->addConfigValue('config', 'hostname', parse_url($new_url, PHP_URL_HOST)); - $configFileSaver->saveToConfigFile(); Config::set('system', 'url', $new_url); $a->setBaseURL($new_url); @@ -1199,7 +1197,7 @@ function admin_page_site_post(App $a) $diaspora_enabled = false; } if ($ssl_policy != intval(Config::get('system', 'ssl_policy'))) { - if ($ssl_policy == SSL_POLICY_FULL) { + if ($ssl_policy == BaseURL::SSL_POLICY_FULL) { q("UPDATE `contact` SET `url` = REPLACE(`url` , 'http:' , 'https:'), `photo` = REPLACE(`photo` , 'http:' , 'https:'), @@ -1217,7 +1215,7 @@ function admin_page_site_post(App $a) `thumb` = REPLACE(`thumb` , 'http:' , 'https:') WHERE 1 " ); - } elseif ($ssl_policy == SSL_POLICY_SELFSIGN) { + } elseif ($ssl_policy == BaseURL::SSL_POLICY_SELFSIGN) { q("UPDATE `contact` SET `url` = REPLACE(`url` , 'https:' , 'http:'), `photo` = REPLACE(`photo` , 'https:' , 'http:'), @@ -1473,9 +1471,9 @@ function admin_page_site(App $a) ]; $ssl_choices = [ - SSL_POLICY_NONE => L10n::t("No SSL policy, links will track page SSL state"), - SSL_POLICY_FULL => L10n::t("Force all links to use SSL"), - SSL_POLICY_SELFSIGN => L10n::t("Self-signed certificate, use SSL for local links only \x28discouraged\x29") + BaseURL::SSL_POLICY_NONE => L10n::t("No SSL policy, links will track page SSL state"), + BaseURL::SSL_POLICY_FULL => L10n::t("Force all links to use SSL"), + BaseURL::SSL_POLICY_SELFSIGN => L10n::t("Self-signed certificate, use SSL for local links only \x28discouraged\x29") ]; $check_git_version_choices = [ diff --git a/src/App.php b/src/App.php index 2576cc5d8e..3e1dc147f3 100644 --- a/src/App.php +++ b/src/App.php @@ -8,7 +8,6 @@ use Detection\MobileDetect; use DOMDocument; use DOMXPath; use Exception; -use FastRoute\RouteCollector; use Friendica\Core\Config\Cache\IConfigCache; use Friendica\Core\Config\Configuration; use Friendica\Core\Hook; @@ -16,6 +15,7 @@ use Friendica\Core\Theme; use Friendica\Database\DBA; use Friendica\Model\Profile; use Friendica\Network\HTTPException\InternalServerErrorException; +use Friendica\Util\BaseURL; use Friendica\Util\Config\ConfigFileLoader; use Friendica\Util\HTTPSignature; use Friendica\Util\Profiler; @@ -84,9 +84,9 @@ class App private $router; /** - * @var string The App URL path + * @var BaseURL */ - private $urlPath; + private $baseURL; /** * @var bool true, if the call is from the Friendica APP, otherwise false @@ -178,6 +178,11 @@ class App return $this->mode; } + /** + * Returns the router of the Application + * + * @return App\Router + */ public function getRouter() { return $this->router; @@ -220,8 +225,6 @@ class App } public $queue; - private $scheme; - private $hostname; /** * @brief App constructor. @@ -229,19 +232,21 @@ class App * @param Configuration $config The Configuration * @param App\Mode $mode The mode of this Friendica app * @param App\Router $router The router of this Friendica app + * @param BaseURL $baseURL The full base URL of this Friendica app * @param LoggerInterface $logger The current app logger * @param Profiler $profiler The profiler of this application * @param bool $isBackend Whether it is used for backend or frontend (Default true=backend) * * @throws Exception if the Basepath is not usable */ - public function __construct(Configuration $config, App\Mode $mode, App\Router $router, LoggerInterface $logger, Profiler $profiler, $isBackend = true) + public function __construct(Configuration $config, App\Mode $mode, App\Router $router, BaseURL $baseURL, LoggerInterface $logger, Profiler $profiler, $isBackend = true) { BaseObject::setApp($this); $this->config = $config; $this->mode = $mode; $this->router = $router; + $this->baseURL = $baseURL; $this->profiler = $profiler; $this->logger = $logger; @@ -257,26 +262,6 @@ class App // This has to be quite large to deal with embedded private photos ini_set('pcre.backtrack_limit', 500000); - $this->scheme = 'http'; - - if (!empty($_SERVER['HTTPS']) || - !empty($_SERVER['HTTP_FORWARDED']) && preg_match('/proto=https/', $_SERVER['HTTP_FORWARDED']) || - !empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https' || - !empty($_SERVER['HTTP_X_FORWARDED_SSL']) && $_SERVER['HTTP_X_FORWARDED_SSL'] == 'on' || - !empty($_SERVER['FRONT_END_HTTPS']) && $_SERVER['FRONT_END_HTTPS'] == 'on' || - !empty($_SERVER['SERVER_PORT']) && (intval($_SERVER['SERVER_PORT']) == 443) // XXX: reasonable assumption, but isn't this hardcoding too much? - ) { - $this->scheme = 'https'; - } - - if (!empty($_SERVER['SERVER_NAME'])) { - $this->hostname = $_SERVER['SERVER_NAME']; - - if (!empty($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] != 80 && $_SERVER['SERVER_PORT'] != 443) { - $this->hostname .= ':' . $_SERVER['SERVER_PORT']; - } - } - set_include_path( get_include_path() . PATH_SEPARATOR . $this->getBasePath() . DIRECTORY_SEPARATOR . 'include' . PATH_SEPARATOR @@ -354,8 +339,6 @@ class App */ public function reload() { - $this->determineURLPath(); - $this->getMode()->determine($this->getBasePath()); if ($this->getMode()->has(App\Mode::DBAVAILABLE)) { @@ -398,97 +381,28 @@ class App } /** - * Figure out if we are running at the top of a domain or in a sub-directory and adjust accordingly + * Returns the scheme of the current call + * @return string + * + * @deprecated 2019.06 - use BaseURL->getScheme() instead */ - private function determineURLPath() - { - /* - * The automatic path detection in this function is currently deactivated, - * see issue https://github.com/friendica/friendica/issues/6679 - * - * The problem is that the function seems to be confused with some url. - * These then confuses the detection which changes the url path. - */ - - /* Relative script path to the web server root - * Not all of those $_SERVER properties can be present, so we do by inverse priority order - */ -/* - $relative_script_path = ''; - $relative_script_path = defaults($_SERVER, 'REDIRECT_URL' , $relative_script_path); - $relative_script_path = defaults($_SERVER, 'REDIRECT_URI' , $relative_script_path); - $relative_script_path = defaults($_SERVER, 'REDIRECT_SCRIPT_URL', $relative_script_path); - $relative_script_path = defaults($_SERVER, 'SCRIPT_URL' , $relative_script_path); - $relative_script_path = defaults($_SERVER, 'REQUEST_URI' , $relative_script_path); -*/ - $this->urlPath = $this->config->get('system', 'urlpath'); - - /* $relative_script_path gives /relative/path/to/friendica/module/parameter - * QUERY_STRING gives pagename=module/parameter - * - * To get /relative/path/to/friendica we perform dirname() for as many levels as there are slashes in the QUERY_STRING - */ -/* - if (!empty($relative_script_path)) { - // Module - if (!empty($_SERVER['QUERY_STRING'])) { - $path = trim(rdirname($relative_script_path, substr_count(trim($_SERVER['QUERY_STRING'], '/'), '/') + 1), '/'); - } else { - // Root page - $path = trim($relative_script_path, '/'); - } - - if ($path && $path != $this->urlPath) { - $this->urlPath = $path; - } - } -*/ - } - public function getScheme() { - return $this->scheme; + return $this->baseURL->getScheme(); } /** - * @brief Retrieves the Friendica instance base URL + * Retrieves the Friendica instance base URL * - * This function assembles the base URL from multiple parts: - * - Protocol is determined either by the request or a combination of - * system.ssl_policy and the $ssl parameter. - * - Host name is determined either by system.hostname or inferred from request - * - Path is inferred from SCRIPT_NAME + * @param bool $ssl Whether to append http or https under BaseURL::SSL_POLICY_SELFSIGN * - * Note: $ssl parameter value doesn't directly correlate with the resulting protocol - * - * @param bool $ssl Whether to append http or https under SSL_POLICY_SELFSIGN * @return string Friendica server base URL - * @throws InternalServerErrorException + * + * @deprecated 2019.06 - use BaseURL->get($ssl) instead */ public function getBaseURL($ssl = false) { - $scheme = $this->scheme; - - if ($this->config->get('system', 'ssl_policy') == SSL_POLICY_FULL) { - $scheme = 'https'; - } - - // Basically, we have $ssl = true on any links which can only be seen by a logged in user - // (and also the login link). Anything seen by an outsider will have it turned off. - - if ($this->config->get('system', 'ssl_policy') == SSL_POLICY_SELFSIGN) { - if ($ssl) { - $scheme = 'https'; - } else { - $scheme = 'http'; - } - } - - if ($this->config->get('config', 'hostname') != '') { - $this->hostname = $this->config->get('config', 'hostname'); - } - - return $scheme . '://' . $this->hostname . (!empty($this->getURLPath()) ? '/' . $this->getURLPath() : '' ); + return $this->baseURL->get($ssl); } /** @@ -497,55 +411,36 @@ class App * Clears the baseurl cache to prevent inconsistencies * * @param string $url - * @throws InternalServerErrorException + * + * @deprecated 2019.06 - use BaseURL->saveByURL($url) instead */ public function setBaseURL($url) { - $parsed = @parse_url($url); - $hostname = ''; - - if (!empty($parsed)) { - if (!empty($parsed['scheme'])) { - $this->scheme = $parsed['scheme']; - } - - if (!empty($parsed['host'])) { - $hostname = $parsed['host']; - } - - if (!empty($parsed['port'])) { - $hostname .= ':' . $parsed['port']; - } - if (!empty($parsed['path'])) { - $this->urlPath = trim($parsed['path'], '\\/'); - } - - if (file_exists($this->getBasePath() . '/.htpreconfig.php')) { - include $this->getBasePath() . '/.htpreconfig.php'; - } - - if ($this->config->get('config', 'hostname') != '') { - $this->hostname = $this->config->get('config', 'hostname'); - } - - if (!isset($this->hostname) || ($this->hostname == '')) { - $this->hostname = $hostname; - } - } + $this->baseURL->saveByURL($url); } + /** + * Returns the current hostname + * + * @return string + * + * @deprecated 2019.06 - use BaseURL->getHostname() instead + */ public function getHostName() { - if ($this->config->get('config', 'hostname') != '') { - $this->hostname = $this->config->get('config', 'hostname'); - } - - return $this->hostname; + return $this->baseURL->getHostname(); } + /** + * Returns the sub-path of the full URL + * + * @return string + * + * @deprecated 2019.06 - use BaseURL->getUrlPath() instead + */ public function getURLPath() { - return $this->urlPath; + return $this->baseURL->getUrlPath(); } /** @@ -1120,7 +1015,7 @@ class App if (!$this->getMode()->isInstall()) { // Force SSL redirection if ($this->config->get('system', 'force_ssl') && ($this->getScheme() == "http") - && intval($this->config->get('system', 'ssl_policy')) == SSL_POLICY_FULL + && intval($this->config->get('system', 'ssl_policy')) == BaseURL::SSL_POLICY_FULL && strpos($this->getBaseURL(), 'https://') === 0 && $_SERVER['REQUEST_METHOD'] == 'GET') { header('HTTP/1.1 302 Moved Temporarily'); @@ -1458,7 +1353,7 @@ class App header("X-Friendica-Version: " . FRIENDICA_VERSION); header("Content-type: text/html; charset=utf-8"); - if ($this->config->get('system', 'hsts') && ($this->config->get('system', 'ssl_policy') == SSL_POLICY_FULL)) { + if ($this->config->get('system', 'hsts') && ($this->config->get('system', 'ssl_policy') == BaseUrl::SSL_POLICY_FULL)) { header("Strict-Transport-Security: max-age=31536000"); } diff --git a/src/Core/Authentication.php b/src/Core/Authentication.php index 106ba2a602..1963d34b4e 100644 --- a/src/Core/Authentication.php +++ b/src/Core/Authentication.php @@ -8,6 +8,7 @@ namespace Friendica\Core; use Friendica\BaseObject; use Friendica\Database\DBA; use Friendica\Model\User; +use Friendica\Util\BaseURL; use Friendica\Util\DateTimeFormat; /** @@ -51,7 +52,7 @@ class Authentication extends BaseObject $value = ""; } - setcookie("Friendica", $value, $time, "/", "", (Config::get('system', 'ssl_policy') == SSL_POLICY_FULL), true); + setcookie("Friendica", $value, $time, "/", "", (Config::get('system', 'ssl_policy') == BaseUrl::SSL_POLICY_FULL), true); } /** diff --git a/src/Core/Session.php b/src/Core/Session.php index d9143c8809..f1da864bb1 100644 --- a/src/Core/Session.php +++ b/src/Core/Session.php @@ -7,6 +7,7 @@ namespace Friendica\Core; use Friendica\Core\Session\CacheSessionHandler; use Friendica\Core\Session\DatabaseSessionHandler; +use Friendica\Util\BaseURL; /** * High-level Session service class @@ -24,7 +25,7 @@ class Session ini_set('session.use_only_cookies', 1); ini_set('session.cookie_httponly', 1); - if (Config::get('system', 'ssl_policy') == SSL_POLICY_FULL) { + if (Config::get('system', 'ssl_policy') == BaseUrl::SSL_POLICY_FULL) { ini_set('session.cookie_secure', 1); } diff --git a/src/Core/System.php b/src/Core/System.php index 45a88fe093..83c3dc9081 100644 --- a/src/Core/System.php +++ b/src/Core/System.php @@ -23,7 +23,7 @@ class System extends BaseObject /** * @brief Retrieves the Friendica instance base URL * - * @param bool $ssl Whether to append http or https under SSL_POLICY_SELFSIGN + * @param bool $ssl Whether to append http or https under BaseURL::SSL_POLICY_SELFSIGN * @return string Friendica server base URL * @throws InternalServerErrorException */ diff --git a/src/Core/Update.php b/src/Core/Update.php index d2bbc237c7..328938fe1c 100644 --- a/src/Core/Update.php +++ b/src/Core/Update.php @@ -3,12 +3,8 @@ namespace Friendica\Core; use Friendica\App; -use Friendica\Core\Config\Cache\IConfigCache; use Friendica\Database\DBA; use Friendica\Database\DBStructure; -use Friendica\Util\BasePath; -use Friendica\Util\Config\ConfigFileLoader; -use Friendica\Util\Config\ConfigFileSaver; use Friendica\Util\Strings; class Update @@ -32,7 +28,7 @@ class Update } // Check if the config files are set correctly - self::checkConfigFile($basePath, $mode); + self::checkBaseSettings($_SERVER); // Don't check the status if the last update was failed if (Config::get('system', 'update', Update::SUCCESS, true) == Update::FAILED) { @@ -229,142 +225,9 @@ class Update } } - /** - * Checks the config settings and saves given config values into the config file - * - * @param string $basePath The basepath of Friendica - * @param App\Mode $mode The current App mode - * - * @return bool True, if something has been saved - */ - public static function checkConfigFile($basePath, App\Mode $mode) - { - if (empty($basePath)) { - $basePath = BasePath::create(dirname(__DIR__, 2)); - } - - $config = [ - 'config' => [ - 'hostname' => [ - 'allowEmpty' => false, - 'default' => '', - ], - ], - 'system' => [ - 'basepath' => [ - 'allowEmpty' => false, - 'default' => $basePath, - ], - ] - ]; - - $configFileLoader = new ConfigFileLoader($basePath, $mode); - $configCache = new Config\Cache\ConfigCache(); - $configFileLoader->setupCache($configCache, true); - - // checks if something is to update, otherwise skip this function at all - $missingConfig = $configCache->keyDiff($config); - if (empty($missingConfig)) { - return true; - } - - // We just want one update process - if (Lock::acquire('config_update')) { - $configFileSaver = new ConfigFileSaver($basePath); - - $updated = false; - $toDelete = []; - - foreach ($missingConfig as $category => $keys) { - foreach ($keys as $key => $value) { - if (self::updateConfigEntry($configCache, $configFileSaver, $category, $key, $value['allowEmpty'], $value['default'])) { - $toDelete[] = ['cat' => $category, 'key' => $key]; - $updated = true; - }; - } - } - - // In case there is nothing to do, skip the update - if (!$updated) { - Lock::release('config_update'); - return true; - } - - if (!$configFileSaver->saveToConfigFile()) { - Logger::alert('Config entry update failed - maybe wrong permission?'); - Lock::release('config_update'); - return false; - } - - // After the successful save, remove the db values - foreach ($toDelete as $delete) { - DBA::delete('config', ['cat' => $delete['cat'], 'k' => $delete['key']]); - } - - Lock::release('config_update'); - } - - return true; - } - - /** - * Adds a value to the ConfigFileSave in case it isn't already updated - * - * @param IConfigCache $configCache The cached config file - * @param ConfigFileSaver $configFileSaver The config file saver - * @param string $cat The config category - * @param string $key The config key - * @param bool $allowEmpty If true, empty values are valid (Default there has to be a variable) - * @param string $default A default value, if none of the settings are valid - * - * @return boolean True, if a value was updated - * - * @throws \Exception if DBA or Logger doesn't work - */ - private static function updateConfigEntry( - IConfigCache $configCache, - ConfigFileSaver $configFileSaver, - $cat, - $key, - $allowEmpty = false, - $default = '') + public static function checkBaseSettings(array $server) { - // check if the config file differs from the whole configuration (= The db contains other values) - $fileValue = $configCache->get($cat, $key); - $dbConfig = DBA::selectFirst('config', ['v'], ['cat' => $cat, 'k' => $key]); - - if (DBA::isResult($dbConfig)) { - $dbValue = $dbConfig['v']; - } else { - $dbValue = null; - } - - // If the db contains a config value, check it - if (( - ($allowEmpty && isset($dbValue)) || - (!$allowEmpty && !empty($dbValue)) - ) && - $fileValue !== $dbValue) { - Logger::info('Difference in config found', ['cat' => $cat, 'key' => $key, 'file' => $fileValue, 'db' => $dbValue]); - $configFileSaver->addConfigValue($cat, $key, $dbValue); - return true; - - // If both config values are not set, use the default value - } elseif ( - ($allowEmpty && !isset($fileValue) && !isset($dbValue)) || - (!$allowEmpty && empty($fileValue) && empty($dbValue) && !empty($default))) { - - Logger::info('Using default for config', ['cat' => $cat, 'key' => $key, 'value' => $default]); - $configFileSaver->addConfigValue($cat, $key, $default); - return true; - - // If either the file config value isn't empty or the db value is the same as the - // file config value, skip it - } else { - Logger::debug('No Difference in config found', ['cat' => $cat, 'key' => $key, 'value' => $fileValue, 'db' => $dbValue]); - return false; - } } /** diff --git a/src/Factory/DependencyFactory.php b/src/Factory/DependencyFactory.php index 0f33e095bc..e55a52d14e 100644 --- a/src/Factory/DependencyFactory.php +++ b/src/Factory/DependencyFactory.php @@ -5,6 +5,7 @@ namespace Friendica\Factory; use Friendica\App; use Friendica\Factory; use Friendica\Util\BasePath; +use Friendica\Util\BaseURL; use Friendica\Util\Config; class DependencyFactory @@ -34,7 +35,8 @@ class DependencyFactory Factory\ConfigFactory::createPConfig($configCache); $logger = Factory\LoggerFactory::create($channel, $config, $profiler); Factory\LoggerFactory::createDev($channel, $config, $profiler); + $baseURL = new BaseURL($config, $_SERVER); - return new App($config, $mode, $router, $logger, $profiler, $isBackend); + return new App($config, $mode, $router, $baseURL, $logger, $profiler, $isBackend); } } diff --git a/src/Model/Contact.php b/src/Model/Contact.php index fe373ae94a..b19783427a 100644 --- a/src/Model/Contact.php +++ b/src/Model/Contact.php @@ -22,6 +22,7 @@ use Friendica\Protocol\Diaspora; use Friendica\Protocol\OStatus; use Friendica\Protocol\PortableContact; use Friendica\Protocol\Salmon; +use Friendica\Util\BaseURL; use Friendica\Util\DateTimeFormat; use Friendica\Util\Network; use Friendica\Util\Strings; @@ -1938,7 +1939,7 @@ class Contact extends BaseObject public static function updateSslPolicy(array $contact, $new_policy) { $ssl_changed = false; - if ((intval($new_policy) == SSL_POLICY_SELFSIGN || $new_policy === 'self') && strstr($contact['url'], 'https:')) { + if ((intval($new_policy) == BaseURL::SSL_POLICY_SELFSIGN || $new_policy === 'self') && strstr($contact['url'], 'https:')) { $ssl_changed = true; $contact['url'] = str_replace('https:', 'http:', $contact['url']); $contact['request'] = str_replace('https:', 'http:', $contact['request']); @@ -1948,7 +1949,7 @@ class Contact extends BaseObject $contact['poco'] = str_replace('https:', 'http:', $contact['poco']); } - if ((intval($new_policy) == SSL_POLICY_FULL || $new_policy === 'full') && strstr($contact['url'], 'http:')) { + if ((intval($new_policy) == BaseURL::SSL_POLICY_FULL || $new_policy === 'full') && strstr($contact['url'], 'http:')) { $ssl_changed = true; $contact['url'] = str_replace('http:', 'https:', $contact['url']); $contact['request'] = str_replace('http:', 'https:', $contact['request']); diff --git a/src/Network/Probe.php b/src/Network/Probe.php index 008106ec3f..b0d2630103 100644 --- a/src/Network/Probe.php +++ b/src/Network/Probe.php @@ -10,6 +10,7 @@ namespace Friendica\Network; */ use DOMDocument; +use DomXPath; use Friendica\Core\Cache; use Friendica\Core\Config; use Friendica\Core\Logger; @@ -18,15 +19,14 @@ use Friendica\Core\System; use Friendica\Database\DBA; use Friendica\Model\Contact; use Friendica\Model\Profile; +use Friendica\Protocol\ActivityPub; use Friendica\Protocol\Email; use Friendica\Protocol\Feed; -use Friendica\Protocol\ActivityPub; use Friendica\Util\Crypto; use Friendica\Util\DateTimeFormat; use Friendica\Util\Network; use Friendica\Util\Strings; use Friendica\Util\XML; -use DomXPath; /** * @brief This class contain functions for probing URL @@ -510,30 +510,6 @@ class Probe return $data; } - /** - * @brief Switch the scheme of an url between http and https - * - * @param string $url URL - * - * @return string switched URL - */ - private static function switchScheme($url) - { - $parts = parse_url($url); - - if (!isset($parts['scheme'])) { - return $url; - } - - if ($parts['scheme'] == 'http') { - $url = str_replace('http://', 'https://', $url); - } elseif ($parts['scheme'] == 'https') { - $url = str_replace('https://', 'http://', $url); - } - - return $url; - } - /** * @brief Checks if a profile url should be OStatus but only provides partial information * @@ -566,7 +542,7 @@ class Probe return $webfinger; } - $url = self::switchScheme($webfinger['subject']); + $url = Network::switchScheme($webfinger['subject']); $path = str_replace('{uri}', urlencode($url), $lrdd); $webfinger2 = self::webfinger($path, $type); diff --git a/src/Protocol/DFRN.php b/src/Protocol/DFRN.php index 8433801812..b6252655ac 100644 --- a/src/Protocol/DFRN.php +++ b/src/Protocol/DFRN.php @@ -29,6 +29,7 @@ use Friendica\Model\PermissionSet; use Friendica\Model\Profile; use Friendica\Model\User; use Friendica\Object\Image; +use Friendica\Util\BaseURL; use Friendica\Util\Crypto; use Friendica\Util\DateTimeFormat; use Friendica\Util\Network; @@ -1208,13 +1209,13 @@ class DFRN $ssl_val = intval(Config::get('system', 'ssl_policy')); switch ($ssl_val) { - case SSL_POLICY_FULL: + case BaseURL::SSL_POLICY_FULL: $ssl_policy = 'full'; break; - case SSL_POLICY_SELFSIGN: + case BaseURL::SSL_POLICY_SELFSIGN: $ssl_policy = 'self'; break; - case SSL_POLICY_NONE: + case BaseURL::SSL_POLICY_NONE: default: $ssl_policy = 'none'; break; diff --git a/src/Util/BaseURL.php b/src/Util/BaseURL.php new file mode 100644 index 0000000000..a9bed2b5e8 --- /dev/null +++ b/src/Util/BaseURL.php @@ -0,0 +1,344 @@ +hostname; + } + + /** + * Returns the current scheme of this call + * @return string + */ + public function getScheme() + { + return $this->scheme; + } + + /** + * Returns the SSL policy of this node + * @return int + */ + public function getSSLPolicy() + { + return $this->sslPolicy; + } + + /** + * Returns the sub-path of this URL + * @return string + */ + public function getUrlPath() + { + return $this->urlPath; + } + + /** + * Returns the full URL of this call + * + * Note: $ssl parameter value doesn't directly correlate with the resulting protocol + * + * @param bool $ssl True, if ssl should get used + * + * @return string + */ + public function get($ssl = false) + { + return (!$ssl ? $this->url : $this->returnBaseURL($ssl)); + } + + /** + * Save current parts of the base Url + * + * @param string? $hostname + * @param int? $sslPolicy + * @param string? $urlPath + * + * @return bool true, if successful + */ + public function save($hostname = null, $sslPolicy = null, $urlPath = null) + { + $success = true; + + if (!empty($hostname)) { + $this->hostname = $hostname; + if (!$this->config->set('config', 'hostname', $this->hostname)) { + $success = false; + } + } + + if (isset($sslPolicy)) { + $this->sslPolicy = $sslPolicy; + if (!$this->config->set('system', 'ssl_policy', $this->sslPolicy)) { + $success = false; + } + } + + if (isset($urlPath)) { + $this->urlPath = $urlPath; + if (!$this->config->set('system', 'urlpath', $this->urlPath)) { + $success = false; + } + } + + $this->determineBaseUrl(); + if (!$this->config->set('system', 'url', $this->url)) { + $success = false; + } + + return $success; + } + + /** + * Save the current url as base URL + * + * @param $url + * + * @return bool true, if the save was successful + */ + public function saveByURL($url) + { + $parsed = @parse_url($url); + + if (empty($parsed)) { + return false; + } + + $hostname = $parsed['host']; + if (!empty($hostname) && !empty($parsed['port'])) { + $hostname .= ':' . $parsed['port']; + } + + $urlPath = null; + if (!empty($parsed['path'])) { + $urlPath = trim($parsed['path'], '\\/'); + } + + return $this->save($hostname, null, $urlPath); + } + + /** + * @param Configuration $config The Friendica configuration + * @param array $server The $_SERVER array + */ + public function __construct(Configuration $config, array $server) + { + $this->config = $config; + $this->server = $server; + + $this->checkConfig(); + $this->determineSchema(); + } + + /** + * Check the current config during loading + */ + public function checkConfig() + { + $this->hostname = $this->config->get('config', 'hostname', null); + $this->urlPath = $this->config->get('system', 'urlpath', null); + $this->sslPolicy = $this->config->get('system', 'ssl_policy', null); + $this->url = $this->config->get('system', 'url', null); + + if (empty($this->hostname)) { + $this->determineHostname(); + + if (!empty($this->hostname)) { + $this->config->set('config', 'hostname', $this->hostname); + } + } + + if (!isset($this->urlPath)) { + $this->determineURLPath(); + $this->config->set('system', 'urlpath', $this->urlPath); + } + + if (!isset($this->sslPolicy)) { + $this->sslPolicy = self::SSL_POLICY_NONE; + $this->config->set('system', 'ssl_policy', $this->sslPolicy); + } + + if (empty($this->url)) { + $this->determineBaseUrl(); + + if (!empty($url)) { + $this->config->set('system', 'url', $this->url); + } + } + } + + /** + * Determines the hostname of this node if not set already + */ + private function determineHostname() + { + $this->hostname = ''; + + if (!empty($this->server['SERVER_NAME'])) { + $this->hostname = $this->server['SERVER_NAME']; + + if (!empty($this->server['SERVER_PORT']) && $this->server['SERVER_PORT'] != 80 && $this->server['SERVER_PORT'] != 443) { + $this->hostname .= ':' . $this->server['SERVER_PORT']; + } + } + } + + /** + * Figure out if we are running at the top of a domain or in a sub-directory + */ + private function determineURLPath() + { + $this->urlPath = ''; + + /* + * The automatic path detection in this function is currently deactivated, + * see issue https://github.com/friendica/friendica/issues/6679 + * + * The problem is that the function seems to be confused with some url. + * These then confuses the detection which changes the url path. + */ + + /* Relative script path to the web server root + * Not all of those $_SERVER properties can be present, so we do by inverse priority order + */ + $relative_script_path = ''; + $relative_script_path = defaults($this->server, 'REDIRECT_URL', $relative_script_path); + $relative_script_path = defaults($this->server, 'REDIRECT_URI', $relative_script_path); + $relative_script_path = defaults($this->server, 'REDIRECT_SCRIPT_URL', $relative_script_path); + $relative_script_path = defaults($this->server, 'SCRIPT_URL', $relative_script_path); + $relative_script_path = defaults($this->server, 'REQUEST_URI', $relative_script_path); + + /* $relative_script_path gives /relative/path/to/friendica/module/parameter + * QUERY_STRING gives pagename=module/parameter + * + * To get /relative/path/to/friendica we perform dirname() for as many levels as there are slashes in the QUERY_STRING + */ + if (!empty($relative_script_path)) { + // Module + if (!empty($this->server['QUERY_STRING'])) { + $this->urlPath = trim(rdirname($relative_script_path, substr_count(trim($this->server['QUERY_STRING'], '/'), '/') + 1), '/'); + } else { + // Root page + $this->urlPath = trim($relative_script_path, '/'); + } + } + } + + /** + * Determine the full URL based on all parts + */ + private function determineBaseUrl() + { + $scheme = 'http'; + + if ($this->sslPolicy == self::SSL_POLICY_FULL) { + $scheme = 'https'; + } + + $this->url = $scheme . '://' . $this->hostname . (!empty($this->urlPath) ? '/' . $this->urlPath : '' ); + } + + /** + * Determine the scheme of the current used link + */ + private function determineSchema() + { + $this->scheme = 'http'; + + if (!empty($this->server['HTTPS']) || + !empty($this->server['HTTP_FORWARDED']) && preg_match('/proto=https/', $this->server['HTTP_FORWARDED']) || + !empty($this->server['HTTP_X_FORWARDED_PROTO']) && $this->server['HTTP_X_FORWARDED_PROTO'] == 'https' || + !empty($this->server['HTTP_X_FORWARDED_SSL']) && $this->server['HTTP_X_FORWARDED_SSL'] == 'on' || + !empty($this->server['FRONT_END_HTTPS']) && $this->server['FRONT_END_HTTPS'] == 'on' || + !empty($this->server['SERVER_PORT']) && (intval($this->server['SERVER_PORT']) == 443) // XXX: reasonable assumption, but isn't this hardcoding too much? + ) { + $this->scheme = 'https'; + } + } + + /** + * Returns the URL based on the current used ssl setting + * + * @param bool $ssl true, if ssl should be used + * + * @return string + */ + private function returnBaseURL($ssl) + { + if ($this->sslPolicy == self::SSL_POLICY_SELFSIGN && $ssl) { + return Network::switchScheme($this->url); + } + + return $this->url; + } +} diff --git a/src/Util/Config/ConfigFileSaver.php b/src/Util/Config/ConfigFileSaver.php deleted file mode 100644 index e32e11a4d5..0000000000 --- a/src/Util/Config/ConfigFileSaver.php +++ /dev/null @@ -1,341 +0,0 @@ -settings)); - - for ($i = 0; $i < $settingsCount; $i++) { - // if already set, overwrite the value - if ($this->settings[$i]['cat'] === $cat && - $this->settings[$i]['key'] === $key) { - $this->settings[$i] = ['cat' => $cat, 'key' => $key, 'value' => $value]; - return; - } - } - - $this->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 or nothing to do - */ - public function saveToConfigFile($name = '') - { - // If no settings et, return true - if (count(array_keys($this->settings)) === 0) { - return true; - } - - $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]; - } - - try { - $reading = fopen($fullName, 'r'); - } catch (\Exception $exception) { - return [null, null]; - } - - if (!$reading) { - return [null, null]; - } - - try { - $writing = fopen($fullName . '.tmp', 'w'); - } catch (\Exception $exception) { - fclose($reading); - return [null, null]; - } - - 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); - - try { - $renamed = rename($fullName, $fullName . '.old'); - } catch (\Exception $exception) { - return false; - } - - if (!$renamed) { - return false; - } - - try { - $renamed = rename($fullName . '.tmp', $fullName); - } catch (\Exception $exception) { - // revert the move of the current config file to have at least the old config - rename($fullName . '.old', $fullName); - return false; - } - - if (!$renamed) { - // 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++) { - - // find the category of the current setting - if (!$categoryFound[$i] && stristr($line, sprintf('[%s]', $this->settings[$i]['cat']))) { - $categoryFound[$i] = true; - - // check the current value - } 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; - - // If end of INI file, add the line before the INI end - } 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++) { - - // check for a non plain config setting (use category too) - 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; - - // check for a plain config setting (don't use a category) - } 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/src/Util/Network.php b/src/Util/Network.php index 35744647e3..b534a5505b 100644 --- a/src/Util/Network.php +++ b/src/Util/Network.php @@ -835,4 +835,26 @@ class Network (strlen($query) ? "?".$query : '') . (strlen($fragment) ? "#".$fragment : ''); } + + + /** + * @brief Switch the scheme of an url between http and https + * + * @param string $url URL + * + * @return string switched URL + */ + public static function switchScheme($url) + { + $parts = parse_url($url, PHP_URL_SCHEME); + if (!isset($parts['scheme'])) { + return $url; + } + if ($parts['scheme'] == 'http') { + $url = str_replace('http://', 'https://', $url); + } elseif ($parts['scheme'] == 'https') { + $url = str_replace('https://', 'http://', $url); + } + return $url; + } } diff --git a/tests/src/Util/Config/ConfigFileSaverTest.php b/tests/src/Util/Config/ConfigFileSaverTest.php deleted file mode 100644 index 04adf6014a..0000000000 --- a/tests/src/Util/Config/ConfigFileSaverTest.php +++ /dev/null @@ -1,189 +0,0 @@ -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->assertEquals('frio', $configCache->get('system', 'theme')); - $this->assertNull($configCache->get('config', 'test_val')); - $this->assertNull($configCache->get('system', 'test_val2')); - - // update values (system and config value) - $configFileSaver->addConfigValue('config', 'admin_email', 'new@mail.it'); - $configFileSaver->addConfigValue('system', 'theme', 'vier'); - - // insert values (system and config value) - $configFileSaver->addConfigValue('config', 'test_val', 'Testingwith@all.we can'); - $configFileSaver->addConfigValue('system', 'test_val2', 'TestIt First'); - - // overwrite value - $configFileSaver->addConfigValue('system', 'test_val2', 'TestIt Now'); - - // save it - $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)); - - $configFileSaver = new ConfigFileSaver($this->root->url()); - - $configFileSaver->addConfigValue('system', 'test_val2', 'TestIt Now'); - - // wrong mod, so return false if nothing to write - $this->assertFalse($configFileSaver->saveToConfigFile()); - } - - /** - * Test the saveToConfigFile() method with nothing to do - * @dataProvider dataConfigFiles - */ - public function testNothingToDo($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); - - // save nothing - $this->assertTrue($configFileSaver->saveToConfigFile()); - - $this->assertTrue($this->root->hasChild($relativeFullName)); - $this->assertFalse($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)->url())); - } -}