PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 4.0.2
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v4.0.2
5.11.1 5.11.0 5.10.2 5.10.1 trunk 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.3.2 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.2 4.1.3 4.10.0 4.11.0 4.12.0 4.13.0 4.13.2 4.13.3 4.13.4 4.13.5 4.14.0 4.14.1 4.14.2 4.15.0 4.15.1 4.15.2 4.15.3 4.2.0 4.3.0 4.3.1 4.4.1 4.4.2 4.5.0 4.6.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.10.0 5.2.0 5.2.1 5.2.2 5.3.0 5.3.1 5.3.2 5.3.3 5.6.0 5.6.1 5.7.0 5.7.1 5.8.0 5.8.1 5.8.2
matomo / app / core / Url.php
matomo / app / core Last commit date
API 5 years ago Access 5 years ago Application 5 years ago Archive 5 years ago ArchiveProcessor 5 years ago Archiver 5 years ago AssetManager 5 years ago Auth 5 years ago Category 5 years ago CliMulti 5 years ago Columns 5 years ago Composer 5 years ago Concurrency 5 years ago Config 5 years ago Container 5 years ago CronArchive 5 years ago DataAccess 5 years ago DataFiles 5 years ago DataTable 5 years ago Db 5 years ago DeviceDetector 5 years ago Email 5 years ago Exception 5 years ago Http 5 years ago Intl 5 years ago Mail 5 years ago Measurable 5 years ago Menu 5 years ago Metrics 5 years ago Notification 5 years ago Period 5 years ago Plugin 5 years ago ProfessionalServices 5 years ago Report 5 years ago ReportRenderer 5 years ago Scheduler 5 years ago Segment 5 years ago Session 5 years ago Settings 5 years ago Tracker 5 years ago Translation 5 years ago UpdateCheck 5 years ago Updater 5 years ago Updates 5 years ago Validators 5 years ago View 5 years ago ViewDataTable 5 years ago Visualization 5 years ago Widget 5 years ago .htaccess 6 years ago Access.php 5 years ago Archive.php 5 years ago ArchiveProcessor.php 5 years ago AssetManager.php 5 years ago Auth.php 5 years ago AuthResult.php 5 years ago BaseFactory.php 5 years ago Cache.php 5 years ago CacheId.php 5 years ago CliMulti.php 5 years ago Common.php 5 years ago Config.php 5 years ago Console.php 5 years ago Context.php 5 years ago Cookie.php 5 years ago CronArchive.php 5 years ago DataArray.php 5 years ago DataTable.php 5 years ago Date.php 5 years ago Db.php 5 years ago DbHelper.php 5 years ago Development.php 5 years ago ErrorHandler.php 5 years ago EventDispatcher.php 5 years ago ExceptionHandler.php 5 years ago FileIntegrity.php 5 years ago Filechecks.php 5 years ago Filesystem.php 5 years ago FrontController.php 5 years ago Http.php 5 years ago IP.php 5 years ago Log.php 5 years ago LogDeleter.php 5 years ago Mail.php 5 years ago Metrics.php 5 years ago NoAccessException.php 5 years ago Nonce.php 5 years ago Notification.php 5 years ago NumberFormatter.php 5 years ago Option.php 5 years ago Period.php 5 years ago Piwik.php 5 years ago Plugin.php 5 years ago Profiler.php 5 years ago ProxyHeaders.php 5 years ago ProxyHttp.php 5 years ago QuickForm2.php 5 years ago RankingQuery.php 5 years ago ReportRenderer.php 5 years ago Segment.php 5 years ago Sequence.php 5 years ago Session.php 5 years ago SettingsPiwik.php 5 years ago SettingsServer.php 5 years ago Singleton.php 5 years ago Site.php 5 years ago TCPDF.php 5 years ago Theme.php 5 years ago Timer.php 5 years ago Tracker.php 5 years ago Twig.php 5 years ago Unzip.php 5 years ago UpdateCheck.php 5 years ago Updater.php 5 years ago UpdaterErrorException.php 5 years ago Updates.php 5 years ago Url.php 5 years ago UrlHelper.php 5 years ago Version.php 5 years ago View.php 5 years ago bootstrap.php 5 years ago dispatch.php 5 years ago testMinimumPhpVersion.php 5 years ago
Url.php
791 lines
1 <?php
2 /**
3 * Matomo - free/libre analytics platform
4 *
5 * @link https://matomo.org
6 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
7 *
8 */
9 namespace Piwik;
10
11 use Exception;
12 use Matomo\Network\IPUtils;
13
14 /**
15 * Provides URL related helper methods.
16 *
17 * This class provides simple methods that can be used to parse and modify
18 * the current URL. It is most useful when plugins need to redirect the current
19 * request to a URL and when they need to link to other parts of Piwik in
20 * HTML.
21 *
22 * ### Examples
23 *
24 * **Redirect to a different controller action**
25 *
26 * public function myControllerAction()
27 * {
28 * $url = Url::getCurrentQueryStringWithParametersModified(array(
29 * 'module' => 'DevicesDetection',
30 * 'action' => 'index'
31 * ));
32 * Url::redirectToUrl($url);
33 * }
34 *
35 * **Link to a different controller action in a template**
36 *
37 * public function myControllerAction()
38 * {
39 * $url = Url::getCurrentQueryStringWithParametersModified(array(
40 * 'module' => 'UserCountryMap',
41 * 'action' => 'realtimeMap',
42 * 'changeVisitAlpha' => 0,
43 * 'removeOldVisits' => 0
44 * ));
45 * $view = new View("@MyPlugin/myPopup");
46 * $view->realtimeMapUrl = $url;
47 * return $view->render();
48 * }
49 *
50 */
51 class Url
52 {
53 /**
54 * Returns the current URL.
55 *
56 * @return string eg, `"http://example.org/dir1/dir2/index.php?param1=value1&param2=value2"`
57 * @api
58 */
59 public static function getCurrentUrl()
60 {
61 return self::getCurrentScheme() . '://'
62 . self::getCurrentHost()
63 . self::getCurrentScriptName(false)
64 . self::getCurrentQueryString();
65 }
66
67 /**
68 * Returns the current URL without the query string.
69 *
70 * @param bool $checkTrustedHost Whether to do trusted host check. Should ALWAYS be true,
71 * except in {@link Piwik\Plugin\Controller}.
72 * @return string eg, `"http://example.org/dir1/dir2/index.php"` if the current URL is
73 * `"http://example.org/dir1/dir2/index.php?param1=value1&param2=value2"`.
74 * @api
75 */
76 public static function getCurrentUrlWithoutQueryString($checkTrustedHost = true)
77 {
78 return self::getCurrentScheme() . '://'
79 . self::getCurrentHost($default = 'unknown', $checkTrustedHost)
80 . self::getCurrentScriptName(false);
81 }
82
83 /**
84 * Returns the current URL without the query string and without the name of the file
85 * being executed.
86 *
87 * @return string eg, `"http://example.org/dir1/dir2/"` if the current URL is
88 * `"http://example.org/dir1/dir2/index.php?param1=value1&param2=value2"`.
89 * @api
90 */
91 public static function getCurrentUrlWithoutFileName()
92 {
93 return self::getCurrentScheme() . '://'
94 . self::getCurrentHost()
95 . self::getCurrentScriptPath();
96 }
97
98 /**
99 * Returns the path to the script being executed. The script file name is not included.
100 *
101 * @return string eg, `"/dir1/dir2/"` if the current URL is
102 * `"http://example.org/dir1/dir2/index.php?param1=value1&param2=value2"`
103 * @api
104 */
105 public static function getCurrentScriptPath()
106 {
107 $queryString = self::getCurrentScriptName();
108
109 //add a fake letter case /test/test2/ returns /test which is not expected
110 $urlDir = dirname($queryString . 'x');
111 $urlDir = str_replace('\\', '/', $urlDir);
112 // if we are in a subpath we add a trailing slash
113 if (strlen($urlDir) > 1) {
114 $urlDir .= '/';
115 }
116 return $urlDir;
117 }
118
119 /**
120 * Returns the path to the script being executed. Includes the script file name.
121 *
122 * @param bool $removePathInfo If true (default value) then the PATH_INFO will be stripped.
123 * @return string eg, `"/dir1/dir2/index.php"` if the current URL is
124 * `"http://example.org/dir1/dir2/index.php?param1=value1&param2=value2"`
125 * @api
126 */
127 public static function getCurrentScriptName($removePathInfo = true)
128 {
129 $url = '';
130
131 // insert extra path info if proxy_uri_header is set and enabled
132 if (isset(Config::getInstance()->General['proxy_uri_header'])
133 && Config::getInstance()->General['proxy_uri_header'] == 1
134 && !empty($_SERVER['HTTP_X_FORWARDED_URI'])
135 ) {
136 $url .= $_SERVER['HTTP_X_FORWARDED_URI'];
137 }
138
139 if (!empty($_SERVER['REQUEST_URI'])) {
140 $url .= $_SERVER['REQUEST_URI'];
141
142 // strip http://host (Apache+Rails anomaly)
143 if (preg_match('~^https?://[^/]+($|/.*)~D', $url, $matches)) {
144 $url = $matches[1];
145 }
146
147 // strip parameters
148 if (($pos = strpos($url, "?")) !== false) {
149 $url = substr($url, 0, $pos);
150 }
151
152 // strip path_info
153 if ($removePathInfo && !empty($_SERVER['PATH_INFO'])) {
154 $url = substr($url, 0, -strlen($_SERVER['PATH_INFO']));
155 }
156 }
157
158 /**
159 * SCRIPT_NAME is our fallback, though it may not be set correctly
160 *
161 * @see http://php.net/manual/en/reserved.variables.php
162 */
163 if (empty($url)) {
164 if (isset($_SERVER['SCRIPT_NAME'])) {
165 $url = $_SERVER['SCRIPT_NAME'];
166 } elseif (isset($_SERVER['SCRIPT_FILENAME'])) {
167 $url = $_SERVER['SCRIPT_FILENAME'];
168 } elseif (isset($_SERVER['argv'])) {
169 $url = $_SERVER['argv'][0];
170 }
171 }
172
173 if (!isset($url[0]) || $url[0] !== '/') {
174 $url = '/' . $url;
175 }
176 return $url;
177 }
178
179 /**
180 * Returns the current URL's protocol.
181 *
182 * @return string `'https'` or `'http'`
183 * @api
184 */
185 public static function getCurrentScheme()
186 {
187 if (self::isPiwikConfiguredToAssumeSecureConnection()) {
188 return 'https';
189 }
190 return self::getCurrentSchemeFromRequestHeader();
191 }
192
193 /**
194 * Validates the **Host** HTTP header (untrusted user input). Used to prevent Host header
195 * attacks.
196 *
197 * @param string|bool $host Contents of Host: header from the HTTP request. If `false`, gets the
198 * value from the request.
199 * @return bool `true` if valid; `false` otherwise.
200 */
201 public static function isValidHost($host = false)
202 {
203 // only do trusted host check if it's enabled
204 if (isset(Config::getInstance()->General['enable_trusted_host_check'])
205 && Config::getInstance()->General['enable_trusted_host_check'] == 0
206 ) {
207 return true;
208 }
209
210 if ($host === false) {
211 $host = self::getHostFromServerNameVar();
212 if (empty($host)) {
213 // fallback to old behaviour
214 $host = @$_SERVER['HTTP_HOST'];
215 if (empty($host)) {
216 // if no current host, assume valid
217 return true;
218 }
219 }
220 }
221
222 // if host is in hardcoded allowlist, assume it's valid
223 if (in_array($host, self::getAlwaysTrustedHosts())) {
224 return true;
225 }
226
227 $trustedHosts = self::getTrustedHosts();
228
229 // Only punctuation we allow is '[', ']', ':', '.', '_' and '-'
230 $hostLength = strlen($host);
231 if ($hostLength !== strcspn($host, '`~!@#$%^&*()+={}\\|;"\'<>,?/ ')) {
232 return false;
233 }
234
235 // if no trusted hosts, just assume it's valid
236 if (empty($trustedHosts)) {
237 self::saveTrustedHostnameInConfig($host);
238 return true;
239 }
240
241 // Escape trusted hosts for preg_match call below
242 foreach ($trustedHosts as &$trustedHost) {
243 $trustedHost = preg_quote($trustedHost);
244 }
245 $trustedHosts = str_replace("/", "\\/", $trustedHosts);
246
247 $untrustedHost = Common::mb_strtolower($host);
248 $untrustedHost = rtrim($untrustedHost, '.');
249
250 $hostRegex = Common::mb_strtolower('/(^|.)' . implode('$|', $trustedHosts) . '$/');
251
252 $result = preg_match($hostRegex, $untrustedHost);
253 return 0 !== $result;
254 }
255
256 /**
257 * Records one host, or an array of hosts in the config file,
258 * if user is Super User
259 *
260 * @static
261 * @param $host string|array
262 * @return bool
263 */
264 public static function saveTrustedHostnameInConfig($host)
265 {
266 return self::saveHostsnameInConfig($host, 'General', 'trusted_hosts');
267 }
268
269 public static function saveCORSHostnameInConfig($host)
270 {
271 return self::saveHostsnameInConfig($host, 'General', 'cors_domains');
272 }
273
274 protected static function saveHostsnameInConfig($host, $domain, $key)
275 {
276 if (Piwik::hasUserSuperUserAccess()
277 && file_exists(Config::getLocalConfigPath())
278 ) {
279 $config = Config::getInstance()->$domain;
280 if (!is_array($host)) {
281 $host = array($host);
282 }
283 $host = array_filter($host);
284 if (empty($host)) {
285 return false;
286 }
287 $config[$key] = $host;
288 Config::getInstance()->$domain = $config;
289 Config::getInstance()->forceSave();
290 return true;
291 }
292 return false;
293 }
294
295 /**
296 * Returns the current host.
297 *
298 * @param bool $checkIfTrusted Whether to do trusted host check. Should ALWAYS be true,
299 * except in Controller.
300 * @return string|bool eg, `"demo.piwik.org"` or false if no host found.
301 */
302 public static function getHost($checkIfTrusted = true)
303 {
304 if (strlen($host = self::getHostFromServerNameVar())) {
305 // if server_name is set we don't want to look at HTTP_HOST
306
307 if (!$checkIfTrusted || self::isValidHost($host)) {
308 return $host;
309 }
310 } elseif (isset($_SERVER['HTTP_HOST'])
311 && strlen($host = $_SERVER['HTTP_HOST'])
312 && (!$checkIfTrusted
313 || self::isValidHost($host))
314 ) {
315 // HTTP/1.1 request
316 return $host;
317 }
318
319 // HTTP/1.0 request doesn't include Host: header
320 if (isset($_SERVER['SERVER_ADDR'])) {
321 return $_SERVER['SERVER_ADDR'];
322 }
323
324 return false;
325 }
326
327 /**
328 * Sets the host. Useful for CLI scripts, eg. core:archive command
329 *
330 * @param $host string
331 */
332 public static function setHost($host)
333 {
334 $_SERVER['SERVER_NAME'] = $host;
335 $_SERVER['HTTP_HOST'] = $host;
336 unset($_SERVER['SERVER_PORT']);
337 }
338
339 /**
340 * Returns the current host.
341 *
342 * @param string $default Default value to return if host unknown
343 * @param bool $checkTrustedHost Whether to do trusted host check. Should ALWAYS be true,
344 * except in Controller.
345 * @return string eg, `"example.org"` if the current URL is
346 * `"http://example.org/dir1/dir2/index.php?param1=value1&param2=value2"`
347 * @api
348 */
349 public static function getCurrentHost($default = 'unknown', $checkTrustedHost = true)
350 {
351 $hostHeaders = array();
352
353 $config = Config::getInstance()->General;
354 if (isset($config['proxy_host_headers'])) {
355 $hostHeaders = $config['proxy_host_headers'];
356 }
357
358 if (!is_array($hostHeaders)) {
359 $hostHeaders = array();
360 }
361
362 $host = self::getHost($checkTrustedHost);
363 $default = Common::sanitizeInputValue($host ? $host : $default);
364
365 return IP::getNonProxyIpFromHeader($default, $hostHeaders);
366 }
367
368 /**
369 * Returns the query string of the current URL.
370 *
371 * @return string eg, `"?param1=value1&param2=value2"` if the current URL is
372 * `"http://example.org/dir1/dir2/index.php?param1=value1&param2=value2"`
373 * @api
374 */
375 public static function getCurrentQueryString()
376 {
377 $url = '';
378 if (isset($_SERVER['QUERY_STRING'])
379 && !empty($_SERVER['QUERY_STRING'])
380 ) {
381 $url .= "?" . $_SERVER['QUERY_STRING'];
382 }
383 return $url;
384 }
385
386 /**
387 * Returns an array mapping query parameter names with query parameter values for
388 * the current URL.
389 *
390 * @return array If current URL is `"http://example.org/dir1/dir2/index.php?param1=value1&param2=value2"`
391 * this will return:
392 *
393 * array(
394 * 'param1' => string 'value1',
395 * 'param2' => string 'value2'
396 * )
397 * @api
398 */
399 public static function getArrayFromCurrentQueryString()
400 {
401 $queryString = self::getCurrentQueryString();
402 $urlValues = UrlHelper::getArrayFromQueryString($queryString);
403 return $urlValues;
404 }
405
406 /**
407 * Modifies the current query string with the supplied parameters and returns
408 * the result. Parameters in the current URL will be overwritten with values
409 * in `$params` and parameters absent from the current URL but present in `$params`
410 * will be added to the result.
411 *
412 * @param array $params set of parameters to modify/add in the current URL
413 * eg, `array('param3' => 'value3')`
414 * @return string eg, `"?param2=value2&param3=value3"`
415 * @api
416 */
417 public static function getCurrentQueryStringWithParametersModified($params)
418 {
419 $urlValues = self::getArrayFromCurrentQueryString();
420 foreach ($params as $key => $value) {
421 $urlValues[$key] = $value;
422 }
423 $query = self::getQueryStringFromParameters($urlValues);
424 if (strlen($query) > 0) {
425 return '?' . $query;
426 }
427 return '';
428 }
429
430 /**
431 * Converts an array of parameters name => value mappings to a query
432 * string. Values must already be URL encoded before you call this function.
433 *
434 * @param array $parameters eg. `array('param1' => 10, 'param2' => array(1,2))`
435 * @return string eg. `"param1=10&param2[]=1&param2[]=2"`
436 * @api
437 */
438 public static function getQueryStringFromParameters($parameters)
439 {
440 $query = '';
441 foreach ($parameters as $name => $value) {
442 if (is_null($value) || $value === false) {
443 continue;
444 }
445 if (is_array($value)) {
446 foreach ($value as $theValue) {
447 $query .= $name . "[]=" . $theValue . "&";
448 }
449 } else {
450 $query .= $name . "=" . $value . "&";
451 }
452 }
453 $query = substr($query, 0, -1);
454 return $query;
455 }
456
457 public static function getQueryStringFromUrl($url)
458 {
459 return parse_url($url, PHP_URL_QUERY);
460 }
461
462 /**
463 * Redirects the user to the referrer. If no referrer exists, the user is redirected
464 * to the current URL without query string.
465 *
466 * @api
467 */
468 public static function redirectToReferrer()
469 {
470 $referrer = self::getReferrer();
471 if ($referrer !== false) {
472 self::redirectToUrl($referrer);
473 }
474 self::redirectToUrl(self::getCurrentUrlWithoutQueryString());
475 }
476
477 private static function redirectToUrlNoExit($url)
478 {
479 if (UrlHelper::isLookLikeUrl($url)
480 || strpos($url, 'index.php') === 0
481 ) {
482 Common::sendResponseCode(302);
483 Common::sendHeader("X-Robots-Tag: noindex");
484 Common::sendHeader("Location: $url");
485 } else {
486 echo "Invalid URL to redirect to.";
487 }
488
489 if (Common::isPhpCliMode()) {
490 throw new Exception("If you were using a browser, Matomo would redirect you to this URL: $url \n\n");
491 }
492 }
493
494 /**
495 * Redirects the user to the specified URL.
496 *
497 * @param string $url
498 * @throws Exception
499 * @api
500 */
501 public static function redirectToUrl($url)
502 {
503 // Close the session manually.
504 // We should not have to call this because it was registered via register_shutdown_function,
505 // but it is not always called fast enough
506 Session::close();
507
508 self::redirectToUrlNoExit($url);
509
510 exit;
511 }
512
513 /**
514 * If the page is using HTTP, redirect to the same page over HTTPS
515 */
516 public static function redirectToHttps()
517 {
518 if (ProxyHttp::isHttps()) {
519 return;
520 }
521 $url = self::getCurrentUrl();
522 $url = str_replace("http://", "https://", $url);
523 self::redirectToUrl($url);
524 }
525
526 /**
527 * Returns the **HTTP_REFERER** `$_SERVER` variable, or `false` if not found.
528 *
529 * @return string|false
530 * @api
531 */
532 public static function getReferrer()
533 {
534 if (!empty($_SERVER['HTTP_REFERER'])) {
535 return $_SERVER['HTTP_REFERER'];
536 }
537 return false;
538 }
539
540 /**
541 * Returns `true` if the URL points to something on the same host, `false` if otherwise.
542 *
543 * @param string $url
544 * @return bool True if local; false otherwise.
545 * @api
546 */
547 public static function isLocalUrl($url)
548 {
549 if (empty($url)) {
550 return true;
551 }
552
553 // handle host name mangling
554 $requestUri = isset($_SERVER['SCRIPT_URI']) ? $_SERVER['SCRIPT_URI'] : '';
555 $parseRequest = @parse_url($requestUri);
556 $hosts = array(self::getHost(), self::getCurrentHost());
557 if (!empty($parseRequest['host'])) {
558 $hosts[] = $parseRequest['host'];
559 }
560
561 // drop port numbers from hostnames and IP addresses
562 $hosts = array_map(array('self', 'getHostSanitized'), $hosts);
563
564 $disableHostCheck = Config::getInstance()->General['enable_trusted_host_check'] == 0;
565 // compare scheme and host
566 $parsedUrl = @parse_url($url);
567 $host = IPUtils::sanitizeIp(@$parsedUrl['host']);
568 return !empty($host)
569 && ($disableHostCheck || in_array($host, $hosts))
570 && !empty($parsedUrl['scheme'])
571 && in_array($parsedUrl['scheme'], array('http', 'https'));
572 }
573
574 /**
575 * Checks whether the given host is a local host like `127.0.0.1` or `localhost`.
576 *
577 * @param string $host
578 * @return bool
579 */
580 public static function isLocalHost($host)
581 {
582 if (empty($host)) {
583 return false;
584 }
585
586 // remove port
587 $hostWithoutPort = explode(':', $host);
588 array_pop($hostWithoutPort);
589 $hostWithoutPort = implode(':', $hostWithoutPort);
590
591 $localHostnames = Url::getLocalHostnames();
592 return in_array($host, $localHostnames, true)
593 || in_array($hostWithoutPort, $localHostnames, true);
594 }
595
596 public static function getTrustedHostsFromConfig()
597 {
598 $hosts = self::getHostsFromConfig('General', 'trusted_hosts');
599
600 // Case user wrote in the config, http://example.com/test instead of example.com
601 foreach ($hosts as &$host) {
602 if (UrlHelper::isLookLikeUrl($host)) {
603 $host = parse_url($host, PHP_URL_HOST);
604 }
605 }
606 return $hosts;
607 }
608
609 public static function getTrustedHosts()
610 {
611 return self::getTrustedHostsFromConfig();
612 }
613
614 public static function getCorsHostsFromConfig()
615 {
616 return self::getHostsFromConfig('General', 'cors_domains');
617 }
618
619 /**
620 * Returns hostname, without port numbers
621 *
622 * @param $host
623 * @return array
624 */
625 public static function getHostSanitized($host)
626 {
627 if (!class_exists("Matomo\\Network\\IPUtils")) {
628 throw new Exception("Matomo\\Network\\IPUtils could not be found, maybe you are using Matomo from git and need to update Composer. $ php composer.phar update");
629 }
630 return IPUtils::sanitizeIp($host);
631 }
632
633 protected static function getHostsFromConfig($domain, $key)
634 {
635 $config = @Config::getInstance()->$domain;
636
637 if (!isset($config[$key])) {
638 return array();
639 }
640
641 $hosts = $config[$key];
642 if (!is_array($hosts)) {
643 return array();
644 }
645 return $hosts;
646 }
647
648 /**
649 * Returns the host part of any valid URL.
650 *
651 * @param string $url Any fully qualified URL
652 * @return string|null The actual host in lower case or null if $url is not a valid fully qualified URL.
653 */
654 public static function getHostFromUrl($url)
655 {
656 $parsedUrl = parse_url($url);
657
658 if (empty($parsedUrl['host'])) {
659 return;
660 }
661
662 return Common::mb_strtolower($parsedUrl['host']);
663 }
664
665 /**
666 * Checks whether any of the given URLs has the given host. If not, we will also check whether any URL uses a
667 * subdomain of the given host. For instance if host is "example.com" and a URL is "http://www.example.com" we
668 * consider this as valid and return true. The always trusted hosts such as "127.0.0.1" are considered valid as well.
669 *
670 * @param $host
671 * @param $urls
672 * @return bool
673 */
674 public static function isHostInUrls($host, $urls)
675 {
676 if (empty($host)) {
677 return false;
678 }
679
680 $host = Common::mb_strtolower($host);
681
682 if (!empty($urls)) {
683 foreach ($urls as $url) {
684 if (Common::mb_strtolower($url) === $host) {
685 return true;
686 }
687
688 $siteHost = self::getHostFromUrl($url);
689
690 if ($siteHost === $host) {
691 return true;
692 }
693
694 if (Common::stringEndsWith($siteHost, '.' . $host)) {
695 // allow subdomains
696 return true;
697 }
698 }
699 }
700
701 return in_array($host, self::getAlwaysTrustedHosts());
702 }
703
704 /**
705 * List of hosts that are never checked for validity.
706 *
707 * @return array
708 */
709 private static function getAlwaysTrustedHosts()
710 {
711 return self::getLocalHostnames();
712 }
713
714 /**
715 * @return array
716 */
717 public static function getLocalHostnames()
718 {
719 return array('localhost', '127.0.0.1', '::1', '[::1]');
720 }
721
722 /**
723 * @return bool
724 */
725 public static function isSecureConnectionAssumedByPiwikButNotForcedYet()
726 {
727 $isSecureConnectionLikelyNotUsed = Url::isSecureConnectionLikelyNotUsed();
728 $hasSessionCookieSecureFlag = ProxyHttp::isHttps();
729 $isSecureConnectionAssumedByPiwikButNotForcedYet = Url::isPiwikConfiguredToAssumeSecureConnection() && !SettingsPiwik::isHttpsForced();
730
731 return $isSecureConnectionLikelyNotUsed
732 && $hasSessionCookieSecureFlag
733 && $isSecureConnectionAssumedByPiwikButNotForcedYet;
734 }
735
736 /**
737 * @return string
738 */
739 protected static function getCurrentSchemeFromRequestHeader()
740 {
741 if (isset($_SERVER['HTTP_X_FORWARDED_SCHEME']) && strtolower($_SERVER['HTTP_X_FORWARDED_SCHEME']) === 'https') {
742 return 'https';
743 }
744
745 if (isset($_SERVER['HTTP_X_URL_SCHEME']) && strtolower($_SERVER['HTTP_X_URL_SCHEME']) === 'https') {
746 return 'https';
747 }
748
749 if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'http') {
750 return 'http';
751 }
752
753 if ((isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS'] == 'on' || $_SERVER['HTTPS'] === true))
754 || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')
755 ) {
756
757 return 'https';
758 }
759 return 'http';
760 }
761
762 protected static function isSecureConnectionLikelyNotUsed()
763 {
764 return Url::getCurrentSchemeFromRequestHeader() == 'http';
765 }
766
767 /**
768 * @return bool
769 */
770 protected static function isPiwikConfiguredToAssumeSecureConnection()
771 {
772 $assume_secure_protocol = @Config::getInstance()->General['assume_secure_protocol'];
773 return (bool) $assume_secure_protocol;
774 }
775
776 public static function getHostFromServerNameVar()
777 {
778 $host = @$_SERVER['SERVER_NAME'];
779 if (!empty($host)) {
780 if (strpos($host, ':') === false
781 && !empty($_SERVER['SERVER_PORT'])
782 && $_SERVER['SERVER_PORT'] != 80
783 && $_SERVER['SERVER_PORT'] != 443
784 ) {
785 $host .= ':' . $_SERVER['SERVER_PORT'];
786 }
787 }
788 return $host;
789 }
790 }
791