32        $session_id = 
$session->getSessionId();
 
   33        if (is_null($session_id)) {
 
   35            throw new \SimpleSAML_Error_Exception(
'Cannot save POST data to a transient session.');
 
   42        return preg_replace(
'#^https:#', 
'http:', 
$url);
 
   56        if (array_key_exists(
'HTTP_HOST', 
$_SERVER)) {
 
   58        } elseif (array_key_exists(
'SERVER_NAME', 
$_SERVER)) {
 
   66            $decomposed = explode(
":", 
$current);
 
   67            $port = array_pop($decomposed);
 
   68            if (!is_numeric($port)) {
 
   69                array_push($decomposed, $port);
 
   71            $current = implode(
":", $decomposed);
 
   86        if (!array_key_exists(
'HTTPS', 
$_SERVER)) {
 
  112        $port = isset(
$_SERVER[
'SERVER_PORT']) ? 
$_SERVER[
'SERVER_PORT'] : $default_port;
 
  115        $port = strval($port);
 
  117        if ($port !== $default_port) {
 
  149        if (!is_string(
$url) || empty(
$url) || !is_array($parameters)) {
 
  150            throw new \InvalidArgumentException(
'Invalid input parameters.');
 
  152        if (!empty($parameters)) {
 
  153            $url = self::addURLParameters(
$url, $parameters);
 
  160        if (
$_SERVER[
'SERVER_PROTOCOL'] === 
'HTTP/1.1' &&
 
  161            $_SERVER[
'REQUEST_METHOD'] === 
'POST' 
  168        if (strlen(
$url) > 2048) {
 
  172        if (!headers_sent()) {
 
  177            header(
'Pragma: no-cache');
 
  178            header(
'Cache-Control: no-cache, no-store, must-revalidate');
 
  182        echo 
'<?xml version="1.0" encoding="UTF-8"?>'.
"\n";
 
  183        echo 
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"';
 
  184        echo 
' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'.
"\n";
 
  185        echo 
'<html xmlns="http://www.w3.org/1999/xhtml">'.
"\n";
 
  187        echo 
'    <meta http-equiv="content-type" content="text/html; charset=utf-8">'.
"\n";
 
  188        echo 
'    <meta http-equiv="refresh" content="0;URL=\''.htmlspecialchars(
$url).
'\'">'."\n
"; 
  189        echo "    <title>Redirect</title>\n
"; 
  192        echo "    <h1>Redirect</h1>\n
"; 
  193        echo '      <p>You were redirected to: <a id="redirlink
" href="'.htmlspecialchars($url).'">'; 
  194        echo htmlspecialchars($url)."</a>\n
"; 
  195        echo '        <script type="text/javascript
">document.getElementById("redirlink
").focus();</script>'."\n
"; 
  200        // end script execution 
  217    private static function savePOSTData(\SimpleSAML_Session $session, $destination, $data) 
  219        // generate a random ID to avoid replay attacks 
  220        $id = Random::generateID(); 
  223            'url'  => $destination, 
  226        // save the post data to the session, tied to the random ID 
  227        $session->setData('core_postdatalink', $id, $postData); 
  246    public static function addURLParameters($url, $parameters) 
  248        if (!is_string($url) || !is_array($parameters)) { 
  249            throw new \InvalidArgumentException('Invalid input parameters.'); 
  252        $queryStart = strpos($url, '?'); 
  253        if ($queryStart === false) { 
  258            $oldQuery = substr($url, $queryStart + 1); 
  259            if ($oldQuery === false) { 
  262                $oldQuery = self::parseQueryString($oldQuery); 
  264            $url = substr($url, 0, $queryStart + 1); 
  268        $query = array_merge($oldQuery, $parameters); 
  269        $url .= http_build_query($query, '', '&'); 
  286    public static function checkSessionCookie($retryURL = null) 
  288        if (!is_null($retryURL) && !is_string($retryURL)) { 
  289            throw new \InvalidArgumentException('Invalid input parameters.'); 
  292        $session = \SimpleSAML_Session::getSessionFromRequest(); 
  293        if ($session->hasSessionCookie()) { 
  297        // we didn't have a session cookie. Redirect to the no-cookie page 
  299        $url = Module::getModuleURL('core/no_cookie.php'); 
  300        if ($retryURL !== null) { 
  301            $url = self::addURLParameters($url, array('retryURL' => $retryURL)); 
  303        self::redirectTrustedURL($url); 
  321    public static function checkURLAllowed($url, array $trustedSites = null) 
  326        $url = self::normalizeURL($url); 
  328        if (filter_var($url, FILTER_VALIDATE_URL) === false) { 
  329            throw new \SimpleSAML_Error_Exception('Invalid URL: '.$url); 
  332        // get the white list of domains 
  333        if ($trustedSites === null) { 
  334            $trustedSites = \SimpleSAML_Configuration::getInstance()->getValue('trusted.url.domains', array()); 
  337        // validates the URL's host is among those allowed 
  338        if (is_array($trustedSites)) { 
  339            assert(is_array($trustedSites)); 
  340            $components = parse_url($url); 
  341            $hostname = $components['host']; 
  343            // check for userinfo 
  344            if ((isset($components['user']) && strpos($components['user'], '\\') !== false) || 
  345                (isset($components['pass']) && strpos($components['pass'], '\\') !== false) 
  347                throw new \SimpleSAML_Error_Exception('Invalid URL: '.$url); 
  350            // allow URLs with standard ports specified (non-standard ports must then be allowed explicitly) 
  351            if (isset($components['port']) && 
  352                (($components['scheme'] === 'http' && $components['port'] !== 80) || 
  353                 ($components['scheme'] === 'https' && $components['port'] !== 443)) 
  355                $hostname = $hostname.':'.$components['port']; 
  358            $self_host = self::getSelfHostWithNonStandardPort(); 
  360            $trustedRegex = \SimpleSAML_Configuration::getInstance()->getValue('trusted.url.regex', false); 
  364                // add self host to the white list 
  365                $trustedSites[] = preg_quote($self_host); 
  366                foreach ($trustedSites as $regex) { 
  367                    // Add start and end delimiters. 
  368                    $regex = "@^{$regex}$
@"; 
  369                    if (preg_match($regex, $hostname)) { 
  375                // add self host to the white list 
  376                $trustedSites[] = $self_host; 
  377                $trusted = in_array($hostname, $trustedSites, true); 
  380            // throw exception due to redirection to untrusted site 
  382                throw new \SimpleSAML_Error_Exception('URL not allowed: '.$url); 
  408    public static function fetch($url, $context = array(), $getHeaders = false) 
  410        if (!is_string($url)) { 
  411            throw new \InvalidArgumentException('Invalid input parameters.'); 
  414        $config = \SimpleSAML_Configuration::getInstance(); 
  416        $proxy = $config->getString('proxy', null); 
  417        if ($proxy !== null) { 
  418            if (!isset($context['http']['proxy'])) { 
  419                $context['http']['proxy'] = $proxy; 
  421            $proxy_auth = $config->getString('proxy.auth', false); 
  422            if ($proxy_auth !== false) { 
  423                $context['http']['header'] = "Proxy-Authorization: Basic 
".base64_encode($proxy_auth); 
  425            if (!isset($context['http']['request_fulluri'])) { 
  426                $context['http']['request_fulluri'] = true; 
  429             * If the remote endpoint over HTTPS uses the SNI extension (Server Name Indication RFC 4366), the proxy 
  430             * could introduce a mismatch between the names in the Host: HTTP header and the SNI_server_name in TLS 
  431             * negotiation (thanks to Cristiano Valli @ GARR-IDEM to have pointed this problem). 
  432             * See: https://bugs.php.net/bug.php?id=63519 
  433             * These controls will force the same value for both fields. 
  434             * Marco Ferrante (marco@csita.unige.it), Nov 2012 
  436            if (preg_match('#^https#i', $url) 
  437                && defined('OPENSSL_TLSEXT_SERVER_NAME') 
  438                && OPENSSL_TLSEXT_SERVER_NAME 
  440                // extract the hostname 
  441                $hostname = parse_url($url, PHP_URL_HOST); 
  442                if (!empty($hostname)) { 
  443                    $context['ssl'] = array( 
  444                        'SNI_server_name' => $hostname, 
  445                        'SNI_enabled'     => true, 
  448                    Logger::warning('Invalid URL format or local URL used through a proxy'); 
  453        $context = stream_context_create($context); 
  454        $data = @file_get_contents($url, false, $context); 
  455        if ($data === false) { 
  456            $error = error_get_last(); 
  457            throw new \SimpleSAML_Error_Exception('Error fetching '.var_export($url, true).':'. 
  458                (is_array($error) ? $error['message'] : 'no error available')); 
  463            if (isset($http_response_header)) { 
  465                foreach ($http_response_header as $h) { 
  466                    if (preg_match('@^HTTP/1\.[01]\s+\d{3}\s+@', $h)) { 
  467                        $headers = array(); // reset 
  471                    $bits = explode(':', $h, 2); 
  472                    if (count($bits) === 2) { 
  473                        $headers[strtolower($bits[0])] = trim($bits[1]); 
  477                // no HTTP headers, probably a different protocol, e.g. file 
  480            return array($data, $headers); 
  498    public static function getAcceptLanguage() 
  500        if (!array_key_exists('HTTP_ACCEPT_LANGUAGE', $_SERVER)) { 
  501            // no Accept-Language header, return an empty set 
  505        $languages = explode(',', strtolower($_SERVER['HTTP_ACCEPT_LANGUAGE'])); 
  509        foreach ($languages as $l) { 
  510            $opts = explode(';', $l); 
  512            $l = trim(array_shift($opts)); // the language is the first element 
  516            // iterate over all options, and check for the quality option 
  517            foreach ($opts as $o) { 
  518                $o = explode('=', $o); 
  520                    // skip option with no value 
  525                $value = trim($o[1]); 
  532            // remove the old key to ensure that the element is added to the end 
  535            // set the quality in the result 
  538            if (strpos($l, '-')) { 
  539                // the language includes a region part 
  541                // extract the language without the region 
  542                $l = explode('-', $l); 
  545                // add this language to the result (unless it is defined already) 
  546                if (!array_key_exists($l, $ret)) { 
  562    public static function guessBasePath() 
  564        if (!array_key_exists('REQUEST_URI', $_SERVER) || !array_key_exists('SCRIPT_FILENAME', $_SERVER)) { 
  567        // get the name of the current script 
  568        $path = explode('/', $_SERVER['SCRIPT_FILENAME']); 
  569        $script = array_pop($path); 
  571        // get the portion of the URI up to the script, i.e.: /simplesaml/some/directory/script.php 
  572        if (!preg_match('#^/(?:[^/]+/)*'.$script.'#', $_SERVER['REQUEST_URI'], $matches)) { 
  575        $uri_s = explode('/', $matches[0]); 
  576        $file_s = explode('/', $_SERVER['SCRIPT_FILENAME']); 
  578        // compare both arrays from the end, popping elements matching out of them 
  579        while ($uri_s[count($uri_s) - 1] === $file_s[count($file_s) - 1]) { 
  583        // we are now left with the minimum part of the URI that does not match anything in the file system, use it 
  584        return join('/', $uri_s).'/'; 
  597    public static function getBaseURL() 
  599        $globalConfig = \SimpleSAML_Configuration::getInstance(); 
  600        $baseURL = $globalConfig->getString('baseurlpath', 'simplesaml/'); 
  602        if (preg_match('#^https?://.*/?$#D', $baseURL, $matches)) { 
  603            // full URL in baseurlpath, override local server values 
  604            return rtrim($baseURL, '/').'/'; 
  605        } elseif ((preg_match('#^/?([^/]?.*/)$#D', $baseURL, $matches)) || 
  606            (preg_match('#^\*(.*)/$#D', $baseURL, $matches)) || 
  611            $protocol .= (self::getServerHTTPS()) ? 's' : ''; 
  614            $hostname = self::getServerHost(); 
  615            $port = self::getServerPort(); 
  616            $path = $globalConfig->getBasePath(); 
  618            return $protocol.$hostname.$port.$path; 
  621             * Invalid 'baseurlpath'. We cannot recover from this, so throw a critical exception and try to be graceful 
  622             * with the configuration. Use a guessed base path instead of the one provided. 
  624            $c = $globalConfig->toArray(); 
  625            $c['baseurlpath'] = self::guessBasePath(); 
  626            throw new \SimpleSAML\Error\CriticalConfigurationError( 
  627                'Invalid value for \'baseurlpath\' in config.php. Valid format is in the form: '. 
  628                '[(http|https)://(hostname|fqdn)[:port]]/[path/to/simplesaml/]. It must end with a \'/\'.', 
  645    public static function getFirstPathElement($trailingslash = true) 
  647        if (preg_match('|^/(.*?)/|', $_SERVER['SCRIPT_NAME'], $matches)) { 
  648            return ($trailingslash ? '/' : '').$matches[1]; 
  666    public static function getPOSTRedirectURL($destination, $data) 
  668        if (!is_string($destination) || !is_array($data)) { 
  669            throw new \InvalidArgumentException('Invalid input parameters.'); 
  672        $config = \SimpleSAML_Configuration::getInstance(); 
  673        $allowed = $config->getBoolean('enable.http_post', false); 
  675        if ($allowed && preg_match("#^
http:#
", $destination) && self::isHTTPS()) { 
  676            // we need to post the data to HTTP 
  677            $url = self::getSecurePOSTRedirectURL($destination, $data); 
  678        } else { // post the data directly 
  679            $session = \SimpleSAML_Session::getSessionFromRequest(); 
  680            $id = self::savePOSTData($session, $destination, $data); 
  681            $url = Module::getModuleURL('core/postredirect.php', array('RedirId' => $id)); 
  697    public static function getSelfHost() 
  699        $decomposed = explode(':', self::getSelfHostWithNonStandardPort()); 
  700        return array_shift($decomposed); 
  715    public static function getSelfHostWithNonStandardPort() 
  717        $url = self::getBaseURL(); 
  720        $colon = strpos($url, '://'); 
  722        $length = strcspn($url, '/', $start); 
  724        return substr($url, $start, $length); 
  736    public static function getSelfHostWithPath() 
  738        $baseurl = explode("/
", self::getBaseURL()); 
  739        $elements = array_slice($baseurl, 3 - count($baseurl), count($baseurl) - 4); 
  740        $path = implode("/
", $elements); 
  741        return self::getSelfHostWithNonStandardPort()."/
".$path; 
  760    public static function getSelfURL() 
  762        $cfg = \SimpleSAML_Configuration::getInstance(); 
  763        $baseDir = $cfg->getBaseDir(); 
  764        $cur_path = realpath($_SERVER['SCRIPT_FILENAME']); 
  765        // make sure we got a string from realpath() 
  766        $cur_path = is_string($cur_path) ? $cur_path : ''; 
  767        // find the path to the current script relative to the www/ directory of SimpleSAMLphp 
  768        $rel_path = str_replace($baseDir.'www'.DIRECTORY_SEPARATOR, '', $cur_path); 
  769        // convert that relative path to an HTTP query 
  770        $url_path = str_replace(DIRECTORY_SEPARATOR, '/', $rel_path); 
  771        // find where the relative path starts in the current request URI 
  772        $uri_pos = (!empty($url_path)) ? strpos($_SERVER['REQUEST_URI'], $url_path) : false; 
  774        if ($cur_path == $rel_path || $uri_pos === false) { 
  776             * We were accessed from an external script. This can happen in the following cases: 
  778             * - $_SERVER['SCRIPT_FILENAME'] points to a script that doesn't exist. E.g. functional testing. In this 
  779             *   case, realpath() returns false and str_replace an empty string, so we compare them loosely. 
  781             * - The URI requested does not belong to a script in the www/ directory of SimpleSAMLphp. In that case, 
  782             *   removing SimpleSAMLphp's base dir from the current path yields the same path, so $cur_path and 
  783             *   $rel_path are equal. 
  785             * - The request URI does not match the current script. Even if the current script is located in the www/ 
  786             *   directory of SimpleSAMLphp, the URI does not contain its relative path, and $uri_pos is false. 
  788             * It doesn't matter which one of those cases we have. We just know we can't apply our base URL to the 
  789             * current URI, so we need to build it back from the PHP environment, unless we have a base URL specified 
  790             * for this case in the configuration. First, check if that's the case. 
  794            $appcfg = $cfg->getConfigItem('application', null); 
  795            $appurl = ($appcfg instanceof \SimpleSAML_Configuration) ? $appcfg->getString('baseURL', '') : ''; 
  796            if (!empty($appurl)) { 
  797                $protocol = parse_url($appurl, PHP_URL_SCHEME); 
  798                $hostname = parse_url($appurl, PHP_URL_HOST); 
  799                $port = parse_url($appurl, PHP_URL_PORT); 
  800                $port = !empty($port) ? ':'.$port : ''; 
  801            } else { // no base URL specified for app, just use the current URL 
  803                $protocol .= (self::getServerHTTPS()) ? 's' : ''; 
  804                $hostname = self::getServerHost(); 
  805                $port = self::getServerPort(); 
  807            return $protocol.'://'.$hostname.$port.$_SERVER['REQUEST_URI']; 
  810        return self::getBaseURL().$url_path.substr($_SERVER['REQUEST_URI'], $uri_pos + strlen($url_path)); 
  823    public static function getSelfURLHost() 
  825        $url = self::getSelfURL(); 
  828        $colon = strpos($url, '://'); 
  830        $length = strcspn($url, '/', $start) + $start; 
  831        return substr($url, 0, $length); 
  843    public static function getSelfURLNoQuery() 
  845        $url = self::getSelfURL(); 
  846        $pos = strpos($url, '?'); 
  850        return substr($url, 0, $pos); 
  862    public static function isHTTPS() 
  864        return strpos(self::getSelfURL(), 'https://') === 0; 
  880    public static function normalizeURL($url) 
  882        if (!is_string($url)) { 
  883            throw new \InvalidArgumentException('Invalid input parameters.'); 
  886        $url = self::resolveURL($url, self::getSelfURL()); 
  888        // verify that the URL is to a http or https site 
  889        if (!preg_match('@^https?://@i', $url)) { 
  890            throw new \InvalidArgumentException('Invalid URL: '.$url); 
  912    public static function parseQueryString($query_string) 
  914        if (!is_string($query_string)) { 
  915            throw new \InvalidArgumentException('Invalid input parameters.'); 
  919        if (empty($query_string)) { 
  923        foreach (explode('&', $query_string) as $param) { 
  924            $param = explode('=', $param); 
  925            $name = urldecode($param[0]); 
  926            if (count($param) === 1) { 
  929                $value = urldecode($param[1]); 
  931            $res[$name] = $value; 
  959    public static function redirectTrustedURL($url, $parameters = array()) 
  961        if (!is_string($url) || !is_array($parameters)) { 
  962            throw new \InvalidArgumentException('Invalid input parameters.'); 
  965        $url = self::normalizeURL($url); 
  966        self::redirect($url, $parameters); 
  991    public static function redirectUntrustedURL($url, $parameters = array()) 
  993        if (!is_string($url) || !is_array($parameters)) { 
  994            throw new \InvalidArgumentException('Invalid input parameters.'); 
  997        $url = self::checkURLAllowed($url); 
  998        self::redirect($url, $parameters); 
 1023    public static function resolveURL($url, $base = null) 
 1025        if ($base === null) { 
 1026            $base = self::getBaseURL(); 
 1029        if (!is_string($url) || !is_string($base)) { 
 1030            throw new \InvalidArgumentException('Invalid input parameters.'); 
 1033        if (!preg_match('/^((((\w+:)\/\/[^\/]+)(\/[^?#]*))(?:\?[^#]*)?)(?:#.*)?/', $base, $baseParsed)) { 
 1034            throw new \InvalidArgumentException('Unable to parse base url: '.$base); 
 1037        $baseDir = dirname($baseParsed[5].'filename'); 
 1038        $baseScheme = $baseParsed[4]; 
 1039        $baseHost = $baseParsed[3]; 
 1040        $basePath = $baseParsed[2]; 
 1041        $baseQuery = $baseParsed[1]; 
 1043        if (preg_match('$^\w+:$', $url)) { 
 1047        if (substr($url, 0, 2) === '//') { 
 1048            return $baseScheme.$url; 
 1051        if ($url[0] === '/') { 
 1052            return $baseHost.$url; 
 1054        if ($url[0] === '?') { 
 1055            return $basePath.$url; 
 1057        if ($url[0] === '#') { 
 1058            return $baseQuery.$url; 
 1061        // we have a relative path. Remove query string/fragment and save it as $tail 
 1062        $queryPos = strpos($url, '?'); 
 1063        $fragmentPos = strpos($url, '#'); 
 1064        if ($queryPos !== false || $fragmentPos !== false) { 
 1065            if ($queryPos === false) { 
 1066                $tailPos = $fragmentPos; 
 1067            } elseif ($fragmentPos === false) { 
 1068                $tailPos = $queryPos; 
 1069            } elseif ($queryPos < $fragmentPos) { 
 1070                $tailPos = $queryPos; 
 1072                $tailPos = $fragmentPos; 
 1075            $tail = substr($url, $tailPos); 
 1076            $dir = substr($url, 0, $tailPos); 
 1082        $dir = System::resolvePath($dir, $baseDir); 
 1084        return $baseHost.$dir.$tail; 
 1104    public static function setCookie($name, $value, $params = null, $throw = true) 
 1106        if (!(is_string($name) && // $name must be a string 
 1107            (is_string($value) || is_null($value)) && // $value can be a string or null 
 1108            (is_array($params) || is_null($params)) && // $params can be an array or null 
 1109            is_bool($throw)) // $throw must be boolean 
 1111            throw new \InvalidArgumentException('Invalid input parameters.'); 
 1114        $default_params = array( 
 1124        if ($params !== null) { 
 1125            $params = array_merge($default_params, $params); 
 1127            $params = $default_params; 
 1130        // Do not set secure cookie if not on HTTPS 
 1131        if ($params['secure'] && !self::isHTTPS()) { 
 1133                throw new \SimpleSAML\Error\CannotSetCookie( 
 1134                    'Setting secure cookie on plain HTTP is not allowed.', 
 1135                    \SimpleSAML\Error\CannotSetCookie::SECURE_COOKIE 
 1138            Logger::warning('Error setting cookie: setting secure cookie on plain HTTP is not allowed.'); 
 1142        if ($value === null) { 
 1143            $expire = time() - 365 * 24 * 60 * 60; 
 1144        } elseif (isset($params['expire'])) { 
 1145            $expire = $params['expire']; 
 1146        } elseif ($params['lifetime'] === 0) { 
 1149            $expire = time() + $params['lifetime']; 
 1152        if ($params['raw']) { 
 1153            $success = @setrawcookie( 
 1163            $success = @setcookie( 
 1176                throw new \SimpleSAML\Error\CannotSetCookie( 
 1177                    'Headers already sent.', 
 1178                    \SimpleSAML\Error\CannotSetCookie::HEADERS_SENT 
 1181            Logger::warning('Error setting cookie: headers already sent.'); 
 1202    public static function submitPOSTData($destination, $data) 
 1204        if (!is_string($destination) || !is_array($data)) { 
 1205            throw new \InvalidArgumentException('Invalid input parameters.'); 
 1208        $config = \SimpleSAML_Configuration::getInstance(); 
 1209        $allowed = $config->getBoolean('enable.http_post', false); 
 1211        if ($allowed && preg_match("#^
http:#
", $destination) && self::isHTTPS()) { 
 1212            // we need to post the data to HTTP 
 1213            self::redirect(self::getSecurePOSTRedirectURL($destination, $data)); 
 1216        $p = new \SimpleSAML_XHTML_Template($config, 'post.php'); 
 1217        $p->data['destination'] = $destination; 
 1218        $p->data['post'] = $data; 
An exception for terminatinating execution or to throw for unit testing.
static getModuleURL($resource, array $parameters=array())
Get absolute URL to a specified module resource.
static aesEncrypt($data)
Encrypt data using AES-256-CBC and the system-wide secret salt as key.
static getSecurePOSTRedirectURL($destination, $data)
Obtain a URL where we can redirect to securely post a form with the given data to a specific destinat...
static getServerPort()
Retrieve the port number from $_SERVER environment variables.
static getServerHTTPS()
Retrieve HTTPS status from $_SERVER environment variables.
static getServerHost()
Retrieve Host value from $_SERVER environment variables.
static savePOSTData(\SimpleSAML_Session $session, $destination, $data)
Save the given HTTP POST data and the destination where it should be posted to a given session.
static redirect($url, $parameters=array())
This function redirects the user to the specified address.
static getSessionFromRequest()
Retrieves the current session.
if(!array_key_exists('StateId', $_REQUEST)) $id
static http()
Fetches the global http state from ILIAS.
if((!isset($_SERVER['DOCUMENT_ROOT'])) OR(empty($_SERVER['DOCUMENT_ROOT']))) $_SERVER['DOCUMENT_ROOT']