X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FApp%2FBaseURL.php;h=cc20343d1c4f8a5659e8224ef07616c5f372ac74;hb=4c6334ea13c0774e31b83a1cc7713c0560f7d66d;hp=6b79fad4662e6c0c88ad6bb18d457c79ad033e16;hpb=b852e5842bffcc1df1e5ac5d356fd9f19b7af499;p=friendica.git diff --git a/src/App/BaseURL.php b/src/App/BaseURL.php index 6b79fad466..cc20343d1c 100644 --- a/src/App/BaseURL.php +++ b/src/App/BaseURL.php @@ -1,398 +1,86 @@ . + * + */ namespace Friendica\App; -use Friendica\Core\Config\IConfiguration; +use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\System; -use Friendica\Util\Network; use Friendica\Util\Strings; use Friendica\Network\HTTPException; +use GuzzleHttp\Psr7\ServerRequest; +use GuzzleHttp\Psr7\Uri; +use Psr\Http\Message\UriInterface; +use Psr\Log\LoggerInterface; /** * A class which checks and contains the basic * environment for the BaseURL (url, urlpath, ssl_policy, hostname, scheme) */ -class BaseURL +class BaseURL extends Uri implements UriInterface { - /** - * No SSL necessary - */ - const SSL_POLICY_NONE = 0; - - /** - * SSL is necessary - */ - const SSL_POLICY_FULL = 1; - - /** - * SSL is optional, but preferred - */ - const SSL_POLICY_SELFSIGN = 2; - - /** - * Define the Default SSL scheme - */ - const DEFAULT_SSL_SCHEME = self::SSL_POLICY_SELFSIGN; - - /** - * The Friendica Config - * - * @var IConfiguration - */ - private $config; - - /** - * The server side variables - * - * @var array - */ - private $server; - - /** - * The hostname of the Base URL - * - * @var string - */ - private $hostname; - - /** - * The SSL_POLICY of the Base URL - * - * @var int - */ - private $sslPolicy; - - /** - * The URL sub-path of the Base URL - * - * @var string - */ - private $urlPath; - - /** - * The full URL - * - * @var string - */ - private $url; - - /** - * The current scheme of this call - * - * @var string - */ - private $scheme; - - /** - * Returns the hostname of this node - * - * @return string - */ - public function getHostname() - { - return $this->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) - { - if ($this->sslPolicy === self::SSL_POLICY_SELFSIGN && $ssl) { - return Network::switchScheme($this->url); - } - - return $this->url; - } - - /** - * 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) - { - $currHostname = $this->hostname; - $currSSLPolicy = $this->sslPolicy; - $currURLPath = $this->urlPath; - - if (!empty($hostname) && $hostname !== $this->hostname) { - if ($this->config->set('config', 'hostname', $hostname)) { - $this->hostname = $hostname; - } else { - return false; - } - } - - if (isset($sslPolicy) && $sslPolicy !== $this->sslPolicy) { - if ($this->config->set('system', 'ssl_policy', $sslPolicy)) { - $this->sslPolicy = $sslPolicy; - } else { - $this->hostname = $currHostname; - $this->config->set('config', 'hostname', $this->hostname); - return false; - } - } - - if (isset($urlPath) && $urlPath !== $this->urlPath) { - if ($this->config->set('system', 'urlpath', $urlPath)) { - $this->urlPath = $urlPath; - } else { - $this->hostname = $currHostname; - $this->sslPolicy = $currSSLPolicy; - $this->config->set('config', 'hostname', $this->hostname); - $this->config->set('system', 'ssl_policy', $this->sslPolicy); - return false; - } - } - - $this->determineBaseUrl(); - if (!$this->config->set('system', 'url', $this->url)) { - $this->hostname = $currHostname; - $this->sslPolicy = $currSSLPolicy; - $this->urlPath = $currURLPath; - $this->determineBaseUrl(); - - $this->config->set('config', 'hostname', $this->hostname); - $this->config->set('system', 'ssl_policy', $this->sslPolicy); - $this->config->set('system', 'urlpath', $this->urlPath); - return false; - } - - return true; - } - - /** - * 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'], '\\/'); - } - - $sslPolicy = null; - if (!empty($parsed['scheme'])) { - if ($parsed['scheme'] == 'https') { - $sslPolicy = BaseURL::SSL_POLICY_FULL; - } - } - - return $this->save($hostname, $sslPolicy, $urlPath); - } - - /** - * Checks, if a redirect to the HTTPS site would be necessary - * - * @return bool - */ - public function checkRedirectHttps() - { - return $this->config->get('system', 'force_ssl') && - ($this->getScheme() == "http") && - intval($this->getSSLPolicy()) == BaseURL::SSL_POLICY_FULL && - strpos($this->get(), 'https://') === 0 && - !empty($this->server['REQUEST_METHOD']) && - $this->server['REQUEST_METHOD'] === 'GET'; - } - - /** - * @param IConfiguration $config The Friendica IConfiguration - * @param array $server The $_SERVER array - */ - public function __construct(IConfiguration $config, array $server) + public function __construct(IManageConfigValues $config, LoggerInterface $logger, array $server = []) { - $this->config = $config; - $this->server = $server; - - $this->determineSchema(); - $this->checkConfig(); - } - - /** - * Check the current config during loading - */ - public function checkConfig() - { - $this->hostname = $this->config->get('config', 'hostname'); - $this->urlPath = $this->config->get('system', 'urlpath'); - $this->sslPolicy = $this->config->get('system', 'ssl_policy'); - $this->url = $this->config->get('system', 'url'); - - 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)) { - if ($this->scheme == 'https') { - $this->sslPolicy = self::SSL_POLICY_FULL; - } else { - $this->sslPolicy = self::DEFAULT_SSL_SCHEME; - } - $this->config->set('system', 'ssl_policy', $this->sslPolicy); - } - - if (empty($this->url)) { - $this->determineBaseUrl(); - - if (!empty($this->url)) { - $this->config->set('system', 'url', $this->url); - } + $url = $config->get('system', 'url'); + if (empty($url)) { + $logger->critical('Invalid config - Missing system.url'); + $url = ServerRequest::getUriFromGlobals() + ->withQuery('') + ->withPath($this->determineURLPath($server)); } - } - - /** - * 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']; - } - } + parent::__construct($url); } /** - * Figure out if we are running at the top of a domain or in a sub-directory + * Figure out if we are running at the top of a domain or in a subdirectory */ - private function determineURLPath() + private function determineURLPath(array $server): string { - $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 = - ($this->server['REDIRECT_URL'] ?? '') ?: - ($this->server['REDIRECT_URI'] ?? '') ?: - ($this->server['REDIRECT_SCRIPT_URL'] ?? '') ?: - ($this->server['SCRIPT_URL'] ?? '') ?: - $this->server['REQUEST_URI'] ?? ''; - - /* $relative_script_path gives /relative/path/to/friendica/module/parameter + $relativeScriptPath = + ($server['REDIRECT_URL'] ?? '') ?: + ($server['REDIRECT_URI'] ?? '') ?: + ($server['REDIRECT_SCRIPT_URL'] ?? '') ?: + ($server['SCRIPT_URL'] ?? '') ?: + $server['REQUEST_URI'] ?? ''; + + /* $relativeScriptPath 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)) { + if (!empty($relativeScriptPath)) { // Module - if (!empty($this->server['QUERY_STRING'])) { - $this->urlPath = trim(rdirname($relative_script_path, substr_count(trim($this->server['QUERY_STRING'], '/'), '/') + 1), '/'); + if (!empty($server['QUERY_STRING'])) { + return trim(dirname($relativeScriptPath, substr_count(trim($server['QUERY_STRING'], '/'), '/') + 1), '/'); } else { // Root page - $this->urlPath = trim($relative_script_path, '/'); + $scriptPathParts = explode('?', $relativeScriptPath, 2); + return trim($scriptPathParts[0], '/'); } } - } - - /** - * 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'; - } + return ''; } /** @@ -402,15 +90,15 @@ class BaseURL * * @return string The cleaned url */ - public function remove(string $origURL) + public function remove(string $origURL): string { // Remove the hostname from the url if it is an internal link $nurl = Strings::normaliseLink($origURL); - $base = Strings::normaliseLink($this->get()); + $base = Strings::normaliseLink($this->__toString()); $url = str_replace($base . '/', '', $nurl); - // if it is an external link return the orignal value - if ($url == Strings::normaliseLink($origURL)) { + // if it is an external link return the original value + if ($url === $nurl) { return $origURL; } else { return $url; @@ -424,23 +112,29 @@ class BaseURL * @param string $toUrl The destination URL (Default is empty, which is the default page of the Friendica node) * @param bool $ssl if true, base URL will try to get called with https:// (works just for relative paths) * + * @throws HTTPException\FoundException + * @throws HTTPException\MovedPermanentlyException + * @throws HTTPException\TemporaryRedirectException + * * @throws HTTPException\InternalServerErrorException In Case the given URL is not relative to the Friendica node */ - public function redirect($toUrl = '', $ssl = false) + public function redirect(string $toUrl = '', bool $ssl = false) { if (!empty(parse_url($toUrl, PHP_URL_SCHEME))) { - throw new HTTPException\InternalServerErrorException("'$toUrl is not a relative path, please use System::externalRedirectTo"); + throw new HTTPException\InternalServerErrorException("$toUrl is not a relative path, please use System::externalRedirectTo"); } - $redirectTo = $this->get($ssl) . '/' . ltrim($toUrl, '/'); + $redirectTo = $this->__toString() . '/' . ltrim($toUrl, '/'); System::externalRedirect($redirectTo); } - /** - * Returns the base url as string - */ - public function __toString() + public function isLocalUrl(string $url): bool + { + return strpos(Strings::normaliseLink($url), Strings::normaliseLink((string)$this)) === 0; + } + + public function isLocalUri(UriInterface $uri): bool { - return $this->get(); + return $this->isLocalUrl((string)$uri); } }