3 namespace Friendica\Util;
5 use Friendica\Core\Config\Configuration;
8 * A class which checks and contains the basic
9 * environment for the BaseURL (url, urlpath, ssl_policy, hostname)
16 const SSL_POLICY_NONE = 0;
21 const SSL_POLICY_FULL = 1;
24 * SSL is optional, but preferred
26 const SSL_POLICY_SELFSIGN = 2;
29 * The Friendica Config
35 * The server side variables
41 * The hostname of the Base URL
47 * The SSL_POLICY of the Base URL
53 * The URL sub-path of the Base URL
65 * The current scheme of this call
71 * Returns the hostname of this node
74 public function getHostname()
76 return $this->hostname;
80 * Returns the current scheme of this call
83 public function getScheme()
89 * Returns the SSL policy of this node
92 public function getSSLPolicy()
94 return $this->sslPolicy;
98 * Returns the sub-path of this URL
101 public function getUrlPath()
103 return $this->urlPath;
107 * Returns the full URL of this call
109 * Note: $ssl parameter value doesn't directly correlate with the resulting protocol
111 * @param bool $ssl True, if ssl should get used
115 public function get($ssl = false)
117 return (!$ssl ? $this->url : $this->returnBaseURL($ssl));
121 * Save current parts of the base Url
123 * @param string? $hostname
124 * @param int? $sslPolicy
125 * @param string? $urlPath
127 * @return bool true, if successful
129 public function save($hostname = null, $sslPolicy = null, $urlPath = null)
133 if (!empty($hostname)) {
134 $this->hostname = $hostname;
135 if (!$this->config->set('config', 'hostname', $this->hostname)) {
140 if (isset($sslPolicy)) {
141 $this->sslPolicy = $sslPolicy;
142 if (!$this->config->set('system', 'ssl_policy', $this->sslPolicy)) {
147 if (isset($urlPath)) {
148 $this->urlPath = $urlPath;
149 if (!$this->config->set('system', 'urlpath', $this->urlPath)) {
154 $this->determineBaseUrl();
155 if (!$this->config->set('system', 'url', $this->url)) {
163 * Save the current url as base URL
167 * @return bool true, if the save was successful
169 public function saveByURL($url)
171 $parsed = @parse_url($url);
173 if (empty($parsed)) {
177 $hostname = $parsed['host'];
178 if (!empty($hostname) && !empty($parsed['port'])) {
179 $hostname .= ':' . $parsed['port'];
183 if (!empty($parsed['path'])) {
184 $urlPath = trim($parsed['path'], '\\/');
187 return $this->save($hostname, null, $urlPath);
191 * @param Configuration $config The Friendica configuration
192 * @param array $server The $_SERVER array
194 public function __construct(Configuration $config, array $server)
196 $this->config = $config;
197 $this->server = $server;
199 $this->checkConfig();
200 $this->determineSchema();
204 * Check the current config during loading
206 public function checkConfig()
208 $this->hostname = $this->config->get('config', 'hostname', null);
209 $this->urlPath = $this->config->get('system', 'urlpath', null);
210 $this->sslPolicy = $this->config->get('system', 'ssl_policy', null);
211 $this->url = $this->config->get('system', 'url', null);
213 if (empty($this->hostname)) {
214 $this->determineHostname();
216 if (!empty($this->hostname)) {
217 $this->config->set('config', 'hostname', $this->hostname);
221 if (!isset($this->urlPath)) {
222 $this->determineURLPath();
223 $this->config->set('system', 'urlpath', $this->urlPath);
226 if (!isset($this->sslPolicy)) {
227 $this->sslPolicy = self::SSL_POLICY_NONE;
228 $this->config->set('system', 'ssl_policy', $this->sslPolicy);
231 if (empty($this->url)) {
232 $this->determineBaseUrl();
235 $this->config->set('system', 'url', $this->url);
241 * Determines the hostname of this node if not set already
243 private function determineHostname()
245 $this->hostname = '';
247 if (!empty($this->server['SERVER_NAME'])) {
248 $this->hostname = $this->server['SERVER_NAME'];
250 if (!empty($this->server['SERVER_PORT']) && $this->server['SERVER_PORT'] != 80 && $this->server['SERVER_PORT'] != 443) {
251 $this->hostname .= ':' . $this->server['SERVER_PORT'];
257 * Figure out if we are running at the top of a domain or in a sub-directory
259 private function determineURLPath()
264 * The automatic path detection in this function is currently deactivated,
265 * see issue https://github.com/friendica/friendica/issues/6679
267 * The problem is that the function seems to be confused with some url.
268 * These then confuses the detection which changes the url path.
271 /* Relative script path to the web server root
272 * Not all of those $_SERVER properties can be present, so we do by inverse priority order
274 $relative_script_path = '';
275 $relative_script_path = defaults($this->server, 'REDIRECT_URL', $relative_script_path);
276 $relative_script_path = defaults($this->server, 'REDIRECT_URI', $relative_script_path);
277 $relative_script_path = defaults($this->server, 'REDIRECT_SCRIPT_URL', $relative_script_path);
278 $relative_script_path = defaults($this->server, 'SCRIPT_URL', $relative_script_path);
279 $relative_script_path = defaults($this->server, 'REQUEST_URI', $relative_script_path);
281 /* $relative_script_path gives /relative/path/to/friendica/module/parameter
282 * QUERY_STRING gives pagename=module/parameter
284 * To get /relative/path/to/friendica we perform dirname() for as many levels as there are slashes in the QUERY_STRING
286 if (!empty($relative_script_path)) {
288 if (!empty($this->server['QUERY_STRING'])) {
289 $this->urlPath = trim(rdirname($relative_script_path, substr_count(trim($this->server['QUERY_STRING'], '/'), '/') + 1), '/');
292 $this->urlPath = trim($relative_script_path, '/');
298 * Determine the full URL based on all parts
300 private function determineBaseUrl()
304 if ($this->sslPolicy == self::SSL_POLICY_FULL) {
308 $this->url = $scheme . '://' . $this->hostname . (!empty($this->urlPath) ? '/' . $this->urlPath : '' );
312 * Determine the scheme of the current used link
314 private function determineSchema()
316 $this->scheme = 'http';
318 if (!empty($this->server['HTTPS']) ||
319 !empty($this->server['HTTP_FORWARDED']) && preg_match('/proto=https/', $this->server['HTTP_FORWARDED']) ||
320 !empty($this->server['HTTP_X_FORWARDED_PROTO']) && $this->server['HTTP_X_FORWARDED_PROTO'] == 'https' ||
321 !empty($this->server['HTTP_X_FORWARDED_SSL']) && $this->server['HTTP_X_FORWARDED_SSL'] == 'on' ||
322 !empty($this->server['FRONT_END_HTTPS']) && $this->server['FRONT_END_HTTPS'] == 'on' ||
323 !empty($this->server['SERVER_PORT']) && (intval($this->server['SERVER_PORT']) == 443) // XXX: reasonable assumption, but isn't this hardcoding too much?
325 $this->scheme = 'https';
330 * Returns the URL based on the current used ssl setting
332 * @param bool $ssl true, if ssl should be used
336 private function returnBaseURL($ssl)
338 if ($this->sslPolicy == self::SSL_POLICY_SELFSIGN && $ssl) {
339 return Network::switchScheme($this->url);