3 namespace Friendica\App;
5 use Friendica\Core\Config\Configuration;
6 use Friendica\Util\Network;
7 use Friendica\Util\Strings;
10 * A class which checks and contains the basic
11 * environment for the BaseURL (url, urlpath, ssl_policy, hostname, scheme)
18 const SSL_POLICY_NONE = 0;
23 const SSL_POLICY_FULL = 1;
26 * SSL is optional, but preferred
28 const SSL_POLICY_SELFSIGN = 2;
31 * Define the Default SSL scheme
33 const DEFAULT_SSL_SCHEME = self::SSL_POLICY_SELFSIGN;
36 * The Friendica Config
43 * The server side variables
50 * The hostname of the Base URL
57 * The SSL_POLICY of the Base URL
64 * The URL sub-path of the Base URL
78 * The current scheme of this call
85 * Returns the hostname of this node
89 public function getHostname()
91 return $this->hostname;
95 * Returns the current scheme of this call
99 public function getScheme()
101 return $this->scheme;
105 * Returns the SSL policy of this node
109 public function getSSLPolicy()
111 return $this->sslPolicy;
115 * Returns the sub-path of this URL
119 public function getUrlPath()
121 return $this->urlPath;
125 * Returns the full URL of this call
127 * Note: $ssl parameter value doesn't directly correlate with the resulting protocol
129 * @param bool $ssl True, if ssl should get used
133 public function get($ssl = false)
135 if ($this->sslPolicy === self::SSL_POLICY_SELFSIGN && $ssl) {
136 return Network::switchScheme($this->url);
143 * Save current parts of the base Url
145 * @param string? $hostname
146 * @param int? $sslPolicy
147 * @param string? $urlPath
149 * @return bool true, if successful
151 public function save($hostname = null, $sslPolicy = null, $urlPath = null)
153 $currHostname = $this->hostname;
154 $currSSLPolicy = $this->sslPolicy;
155 $currURLPath = $this->urlPath;
157 if (!empty($hostname) && $hostname !== $this->hostname) {
158 if ($this->config->set('config', 'hostname', $hostname)) {
159 $this->hostname = $hostname;
165 if (isset($sslPolicy) && $sslPolicy !== $this->sslPolicy) {
166 if ($this->config->set('system', 'ssl_policy', $sslPolicy)) {
167 $this->sslPolicy = $sslPolicy;
169 $this->hostname = $currHostname;
170 $this->config->set('config', 'hostname', $this->hostname);
175 if (isset($urlPath) && $urlPath !== $this->urlPath) {
176 if ($this->config->set('system', 'urlpath', $urlPath)) {
177 $this->urlPath = $urlPath;
179 $this->hostname = $currHostname;
180 $this->sslPolicy = $currSSLPolicy;
181 $this->config->set('config', 'hostname', $this->hostname);
182 $this->config->set('system', 'ssl_policy', $this->sslPolicy);
187 $this->determineBaseUrl();
188 if (!$this->config->set('system', 'url', $this->url)) {
189 $this->hostname = $currHostname;
190 $this->sslPolicy = $currSSLPolicy;
191 $this->urlPath = $currURLPath;
192 $this->determineBaseUrl();
194 $this->config->set('config', 'hostname', $this->hostname);
195 $this->config->set('system', 'ssl_policy', $this->sslPolicy);
196 $this->config->set('system', 'urlpath', $this->urlPath);
204 * Save the current url as base URL
208 * @return bool true, if the save was successful
210 public function saveByURL($url)
212 $parsed = @parse_url($url);
214 if (empty($parsed)) {
218 $hostname = $parsed['host'];
219 if (!empty($hostname) && !empty($parsed['port'])) {
220 $hostname .= ':' . $parsed['port'];
224 if (!empty($parsed['path'])) {
225 $urlPath = trim($parsed['path'], '\\/');
229 if (!empty($parsed['scheme'])) {
230 if ($parsed['scheme'] == 'https') {
231 $sslPolicy = BaseURL::SSL_POLICY_FULL;
235 return $this->save($hostname, $sslPolicy, $urlPath);
239 * Checks, if a redirect to the HTTPS site would be necessary
243 public function checkRedirectHttps()
245 return $this->config->get('system', 'force_ssl') &&
246 ($this->getScheme() == "http") &&
247 intval($this->getSSLPolicy()) == BaseURL::SSL_POLICY_FULL &&
248 strpos($this->get(), 'https://') === 0 &&
249 !empty($this->server['REQUEST_METHOD']) &&
250 $this->server['REQUEST_METHOD'] === 'GET';
254 * @param Configuration $config The Friendica configuration
255 * @param array $server The $_SERVER array
257 public function __construct(Configuration $config, array $server)
259 $this->config = $config;
260 $this->server = $server;
262 $this->determineSchema();
263 $this->checkConfig();
267 * Check the current config during loading
269 public function checkConfig()
271 $this->hostname = $this->config->get('config', 'hostname');
272 $this->urlPath = $this->config->get('system', 'urlpath');
273 $this->sslPolicy = $this->config->get('system', 'ssl_policy');
274 $this->url = $this->config->get('system', 'url');
276 if (empty($this->hostname)) {
277 $this->determineHostname();
279 if (!empty($this->hostname)) {
280 $this->config->set('config', 'hostname', $this->hostname);
284 if (!isset($this->urlPath)) {
285 $this->determineURLPath();
286 $this->config->set('system', 'urlpath', $this->urlPath);
289 if (!isset($this->sslPolicy)) {
290 if ($this->scheme == 'https') {
291 $this->sslPolicy = self::SSL_POLICY_FULL;
293 $this->sslPolicy = self::DEFAULT_SSL_SCHEME;
295 $this->config->set('system', 'ssl_policy', $this->sslPolicy);
298 if (empty($this->url)) {
299 $this->determineBaseUrl();
301 if (!empty($this->url)) {
302 $this->config->set('system', 'url', $this->url);
308 * Determines the hostname of this node if not set already
310 private function determineHostname()
312 $this->hostname = '';
314 if (!empty($this->server['SERVER_NAME'])) {
315 $this->hostname = $this->server['SERVER_NAME'];
317 if (!empty($this->server['SERVER_PORT']) && $this->server['SERVER_PORT'] != 80 && $this->server['SERVER_PORT'] != 443) {
318 $this->hostname .= ':' . $this->server['SERVER_PORT'];
324 * Figure out if we are running at the top of a domain or in a sub-directory
326 private function determineURLPath()
331 * The automatic path detection in this function is currently deactivated,
332 * see issue https://github.com/friendica/friendica/issues/6679
334 * The problem is that the function seems to be confused with some url.
335 * These then confuses the detection which changes the url path.
338 /* Relative script path to the web server root
339 * Not all of those $_SERVER properties can be present, so we do by inverse priority order
341 $relative_script_path = '';
342 $relative_script_path = defaults($this->server, 'REDIRECT_URL', $relative_script_path);
343 $relative_script_path = defaults($this->server, 'REDIRECT_URI', $relative_script_path);
344 $relative_script_path = defaults($this->server, 'REDIRECT_SCRIPT_URL', $relative_script_path);
345 $relative_script_path = defaults($this->server, 'SCRIPT_URL', $relative_script_path);
346 $relative_script_path = defaults($this->server, 'REQUEST_URI', $relative_script_path);
348 /* $relative_script_path gives /relative/path/to/friendica/module/parameter
349 * QUERY_STRING gives pagename=module/parameter
351 * To get /relative/path/to/friendica we perform dirname() for as many levels as there are slashes in the QUERY_STRING
353 if (!empty($relative_script_path)) {
355 if (!empty($this->server['QUERY_STRING'])) {
356 $this->urlPath = trim(rdirname($relative_script_path, substr_count(trim($this->server['QUERY_STRING'], '/'), '/') + 1), '/');
359 $this->urlPath = trim($relative_script_path, '/');
365 * Determine the full URL based on all parts
367 private function determineBaseUrl()
371 if ($this->sslPolicy == self::SSL_POLICY_FULL) {
375 $this->url = $scheme . '://' . $this->hostname . (!empty($this->urlPath) ? '/' . $this->urlPath : '');
379 * Determine the scheme of the current used link
381 private function determineSchema()
383 $this->scheme = 'http';
385 if (!empty($this->server['HTTPS']) ||
386 !empty($this->server['HTTP_FORWARDED']) && preg_match('/proto=https/', $this->server['HTTP_FORWARDED']) ||
387 !empty($this->server['HTTP_X_FORWARDED_PROTO']) && $this->server['HTTP_X_FORWARDED_PROTO'] == 'https' ||
388 !empty($this->server['HTTP_X_FORWARDED_SSL']) && $this->server['HTTP_X_FORWARDED_SSL'] == 'on' ||
389 !empty($this->server['FRONT_END_HTTPS']) && $this->server['FRONT_END_HTTPS'] == 'on' ||
390 !empty($this->server['SERVER_PORT']) && (intval($this->server['SERVER_PORT']) == 443) // XXX: reasonable assumption, but isn't this hardcoding too much?
392 $this->scheme = 'https';
397 * Removes the base url from an url. This avoids some mixed content problems.
399 * @param string $origURL
401 * @return string The cleaned url
403 public function remove(string $origURL)
405 // Remove the hostname from the url if it is an internal link
406 $nurl = Strings::normaliseLink($origURL);
407 $base = Strings::normaliseLink($this->get());
408 $url = str_replace($base . '/', '', $nurl);
410 // if it is an external link return the orignal value
411 if ($url == Strings::normaliseLink($origURL)) {