vendor/contao/core-bundle/src/Resources/contao/library/Contao/Environment.php line 534

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of Contao.
  4.  *
  5.  * (c) Leo Feyer
  6.  *
  7.  * @license LGPL-3.0-or-later
  8.  */
  9. namespace Contao;
  10. /**
  11.  * Reads the environment variables
  12.  *
  13.  * The class returns the environment variables (which are stored in the PHP
  14.  * $_SERVER array) independent of the operating system.
  15.  *
  16.  * Usage:
  17.  *
  18.  *     echo Environment::get('scriptName');
  19.  *     echo Environment::get('requestUri');
  20.  */
  21. class Environment
  22. {
  23.     /**
  24.      * Object instance (Singleton)
  25.      * @var Environment
  26.      */
  27.     protected static $objInstance;
  28.     /**
  29.      * The SAPI name
  30.      * @var string
  31.      */
  32.     protected static $strSapi = \PHP_SAPI;
  33.     /**
  34.      * Cache
  35.      * @var array
  36.      */
  37.     protected static $arrCache = array();
  38.     /**
  39.      * Return an environment variable
  40.      *
  41.      * @param string $strKey The variable name
  42.      *
  43.      * @return mixed The variable value
  44.      */
  45.     public static function get($strKey)
  46.     {
  47.         if (isset(static::$arrCache[$strKey]))
  48.         {
  49.             return static::$arrCache[$strKey];
  50.         }
  51.         if (\in_array($strKeyget_class_methods(self::class)))
  52.         {
  53.             static::$arrCache[$strKey] = static::$strKey();
  54.         }
  55.         else
  56.         {
  57.             $arrChunks preg_split('/([A-Z][a-z]*)/'$strKey, -1PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY);
  58.             $strServerKey strtoupper(implode('_'$arrChunks));
  59.             static::$arrCache[$strKey] = $_SERVER[$strServerKey] ?? null;
  60.         }
  61.         return static::$arrCache[$strKey];
  62.     }
  63.     /**
  64.      * Set an environment variable
  65.      *
  66.      * @param string $strKey   The variable name
  67.      * @param mixed  $varValue The variable value
  68.      */
  69.     public static function set($strKey$varValue)
  70.     {
  71.         static::$arrCache[$strKey] = $varValue;
  72.     }
  73.     /**
  74.      * Reset the internal cache
  75.      */
  76.     public static function reset()
  77.     {
  78.         static::$arrCache = array();
  79.     }
  80.     /**
  81.      * Return the absolute path to the script (e.g. /home/www/html/website/index.php)
  82.      *
  83.      * @return string The absolute path to the script
  84.      */
  85.     protected static function scriptFilename()
  86.     {
  87.         return str_replace('//''/'strtr((static::$strSapi == 'cgi' || static::$strSapi == 'isapi' || static::$strSapi == 'cgi-fcgi' || static::$strSapi == 'fpm-fcgi') && ($_SERVER['ORIG_PATH_TRANSLATED'] ?? $_SERVER['PATH_TRANSLATED']) ? ($_SERVER['ORIG_PATH_TRANSLATED'] ?? $_SERVER['PATH_TRANSLATED']) : ($_SERVER['ORIG_SCRIPT_FILENAME'] ?? $_SERVER['SCRIPT_FILENAME']), '\\''/'));
  88.     }
  89.     /**
  90.      * Return the relative path to the script (e.g. /website/index.php)
  91.      *
  92.      * @return string The relative path to the script
  93.      */
  94.     protected static function scriptName()
  95.     {
  96.         $request System::getContainer()->get('request_stack')->getCurrentRequest();
  97.         if ($request === null)
  98.         {
  99.             return $_SERVER['ORIG_SCRIPT_NAME'] ?? $_SERVER['SCRIPT_NAME'];
  100.         }
  101.         return $request->getScriptName();
  102.     }
  103.     /**
  104.      * Alias for scriptName()
  105.      *
  106.      * @return string The script name
  107.      */
  108.     protected static function phpSelf()
  109.     {
  110.         return static::scriptName();
  111.     }
  112.     /**
  113.      * Return the document root (e.g. /home/www/user/)
  114.      *
  115.      * Calculated as SCRIPT_FILENAME minus SCRIPT_NAME as some CGI versions
  116.      * and mod-rewrite rules might return an incorrect DOCUMENT_ROOT.
  117.      *
  118.      * @return string The document root
  119.      */
  120.     protected static function documentRoot()
  121.     {
  122.         $strDocumentRoot '';
  123.         $arrUriSegments = array();
  124.         $scriptName = static::get('scriptName');
  125.         $scriptFilename = static::get('scriptFilename');
  126.         // Fallback to DOCUMENT_ROOT if SCRIPT_FILENAME and SCRIPT_NAME point to different files
  127.         if (basename($scriptName) != basename($scriptFilename))
  128.         {
  129.             return str_replace('//''/'strtr(realpath($_SERVER['DOCUMENT_ROOT']), '\\''/'));
  130.         }
  131.         if (=== strncmp($scriptFilename'/'1))
  132.         {
  133.             $strDocumentRoot '/';
  134.         }
  135.         $arrSnSegments explode('/'strrev($scriptName));
  136.         $arrSfnSegments explode('/'strrev($scriptFilename));
  137.         foreach ($arrSfnSegments as $k=>$v)
  138.         {
  139.             if (@$arrSnSegments[$k] != $v)
  140.             {
  141.                 $arrUriSegments[] = $v;
  142.             }
  143.         }
  144.         $strDocumentRoot .= strrev(implode('/'$arrUriSegments));
  145.         if (\strlen($strDocumentRoot) < 2)
  146.         {
  147.             $strDocumentRoot substr($scriptFilename0, -(\strlen($strDocumentRoot) + 1));
  148.         }
  149.         return str_replace('//''/'strtr(realpath($strDocumentRoot), '\\''/'));
  150.     }
  151.     /**
  152.      * Return the query string (e.g. id=2)
  153.      *
  154.      * @return string The query string
  155.      */
  156.     protected static function queryString()
  157.     {
  158.         if (!isset($_SERVER['QUERY_STRING']))
  159.         {
  160.             return '';
  161.         }
  162.         return static::encodeRequestString($_SERVER['QUERY_STRING']);
  163.     }
  164.     /**
  165.      * Return the request URI [path]?[query] (e.g. /contao/index.php?id=2)
  166.      *
  167.      * @return string The request URI
  168.      */
  169.     protected static function requestUri()
  170.     {
  171.         if (!empty($_SERVER['REQUEST_URI']))
  172.         {
  173.             $arrComponents parse_url($_SERVER['REQUEST_URI']);
  174.             if ($arrComponents === false)
  175.             {
  176.                 $strRequest $_SERVER['REQUEST_URI'];
  177.             }
  178.             else
  179.             {
  180.                 $strRequest $arrComponents['path'] . (isset($arrComponents['query']) ? '?' $arrComponents['query'] : '');
  181.             }
  182.         }
  183.         else
  184.         {
  185.             $strRequest '/' preg_replace('/^\//''', static::get('scriptName')) . (!empty($_SERVER['QUERY_STRING']) ? '?' $_SERVER['QUERY_STRING'] : '');
  186.         }
  187.         return static::encodeRequestString($strRequest);
  188.     }
  189.     /**
  190.      * Return the first eight accepted languages as array
  191.      *
  192.      * @return array The languages array
  193.      */
  194.     protected static function httpAcceptLanguage()
  195.     {
  196.         $arrAccepted = array();
  197.         $arrLanguages = array();
  198.         // The implementation differs from the original implementation and also works with .jp browsers
  199.         preg_match_all('/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i'$_SERVER['HTTP_ACCEPT_LANGUAGE'], $arrAccepted);
  200.         // Remove all invalid locales
  201.         foreach ($arrAccepted[1] as $v)
  202.         {
  203.             $chunks explode('-'$v);
  204.             // Language plus dialect, e.g. en-US or fr-FR
  205.             if (isset($chunks[1]))
  206.             {
  207.                 $locale $chunks[0] . '-' strtoupper($chunks[1]);
  208.                 if (preg_match('/^[a-z]{2}(-[A-Z]{2})?$/'$locale))
  209.                 {
  210.                     $arrLanguages[] = $locale;
  211.                 }
  212.             }
  213.             $locale $chunks[0];
  214.             // Language only, e.g. en or fr (see #29)
  215.             if (preg_match('/^[a-z]{2}$/'$locale))
  216.             {
  217.                 $arrLanguages[] = $locale;
  218.             }
  219.         }
  220.         return \array_slice(array_unique($arrLanguages), 08);
  221.     }
  222.     /**
  223.      * Return accepted encoding types as array
  224.      *
  225.      * @return array The encoding types array
  226.      */
  227.     protected static function httpAcceptEncoding()
  228.     {
  229.         return array_values(array_unique(explode(','strtolower($_SERVER['HTTP_ACCEPT_ENCODING']))));
  230.     }
  231.     /**
  232.      * Return the user agent as string
  233.      *
  234.      * @return string The user agent string
  235.      */
  236.     protected static function httpUserAgent()
  237.     {
  238.         if (!isset($_SERVER['HTTP_USER_AGENT']))
  239.         {
  240.             return '';
  241.         }
  242.         $ua strip_tags($_SERVER['HTTP_USER_AGENT']);
  243.         $ua preg_replace('/javascript|vbscri?pt|script|applet|alert|document|write|cookie/i'''$ua);
  244.         return substr($ua0255);
  245.     }
  246.     /**
  247.      * Return the HTTP Host
  248.      *
  249.      * @return string The host name
  250.      */
  251.     protected static function httpHost()
  252.     {
  253.         if (!empty($_SERVER['HTTP_HOST']))
  254.         {
  255.             $host $_SERVER['HTTP_HOST'];
  256.         }
  257.         else
  258.         {
  259.             $host $_SERVER['SERVER_NAME'] ?? null;
  260.             if (($_SERVER['SERVER_PORT'] ?? 80) != 80)
  261.             {
  262.                 $host .= ':' $_SERVER['SERVER_PORT'];
  263.             }
  264.         }
  265.         return preg_replace('/[^A-Za-z0-9[\].:_-]/'''$host);
  266.     }
  267.     /**
  268.      * Return the HTTP X-Forwarded-Host
  269.      *
  270.      * @return string The name of the X-Forwarded-Host
  271.      */
  272.     protected static function httpXForwardedHost()
  273.     {
  274.         if (!isset($_SERVER['HTTP_X_FORWARDED_HOST']))
  275.         {
  276.             return '';
  277.         }
  278.         return preg_replace('/[^A-Za-z0-9[\].:-]/'''$_SERVER['HTTP_X_FORWARDED_HOST']);
  279.     }
  280.     /**
  281.      * Return true if the current page was requested via an SSL connection
  282.      *
  283.      * @return boolean True if SSL is enabled
  284.      */
  285.     protected static function ssl()
  286.     {
  287.         $request System::getContainer()->get('request_stack')->getCurrentRequest();
  288.         if ($request === null)
  289.         {
  290.             return false;
  291.         }
  292.         return $request->isSecure();
  293.     }
  294.     /**
  295.      * Return the current URL without path or query string
  296.      *
  297.      * @return string The URL
  298.      */
  299.     protected static function url()
  300.     {
  301.         return (static::get('ssl') ? 'https://' 'http://') . static::get('httpHost');
  302.     }
  303.     /**
  304.      * Return the current URL with path or query string
  305.      *
  306.      * @return string The URL
  307.      */
  308.     protected static function uri()
  309.     {
  310.         return static::get('url') . static::get('requestUri');
  311.     }
  312.     /**
  313.      * Return the real REMOTE_ADDR even if a proxy server is used
  314.      *
  315.      * @return string The IP address of the client
  316.      */
  317.     protected static function ip()
  318.     {
  319.         $request System::getContainer()->get('request_stack')->getCurrentRequest();
  320.         if ($request === null)
  321.         {
  322.             return '';
  323.         }
  324.         return $request->getClientIp();
  325.     }
  326.     /**
  327.      * Return the SERVER_ADDR
  328.      *
  329.      * @return string The IP address of the server
  330.      */
  331.     protected static function server()
  332.     {
  333.         $strServer = !empty($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR'] : $_SERVER['LOCAL_ADDR'];
  334.         // Special workaround for Strato users
  335.         if (empty($strServer))
  336.         {
  337.             $strServer = @gethostbyname($_SERVER['SERVER_NAME']);
  338.         }
  339.         return $strServer;
  340.     }
  341.     /**
  342.      * Return the relative path to the base directory (e.g. /path)
  343.      *
  344.      * @return string The relative path to the installation
  345.      */
  346.     protected static function path()
  347.     {
  348.         $request System::getContainer()->get('request_stack')->getCurrentRequest();
  349.         if ($request === null)
  350.         {
  351.             return '';
  352.         }
  353.         return $request->getBasePath();
  354.     }
  355.     /**
  356.      * Return the relative path to the script (e.g. index.php)
  357.      *
  358.      * @return string The relative path to the script
  359.      */
  360.     protected static function script()
  361.     {
  362.         return preg_replace('/^' preg_quote(static::get('path'), '/') . '\/?/''', static::get('scriptName'));
  363.     }
  364.     /**
  365.      * Return the relative path to the script and include the request (e.g. index.php?id=2)
  366.      *
  367.      * @return string The relative path to the script including the request string
  368.      */
  369.     protected static function request()
  370.     {
  371.         return preg_replace('/^' preg_quote(static::get('path'), '/') . '\/?/''', static::get('requestUri'));
  372.     }
  373.     /**
  374.      * Return the request string without the script name (e.g. en/news.html)
  375.      *
  376.      * @return string The base URL
  377.      */
  378.     protected static function relativeRequest()
  379.     {
  380.         return preg_replace('/^' preg_quote(static::get('script'), '/') . '\/?/''', static::get('request'));
  381.     }
  382.     /**
  383.      * Return the request string without the index.php fragment
  384.      *
  385.      * @return string The request string without the index.php fragment
  386.      */
  387.     protected static function indexFreeRequest()
  388.     {
  389.         $strRequest = static::get('request');
  390.         if ($strRequest == static::get('script'))
  391.         {
  392.             return '';
  393.         }
  394.         return $strRequest;
  395.     }
  396.     /**
  397.      * Return the URL and path that can be used in a <base> tag
  398.      *
  399.      * @return string The base URL
  400.      */
  401.     protected static function base()
  402.     {
  403.         return static::get('url') . static::get('path') . '/';
  404.     }
  405.     /**
  406.      * Return the host name
  407.      *
  408.      * @return string The host name
  409.      */
  410.     protected static function host()
  411.     {
  412.         return preg_replace('/:\d+$/''', static::get('httpHost'));
  413.     }
  414.     /**
  415.      * Return true on Ajax requests
  416.      *
  417.      * @return boolean True if it is an Ajax request
  418.      */
  419.     protected static function isAjaxRequest()
  420.     {
  421.         if (!isset($_SERVER['HTTP_X_REQUESTED_WITH']))
  422.         {
  423.             return false;
  424.         }
  425.         return $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest';
  426.     }
  427.     /**
  428.      * Return the operating system and the browser name and version
  429.      *
  430.      * @return object The agent information
  431.      *
  432.      * @deprecated Deprecated since Contao 4.13, to be removed in Contao 5.0.
  433.      */
  434.     protected static function agent()
  435.     {
  436.         trigger_deprecation('contao/core-bundle''4.13''Using "%s::get(\'agent\')" has been deprecated and will no longer work in Contao 5.0.'__CLASS__);
  437.         $ua = static::get('httpUserAgent');
  438.         $return = new \stdClass();
  439.         $return->string $ua;
  440.         $os 'unknown';
  441.         $mobile false;
  442.         $browser 'other';
  443.         $shorty '';
  444.         $version '';
  445.         $engine '';
  446.         // Operating system
  447.         foreach (Config::get('os') as $k=>$v)
  448.         {
  449.             if (stripos($ua$k) !== false)
  450.             {
  451.                 $os $v['os'];
  452.                 $mobile $v['mobile'];
  453.                 break;
  454.             }
  455.         }
  456.         $return->os $os;
  457.         // Browser and version
  458.         foreach (Config::get('browser') as $k=>$v)
  459.         {
  460.             if (stripos($ua$k) !== false)
  461.             {
  462.                 $browser $v['browser'];
  463.                 $shorty  $v['shorty'];
  464.                 $version preg_replace($v['version'], '$1'$ua);
  465.                 $engine  $v['engine'];
  466.                 break;
  467.             }
  468.         }
  469.         $versions explode('.'$version);
  470.         $version  $versions[0];
  471.         $return->class $os ' ' $browser ' ' $engine;
  472.         // Add the version number if available
  473.         if ($version)
  474.         {
  475.             $return->class .= ' ' $shorty $version;
  476.         }
  477.         // Android tablets are not mobile (see #4150 and #5869)
  478.         if ($os == 'android' && $engine != 'presto' && stripos($ua'mobile') === false)
  479.         {
  480.             $mobile false;
  481.         }
  482.         // Mark mobile devices
  483.         if ($mobile)
  484.         {
  485.             $return->class .= ' mobile';
  486.         }
  487.         $return->browser  $browser;
  488.         $return->shorty   $shorty;
  489.         $return->version  $version;
  490.         $return->engine   $engine;
  491.         $return->versions $versions;
  492.         $return->mobile   $mobile;
  493.         return $return;
  494.     }
  495.     /**
  496.      * Encode a request string preserving certain reserved characters
  497.      *
  498.      * @param string $strRequest The request string
  499.      *
  500.      * @return string The encoded request string
  501.      */
  502.     protected static function encodeRequestString($strRequest)
  503.     {
  504.         return preg_replace_callback('/[^A-Za-z0-9\-_.~&=+,\/?%\[\]]+/', static function ($matches) { return rawurlencode($matches[0]); }, $strRequest);
  505.     }
  506.     /**
  507.      * Prevent direct instantiation (Singleton)
  508.      *
  509.      * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0.
  510.      *             The Environment class is now static.
  511.      */
  512.     protected function __construct()
  513.     {
  514.     }
  515.     /**
  516.      * Prevent cloning of the object (Singleton)
  517.      *
  518.      * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0.
  519.      *             The Environment class is now static.
  520.      */
  521.     final public function __clone()
  522.     {
  523.     }
  524.     /**
  525.      * Return an environment variable
  526.      *
  527.      * @param string $strKey The variable name
  528.      *
  529.      * @return string The variable value
  530.      *
  531.      * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0.
  532.      *             Use Environment::get() instead.
  533.      */
  534.     public function __get($strKey)
  535.     {
  536.         return static::get($strKey);
  537.     }
  538.     /**
  539.      * Set an environment variable
  540.      *
  541.      * @param string $strKey   The variable name
  542.      * @param mixed  $varValue The variable value
  543.      *
  544.      * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0.
  545.      *             Use Environment::set() instead.
  546.      */
  547.     public function __set($strKey$varValue)
  548.     {
  549.         static::set($strKey$varValue);
  550.     }
  551.     /**
  552.      * Return the object instance (Singleton)
  553.      *
  554.      * @return Environment The object instance
  555.      *
  556.      * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0.
  557.      *             The Environment class is now static.
  558.      */
  559.     public static function getInstance()
  560.     {
  561.         trigger_deprecation('contao/core-bundle''4.0''Using "Contao\Environment::getInstance()" has been deprecated and will no longer work in Contao 5.0. The "Contao\Environment" class is now static.');
  562.         if (static::$objInstance === null)
  563.         {
  564.             static::$objInstance = new static();
  565.         }
  566.         return static::$objInstance;
  567.     }
  568. }
  569. class_alias(Environment::class, 'Environment');