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