PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 4.3.0
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v4.3.0
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 SupportedBrowser.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
798 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::getHostFromServerVariable();
212 if (empty($host)) {
213 // if no current host, assume valid
214 return true;
215 }
216 }
217
218 // if host is in hardcoded allowlist, assume it's valid
219 if (in_array($host, self::getAlwaysTrustedHosts())) {
220 return true;
221 }
222
223 $trustedHosts = self::getTrustedHosts();
224
225 // Only punctuation we allow is '[', ']', ':', '.', '_' and '-'
226 $hostLength = strlen($host);
227 if ($hostLength !== strcspn($host, '`~!@#$%^&*()+={}\\|;"\'<>,?/ ')) {
228 return false;
229 }
230
231 // if no trusted hosts, just assume it's valid
232 if (empty($trustedHosts)) {
233 self::saveTrustedHostnameInConfig($host);
234 return true;
235 }
236
237 // Escape trusted hosts for preg_match call below
238 foreach ($trustedHosts as &$trustedHost) {
239 $trustedHost = preg_quote($trustedHost);
240 }
241 $trustedHosts = str_replace("/", "\\/", $trustedHosts);
242
243 $untrustedHost = Common::mb_strtolower($host);
244 $untrustedHost = rtrim($untrustedHost, '.');
245
246 $hostRegex = Common::mb_strtolower('/(^|.)' . implode('$|', $trustedHosts) . '$/');
247
248 $result = preg_match($hostRegex, $untrustedHost);
249 return 0 !== $result;
250 }
251
252 /**
253 * Records one host, or an array of hosts in the config file,
254 * if user is Super User
255 *
256 * @static
257 * @param $host string|array
258 * @return bool
259 */
260 public static function saveTrustedHostnameInConfig($host)
261 {
262 return self::saveHostsnameInConfig($host, 'General', 'trusted_hosts');
263 }
264
265 public static function saveCORSHostnameInConfig($host)
266 {
267 return self::saveHostsnameInConfig($host, 'General', 'cors_domains');
268 }
269
270 protected static function saveHostsnameInConfig($host, $domain, $key)
271 {
272 if (Piwik::hasUserSuperUserAccess()
273 && file_exists(Config::getLocalConfigPath())
274 ) {
275 $config = Config::getInstance()->$domain;
276 if (!is_array($host)) {
277 $host = array($host);
278 }
279 $host = array_filter($host);
280 if (empty($host)) {
281 return false;
282 }
283 $config[$key] = $host;
284 Config::getInstance()->$domain = $config;
285 Config::getInstance()->forceSave();
286 return true;
287 }
288 return false;
289 }
290
291 /**
292 * Returns the current host.
293 *
294 * @param bool $checkIfTrusted Whether to do trusted host check. Should ALWAYS be true,
295 * except in Controller.
296 * @return string|bool eg, `"demo.piwik.org"` or false if no host found.
297 */
298 public static function getHost($checkIfTrusted = true)
299 {
300 $host = self::getHostFromServerVariable();
301
302 if (strlen($host) && (!$checkIfTrusted || self::isValidHost($host))) {
303 return $host;
304 }
305
306 // HTTP/1.0 request doesn't include Host: header
307 if (isset($_SERVER['SERVER_ADDR'])) {
308 return $_SERVER['SERVER_ADDR'];
309 }
310
311 return false;
312 }
313
314 protected static function getHostFromServerVariable()
315 {
316 try {
317 // this fails when trying to get the hostname before the config was initialized
318 // e.g. for loading the domain specific configuration file
319 // in such a case we always use HTTP_HOST
320 $preferServerName = Config::getInstance()->General['host_validation_use_server_name'];
321 } catch (\Exception $e) {
322 $preferServerName = false;
323 }
324
325 if ($preferServerName && strlen($host = self::getHostFromServerNameVar())) {
326 return $host;
327 } elseif (isset($_SERVER['HTTP_HOST']) && strlen($host = $_SERVER['HTTP_HOST'])) {
328 return $host;
329 }
330
331 return false;
332 }
333
334 /**
335 * Sets the host. Useful for CLI scripts, eg. core:archive command
336 *
337 * @param $host string
338 */
339 public static function setHost($host)
340 {
341 $_SERVER['SERVER_NAME'] = $host;
342 $_SERVER['HTTP_HOST'] = $host;
343 unset($_SERVER['SERVER_PORT']);
344 }
345
346 /**
347 * Returns the current host.
348 *
349 * @param string $default Default value to return if host unknown
350 * @param bool $checkTrustedHost Whether to do trusted host check. Should ALWAYS be true,
351 * except in Controller.
352 * @return string eg, `"example.org"` if the current URL is
353 * `"http://example.org/dir1/dir2/index.php?param1=value1&param2=value2"`
354 * @api
355 */
356 public static function getCurrentHost($default = 'unknown', $checkTrustedHost = true)
357 {
358 $hostHeaders = array();
359
360 $config = Config::getInstance()->General;
361 if (isset($config['proxy_host_headers'])) {
362 $hostHeaders = $config['proxy_host_headers'];
363 }
364
365 if (!is_array($hostHeaders)) {
366 $hostHeaders = array();
367 }
368
369 $host = self::getHost($checkTrustedHost);
370 $default = Common::sanitizeInputValue($host ? $host : $default);
371
372 return IP::getNonProxyIpFromHeader($default, $hostHeaders);
373 }
374
375 /**
376 * Returns the query string of the current URL.
377 *
378 * @return string eg, `"?param1=value1&param2=value2"` if the current URL is
379 * `"http://example.org/dir1/dir2/index.php?param1=value1&param2=value2"`
380 * @api
381 */
382 public static function getCurrentQueryString()
383 {
384 $url = '';
385 if (isset($_SERVER['QUERY_STRING'])
386 && !empty($_SERVER['QUERY_STRING'])
387 ) {
388 $url .= "?" . $_SERVER['QUERY_STRING'];
389 }
390 return $url;
391 }
392
393 /**
394 * Returns an array mapping query parameter names with query parameter values for
395 * the current URL.
396 *
397 * @return array If current URL is `"http://example.org/dir1/dir2/index.php?param1=value1&param2=value2"`
398 * this will return:
399 *
400 * array(
401 * 'param1' => string 'value1',
402 * 'param2' => string 'value2'
403 * )
404 * @api
405 */
406 public static function getArrayFromCurrentQueryString()
407 {
408 $queryString = self::getCurrentQueryString();
409 $urlValues = UrlHelper::getArrayFromQueryString($queryString);
410 return $urlValues;
411 }
412
413 /**
414 * Modifies the current query string with the supplied parameters and returns
415 * the result. Parameters in the current URL will be overwritten with values
416 * in `$params` and parameters absent from the current URL but present in `$params`
417 * will be added to the result.
418 *
419 * @param array $params set of parameters to modify/add in the current URL
420 * eg, `array('param3' => 'value3')`
421 * @return string eg, `"?param2=value2&param3=value3"`
422 * @api
423 */
424 public static function getCurrentQueryStringWithParametersModified($params)
425 {
426 $urlValues = self::getArrayFromCurrentQueryString();
427 foreach ($params as $key => $value) {
428 $urlValues[$key] = $value;
429 }
430 $query = self::getQueryStringFromParameters($urlValues);
431 if (strlen($query) > 0) {
432 return '?' . $query;
433 }
434 return '';
435 }
436
437 /**
438 * Converts an array of parameters name => value mappings to a query
439 * string. Values must already be URL encoded before you call this function.
440 *
441 * @param array $parameters eg. `array('param1' => 10, 'param2' => array(1,2))`
442 * @return string eg. `"param1=10&param2[]=1&param2[]=2"`
443 * @api
444 */
445 public static function getQueryStringFromParameters($parameters)
446 {
447 $query = '';
448 foreach ($parameters as $name => $value) {
449 if (is_null($value) || $value === false) {
450 continue;
451 }
452 if (is_array($value)) {
453 foreach ($value as $theValue) {
454 $query .= $name . "[]=" . $theValue . "&";
455 }
456 } else {
457 $query .= $name . "=" . $value . "&";
458 }
459 }
460 $query = substr($query, 0, -1);
461 return $query;
462 }
463
464 public static function getQueryStringFromUrl($url)
465 {
466 return parse_url($url, PHP_URL_QUERY);
467 }
468
469 /**
470 * Redirects the user to the referrer. If no referrer exists, the user is redirected
471 * to the current URL without query string.
472 *
473 * @api
474 */
475 public static function redirectToReferrer()
476 {
477 $referrer = self::getReferrer();
478 if ($referrer !== false) {
479 self::redirectToUrl($referrer);
480 }
481 self::redirectToUrl(self::getCurrentUrlWithoutQueryString());
482 }
483
484 private static function redirectToUrlNoExit($url)
485 {
486 if (UrlHelper::isLookLikeUrl($url)
487 || strpos($url, 'index.php') === 0
488 ) {
489 Common::sendResponseCode(302);
490 Common::sendHeader("X-Robots-Tag: noindex");
491 Common::sendHeader("Location: $url");
492 } else {
493 echo "Invalid URL to redirect to.";
494 }
495
496 if (Common::isPhpCliMode()) {
497 throw new Exception("If you were using a browser, Matomo would redirect you to this URL: $url \n\n");
498 }
499 }
500
501 /**
502 * Redirects the user to the specified URL.
503 *
504 * @param string $url
505 * @throws Exception
506 * @api
507 */
508 public static function redirectToUrl($url)
509 {
510 // Close the session manually.
511 // We should not have to call this because it was registered via register_shutdown_function,
512 // but it is not always called fast enough
513 Session::close();
514
515 self::redirectToUrlNoExit($url);
516
517 exit;
518 }
519
520 /**
521 * If the page is using HTTP, redirect to the same page over HTTPS
522 */
523 public static function redirectToHttps()
524 {
525 if (ProxyHttp::isHttps()) {
526 return;
527 }
528 $url = self::getCurrentUrl();
529 $url = str_replace("http://", "https://", $url);
530 self::redirectToUrl($url);
531 }
532
533 /**
534 * Returns the **HTTP_REFERER** `$_SERVER` variable, or `false` if not found.
535 *
536 * @return string|false
537 * @api
538 */
539 public static function getReferrer()
540 {
541 if (!empty($_SERVER['HTTP_REFERER'])) {
542 return $_SERVER['HTTP_REFERER'];
543 }
544 return false;
545 }
546
547 /**
548 * Returns `true` if the URL points to something on the same host, `false` if otherwise.
549 *
550 * @param string $url
551 * @return bool True if local; false otherwise.
552 * @api
553 */
554 public static function isLocalUrl($url)
555 {
556 if (empty($url)) {
557 return true;
558 }
559
560 // handle host name mangling
561 $requestUri = isset($_SERVER['SCRIPT_URI']) ? $_SERVER['SCRIPT_URI'] : '';
562 $parseRequest = @parse_url($requestUri);
563 $hosts = array(self::getHost(), self::getCurrentHost());
564 if (!empty($parseRequest['host'])) {
565 $hosts[] = $parseRequest['host'];
566 }
567
568 // drop port numbers from hostnames and IP addresses
569 $hosts = array_map(array('self', 'getHostSanitized'), $hosts);
570
571 $disableHostCheck = Config::getInstance()->General['enable_trusted_host_check'] == 0;
572 // compare scheme and host
573 $parsedUrl = @parse_url($url);
574 $host = IPUtils::sanitizeIp(@$parsedUrl['host']);
575 return !empty($host)
576 && ($disableHostCheck || in_array($host, $hosts))
577 && !empty($parsedUrl['scheme'])
578 && in_array($parsedUrl['scheme'], array('http', 'https'));
579 }
580
581 /**
582 * Checks whether the given host is a local host like `127.0.0.1` or `localhost`.
583 *
584 * @param string $host
585 * @return bool
586 */
587 public static function isLocalHost($host)
588 {
589 if (empty($host)) {
590 return false;
591 }
592
593 // remove port
594 $hostWithoutPort = explode(':', $host);
595 array_pop($hostWithoutPort);
596 $hostWithoutPort = implode(':', $hostWithoutPort);
597
598 $localHostnames = Url::getLocalHostnames();
599 return in_array($host, $localHostnames, true)
600 || in_array($hostWithoutPort, $localHostnames, true);
601 }
602
603 public static function getTrustedHostsFromConfig()
604 {
605 $hosts = self::getHostsFromConfig('General', 'trusted_hosts');
606
607 // Case user wrote in the config, http://example.com/test instead of example.com
608 foreach ($hosts as &$host) {
609 if (UrlHelper::isLookLikeUrl($host)) {
610 $host = parse_url($host, PHP_URL_HOST);
611 }
612 }
613 return $hosts;
614 }
615
616 public static function getTrustedHosts()
617 {
618 return self::getTrustedHostsFromConfig();
619 }
620
621 public static function getCorsHostsFromConfig()
622 {
623 return self::getHostsFromConfig('General', 'cors_domains');
624 }
625
626 /**
627 * Returns hostname, without port numbers
628 *
629 * @param $host
630 * @return array
631 */
632 public static function getHostSanitized($host)
633 {
634 if (!class_exists("Matomo\\Network\\IPUtils")) {
635 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");
636 }
637 return IPUtils::sanitizeIp($host);
638 }
639
640 protected static function getHostsFromConfig($domain, $key)
641 {
642 $config = @Config::getInstance()->$domain;
643
644 if (!isset($config[$key])) {
645 return array();
646 }
647
648 $hosts = $config[$key];
649 if (!is_array($hosts)) {
650 return array();
651 }
652 return $hosts;
653 }
654
655 /**
656 * Returns the host part of any valid URL.
657 *
658 * @param string $url Any fully qualified URL
659 * @return string|null The actual host in lower case or null if $url is not a valid fully qualified URL.
660 */
661 public static function getHostFromUrl($url)
662 {
663 $parsedUrl = parse_url($url);
664
665 if (empty($parsedUrl['host'])) {
666 return;
667 }
668
669 return Common::mb_strtolower($parsedUrl['host']);
670 }
671
672 /**
673 * Checks whether any of the given URLs has the given host. If not, we will also check whether any URL uses a
674 * subdomain of the given host. For instance if host is "example.com" and a URL is "http://www.example.com" we
675 * consider this as valid and return true. The always trusted hosts such as "127.0.0.1" are considered valid as well.
676 *
677 * @param $host
678 * @param $urls
679 * @return bool
680 */
681 public static function isHostInUrls($host, $urls)
682 {
683 if (empty($host)) {
684 return false;
685 }
686
687 $host = Common::mb_strtolower($host);
688
689 if (!empty($urls)) {
690 foreach ($urls as $url) {
691 if (Common::mb_strtolower($url) === $host) {
692 return true;
693 }
694
695 $siteHost = self::getHostFromUrl($url);
696
697 if ($siteHost === $host) {
698 return true;
699 }
700
701 if (Common::stringEndsWith($siteHost, '.' . $host)) {
702 // allow subdomains
703 return true;
704 }
705 }
706 }
707
708 return in_array($host, self::getAlwaysTrustedHosts());
709 }
710
711 /**
712 * List of hosts that are never checked for validity.
713 *
714 * @return array
715 */
716 private static function getAlwaysTrustedHosts()
717 {
718 return self::getLocalHostnames();
719 }
720
721 /**
722 * @return array
723 */
724 public static function getLocalHostnames()
725 {
726 return array('localhost', '127.0.0.1', '::1', '[::1]');
727 }
728
729 /**
730 * @return bool
731 */
732 public static function isSecureConnectionAssumedByPiwikButNotForcedYet()
733 {
734 $isSecureConnectionLikelyNotUsed = Url::isSecureConnectionLikelyNotUsed();
735 $hasSessionCookieSecureFlag = ProxyHttp::isHttps();
736 $isSecureConnectionAssumedByPiwikButNotForcedYet = Url::isPiwikConfiguredToAssumeSecureConnection() && !SettingsPiwik::isHttpsForced();
737
738 return $isSecureConnectionLikelyNotUsed
739 && $hasSessionCookieSecureFlag
740 && $isSecureConnectionAssumedByPiwikButNotForcedYet;
741 }
742
743 /**
744 * @return string
745 */
746 protected static function getCurrentSchemeFromRequestHeader()
747 {
748 if (isset($_SERVER['HTTP_X_FORWARDED_SCHEME']) && strtolower($_SERVER['HTTP_X_FORWARDED_SCHEME']) === 'https') {
749 return 'https';
750 }
751
752 if (isset($_SERVER['HTTP_X_URL_SCHEME']) && strtolower($_SERVER['HTTP_X_URL_SCHEME']) === 'https') {
753 return 'https';
754 }
755
756 if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'http') {
757 return 'http';
758 }
759
760 if ((isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS'] == 'on' || $_SERVER['HTTPS'] === true))
761 || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')
762 ) {
763
764 return 'https';
765 }
766 return 'http';
767 }
768
769 protected static function isSecureConnectionLikelyNotUsed()
770 {
771 return Url::getCurrentSchemeFromRequestHeader() == 'http';
772 }
773
774 /**
775 * @return bool
776 */
777 protected static function isPiwikConfiguredToAssumeSecureConnection()
778 {
779 $assume_secure_protocol = @Config::getInstance()->General['assume_secure_protocol'];
780 return (bool) $assume_secure_protocol;
781 }
782
783 public static function getHostFromServerNameVar()
784 {
785 $host = @$_SERVER['SERVER_NAME'];
786 if (!empty($host)) {
787 if (strpos($host, ':') === false
788 && !empty($_SERVER['SERVER_PORT'])
789 && $_SERVER['SERVER_PORT'] != 80
790 && $_SERVER['SERVER_PORT'] != 443
791 ) {
792 $host .= ':' . $_SERVER['SERVER_PORT'];
793 }
794 }
795 return $host;
796 }
797 }
798