. */ /** * A simple API to handle and reconstruct URLs in Maarch applications * * This file provides a static class with two goals: * - give access to parts of the url the user used to access the application * - reconstructs some meaningful urls to be used in the application * * Example: * * '80' * Url::host(); //-> 'example.com' * Url::proto(); //-> 'http' * Url::coreurl(); //-> 'http://example.com/entreprise/' * * * // If the user calls the URL * // https://example.com:8043/apps/maarch_entreprise/index.php * * * Url::port(); //-> '8043' * Url::host(); //-> 'example.com' * Url::proto(); //-> 'https' * Url::coreurl(); //-> 'https://example.com:8043/' * * * * the class Url is compatible with reverse proxies * * Given the reverse proxy provides the necessary information about the original * request, {@link Url} is able to detect that the application is running * behind a reverse proxy and looks for special HTTP headers in order to * reconstruct URLs that are accessible by a user (i.e. external URLS). * * {@link Url} looks for the following headers * (they must be set by the reverse proxy) : * - X-Forwarded-Host: The original host of the request (i.e. the host of the * proxy server) * - X-Forwarded-Proto: The original protocol of the request (i.e. the protocol * of the proxy server) * - X-Forwarded-Port: The original port of the request (i.e. the port of the * proxy server) * - X-Forwarded-Script-Name: The original value of the Script Name variable * * Example: * - the public url is: * https://example.com:8043/apps/maarch_entreprise/index.php * - it redirects to: * http://internal/subdir/entreprise/apps/maarch_entreprise/index.php * * Following headers must be set in the reverse proxy before it forwards the * request: * - X-Forwarded-Host: example.com * - X-Forwarded-Proto: https * - X-Forwarded-Port: 8043 * - X-Forwarded-Script-Name: /apps/maarch_entreprise/index.php * * Then, the {@link Url} class will return the corrects values: * * 'https://example.com:8043/' * * * If the reverse proxy did not set the necessary headers, it would have return: * * 'http://internal/subdir/entreprise/' -- It is an local * //only URL, the external user cannot access it. * * * @package Core * @author Bruno Carlin * */ /** * Url allows one to get necessary elements to use full urls. * * It is a static class, which means it does not have to be instantiated to be * used. In fact, its constructor has been disabled and tentative to instantiate * it will throw a Fatal error. * * Example of use: * * 'example.com' * Url::coreuri(); //-> 'http://example.com/entreprise/'; * * * * For performance reasons, it has an internal cache, which means that url * components will only be computed once. The cost of calling any method of * this class is the cost of an associative array lookup. * In terms of performance, and after the first call, calling * Url::host() is roughly equivalent to something like * $url['host']. * * @author Bruno Carlin * */ class Url { private static $_cache = array(); // @codeCoverageIgnoreStart private function __construct() {} // @codeCoverageIgnoreEnd /** * Cleans the internal cache of Url * * To use with caution. It allows you to clean the internal cache of this * class. */ public static function forget() { self::$_cache = array(); } private static function _buildScriptName() { return array_key_exists('HTTP_X_FORWARDED_SCRIPT_NAME', $_SERVER) ? $_SERVER['HTTP_X_FORWARDED_SCRIPT_NAME'] : $_SERVER['SCRIPT_NAME']; } private static function _buildRequestUri() { if ($_SERVER["QUERY_STRING"] !== "") { return self::scriptName() . "?" . $_SERVER["QUERY_STRING"]; } else { return self::scriptName(); } } private static function _buildBaseUri() { $baseUri = array_key_exists('HTTP_X_FORWARDED_SCRIPT_NAME', $_SERVER) ? $_SERVER['HTTP_X_FORWARDED_SCRIPT_NAME'] : $_SERVER['SCRIPT_NAME']; $baseUri = trim(dirname($baseUri), '/'); if (($appsPos = strpos($baseUri, 'apps')) !== false) { $baseUri = substr($baseUri, 0, max($appsPos - 1, 0)); } return '/'.$baseUri; } private static function _buildHost() { if (array_key_exists('HTTP_X_FORWARDED_HOST', $_SERVER)) { return $_SERVER['HTTP_X_FORWARDED_HOST']; } else { $hostParts = explode(':',$_SERVER['HTTP_HOST']); return $hostParts[0]; } } private static function _buildPort() { if(array_key_exists('HTTP_X_FORWARDED_PORT', $_SERVER)) { return $_SERVER['HTTP_X_FORWARDED_PORT']; } else if (array_key_exists('HTTP_X_FORWARDED_PROTO', $_SERVER)) { if ($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') {return '443';} else {return '80';} } else { return $_SERVER['SERVER_PORT']; } } private static function _buildProto() { if (array_key_exists('HTTP_X_FORWARDED_PROTO', $_SERVER)) { return $_SERVER['HTTP_X_FORWARDED_PROTO']; } return (array_key_exists('HTTPS', $_SERVER) && $_SERVER['HTTPS'] == 'on') ? 'https' : 'http'; } private static function _buildCoreUrl() { $tmp = self::proto() . '://'; $tmp .= self::host(); if (self::proto() === 'http') { $tmp .= (self::port() == '80') ? '' : ':' . self::port(); } else { $tmp .= (self::port() == '443') ? '' : ':' . self::port(); } $tmp .= self::baseUri(); $tmp .= (strrpos(self::baseUri(), '/') == strlen(self::baseUri()) - 1) ? '' : '/'; return $tmp; } /** * Returns the coreurl of a Maarch application. * * The core url is the base URL for the application ; i.e. the URL to access * the folder where the application is located. * * Example: * * 'http://example.com/entreprise/' * * * @return String The coreurl */ public static function coreurl() { if (!array_key_exists('coreurl', self::$_cache)) { self::$_cache['coreurl'] = self::_buildCoreUrl(); } return self::$_cache['coreurl']; } /** * Returns the SCRIPT_NAME of the current request. * * The SCRIPT_NAME Server vairble is the URI entered by the user to access * a page of theapplication, excluding the query string. * * It is particularly useful to abstract the current url and not test * whether the application is running behind a proxy or not. * * Example: * * '/entreprise/apps/maarch_entreprise/index.php' * * * @return String The SCRIPT_NAME value */ public static function scriptName() { if (!array_key_exists('scriptName', self::$_cache)) { self::$_cache['scriptName'] = self::_buildScriptName(); } return self::$_cache['scriptName']; } /** * Returns the request uri of the current request. * * The request URI is the path entered by the user to access a page of the * application, including the query string. * * It is particularly useful to abstract the current url and not test * whether the application is running behind a proxy or not. * * Example: * * '/entreprise/apps/maarch_entreprise/index.php?args' * * * @return String The request URI */ public static function requestUri() { if (!array_key_exists('requestUri', self::$_cache)) { self::$_cache['requestUri'] = self::_buildRequestUri(); } return self::$_cache['requestUri']; } /** * Returns the protocol to used to access a Maarch Application. * * It can only have two values : "http" or "https". * * Example: * * 'http' * * @return String The protocol used ("http" or "https") */ public static function proto() { if (!array_key_exists('proto', self::$_cache)) { self::$_cache['proto'] = self::_buildProto(); } return self::$_cache['proto']; } /** * Returns the host used to access a Maarch Application. * * This sends back the "Host" header of the HTTP request called by the user. * * Example: * * 'example.com' * * * @return String The host */ public static function host() { if (!array_key_exists('host', self::$_cache)) { self::$_cache['host'] = self::_buildHost(); } return self::$_cache['host']; } /** * Returns the port of the server used to access a Maarch Application. * * Example: * * '80' * * * @return String The port */ public static function port() { if (!array_key_exists('port', self::$_cache)) { self::$_cache['port'] = self::_buildPort(); } return self::$_cache['port']; } /** * Returns the base URI of a Maarch Application. * * The base URI is the path of URL for the root folder of a Maarch * Application. * * Example: * * '/subdir/entreprise' * * * @return String The base URI of the application */ public static function baseUri() { if (!array_key_exists('baseUri', self::$_cache)) { self::$_cache['baseUri'] = self::_buildBaseUri(); } return self::$_cache['baseUri']; } }