]> git.mxchange.org Git - friendica.git/blob - src/Util/BaseURL.php
a9bed2b5e8ab0f1f2197e7f5abf61ee61be047b6
[friendica.git] / src / Util / BaseURL.php
1 <?php
2
3 namespace Friendica\Util;
4
5 use Friendica\Core\Config\Configuration;
6
7 /**
8  * A class which checks and contains the basic
9  * environment for the BaseURL (url, urlpath, ssl_policy, hostname)
10  */
11 class BaseURL
12 {
13         /**
14          * No SSL necessary
15          */
16         const SSL_POLICY_NONE = 0;
17
18         /**
19          * SSL is necessary
20          */
21         const SSL_POLICY_FULL = 1;
22
23         /**
24          * SSL is optional, but preferred
25          */
26         const SSL_POLICY_SELFSIGN = 2;
27
28         /**
29          * The Friendica Config
30          * @var Configuration
31          */
32         private $config;
33
34         /**
35          * The server side variables
36          * @var array
37          */
38         private $server;
39
40         /**
41          * The hostname of the Base URL
42          * @var string
43          */
44         private $hostname;
45
46         /**
47          * The SSL_POLICY of the Base URL
48          * @var int
49          */
50         private $sslPolicy;
51
52         /**
53          * The URL sub-path of the Base URL
54          * @var string
55          */
56         private $urlPath;
57
58         /**
59          * The full URL
60          * @var string
61          */
62         private $url;
63
64         /**
65          * The current scheme of this call
66          * @var string
67          */
68         private $scheme;
69
70         /**
71          * Returns the hostname of this node
72          * @return string
73          */
74         public function getHostname()
75         {
76                 return $this->hostname;
77         }
78
79         /**
80          * Returns the current scheme of this call
81          * @return string
82          */
83         public function getScheme()
84         {
85                 return $this->scheme;
86         }
87
88         /**
89          * Returns the SSL policy of this node
90          * @return int
91          */
92         public function getSSLPolicy()
93         {
94                 return $this->sslPolicy;
95         }
96
97         /**
98          * Returns the sub-path of this URL
99          * @return string
100          */
101         public function getUrlPath()
102         {
103                 return $this->urlPath;
104         }
105
106         /**
107          * Returns the full URL of this call
108          *
109          * Note: $ssl parameter value doesn't directly correlate with the resulting protocol
110          *
111          * @param bool $ssl True, if ssl should get used
112          *
113          * @return string
114          */
115         public function get($ssl = false)
116         {
117                 return (!$ssl ? $this->url : $this->returnBaseURL($ssl));
118         }
119
120         /**
121          * Save current parts of the base Url
122          *
123          * @param string? $hostname
124          * @param int?    $sslPolicy
125          * @param string? $urlPath
126          *
127          * @return bool true, if successful
128          */
129         public function save($hostname = null, $sslPolicy = null, $urlPath = null)
130         {
131                 $success = true;
132
133                 if (!empty($hostname)) {
134                         $this->hostname  = $hostname;
135                         if (!$this->config->set('config', 'hostname', $this->hostname)) {
136                                 $success = false;
137                         }
138                 }
139
140                 if (isset($sslPolicy)) {
141                         $this->sslPolicy = $sslPolicy;
142                         if (!$this->config->set('system', 'ssl_policy', $this->sslPolicy)) {
143                                 $success = false;
144                         }
145                 }
146
147                 if (isset($urlPath)) {
148                         $this->urlPath   = $urlPath;
149                         if (!$this->config->set('system', 'urlpath', $this->urlPath)) {
150                                 $success = false;
151                         }
152                 }
153
154                 $this->determineBaseUrl();
155                 if (!$this->config->set('system', 'url', $this->url)) {
156                         $success = false;
157                 }
158
159                 return $success;
160         }
161
162         /**
163          * Save the current url as base URL
164          *
165          * @param $url
166          *
167          * @return bool true, if the save was successful
168          */
169         public function saveByURL($url)
170         {
171                 $parsed = @parse_url($url);
172
173                 if (empty($parsed)) {
174                         return false;
175                 }
176
177                 $hostname = $parsed['host'];
178                 if (!empty($hostname) && !empty($parsed['port'])) {
179                         $hostname .= ':' . $parsed['port'];
180                 }
181
182                 $urlPath = null;
183                 if (!empty($parsed['path'])) {
184                         $urlPath = trim($parsed['path'], '\\/');
185                 }
186
187                 return $this->save($hostname, null, $urlPath);
188         }
189
190         /**
191          * @param Configuration $config The Friendica configuration
192          * @param array         $server The $_SERVER array
193          */
194         public function __construct(Configuration $config, array $server)
195         {
196                 $this->config = $config;
197                 $this->server = $server;
198
199                 $this->checkConfig();
200                 $this->determineSchema();
201         }
202
203         /**
204          * Check the current config during loading
205          */
206         public function checkConfig()
207         {
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);
212
213                 if (empty($this->hostname)) {
214                         $this->determineHostname();
215
216                         if (!empty($this->hostname)) {
217                                 $this->config->set('config', 'hostname', $this->hostname);
218                         }
219                 }
220
221                 if (!isset($this->urlPath)) {
222                         $this->determineURLPath();
223                         $this->config->set('system', 'urlpath', $this->urlPath);
224                 }
225
226                 if (!isset($this->sslPolicy)) {
227                         $this->sslPolicy = self::SSL_POLICY_NONE;
228                         $this->config->set('system', 'ssl_policy', $this->sslPolicy);
229                 }
230
231                 if (empty($this->url)) {
232                         $this->determineBaseUrl();
233
234                         if (!empty($url)) {
235                                 $this->config->set('system', 'url', $this->url);
236                         }
237                 }
238         }
239
240         /**
241          * Determines the hostname of this node if not set already
242          */
243         private function determineHostname()
244         {
245                 $this->hostname = '';
246
247                 if (!empty($this->server['SERVER_NAME'])) {
248                         $this->hostname = $this->server['SERVER_NAME'];
249
250                         if (!empty($this->server['SERVER_PORT']) && $this->server['SERVER_PORT'] != 80 && $this->server['SERVER_PORT'] != 443) {
251                                 $this->hostname .= ':' . $this->server['SERVER_PORT'];
252                         }
253                 }
254         }
255
256         /**
257          * Figure out if we are running at the top of a domain or in a sub-directory
258          */
259         private function determineURLPath()
260         {
261                 $this->urlPath = '';
262
263                 /*
264                  * The automatic path detection in this function is currently deactivated,
265                  * see issue https://github.com/friendica/friendica/issues/6679
266                  *
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.
269                  */
270
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
273                  */
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);
280
281                 /* $relative_script_path gives /relative/path/to/friendica/module/parameter
282                  * QUERY_STRING gives pagename=module/parameter
283                  *
284                  * To get /relative/path/to/friendica we perform dirname() for as many levels as there are slashes in the QUERY_STRING
285                  */
286                 if (!empty($relative_script_path)) {
287                         // Module
288                         if (!empty($this->server['QUERY_STRING'])) {
289                                 $this->urlPath = trim(rdirname($relative_script_path, substr_count(trim($this->server['QUERY_STRING'], '/'), '/') + 1), '/');
290                         } else {
291                                 // Root page
292                                 $this->urlPath = trim($relative_script_path, '/');
293                         }
294                 }
295         }
296
297         /**
298          * Determine the full URL based on all parts
299          */
300         private function determineBaseUrl()
301         {
302                 $scheme = 'http';
303
304                 if ($this->sslPolicy == self::SSL_POLICY_FULL) {
305                         $scheme = 'https';
306                 }
307
308                 $this->url = $scheme . '://' . $this->hostname . (!empty($this->urlPath) ? '/' . $this->urlPath : '' );
309         }
310
311         /**
312          * Determine the scheme of the current used link
313          */
314         private function determineSchema()
315         {
316                 $this->scheme = 'http';
317
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?
324                 ) {
325                         $this->scheme = 'https';
326                 }
327         }
328
329         /**
330          * Returns the URL based on the current used ssl setting
331          *
332          * @param bool $ssl true, if ssl should be used
333          *
334          * @return string
335          */
336         private function returnBaseURL($ssl)
337         {
338                 if ($this->sslPolicy == self::SSL_POLICY_SELFSIGN && $ssl) {
339                         return Network::switchScheme($this->url);
340                 }
341
342                 return $this->url;
343         }
344 }