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

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