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

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.             if ($arrComponents === false)
  177.             {
  178.                 $strRequest $_SERVER['REQUEST_URI'];
  179.             }
  180.             else
  181.             {
  182.                 $strRequest $arrComponents['path'] . (isset($arrComponents['query']) ? '?' $arrComponents['query'] : '');
  183.             }
  184.         }
  185.         else
  186.         {
  187.             $strRequest '/' preg_replace('/^\//''', static::get('scriptName')) . (!empty($_SERVER['QUERY_STRING']) ? '?' $_SERVER['QUERY_STRING'] : '');
  188.         }
  189.         return static::encodeRequestString($strRequest);
  190.     }
  191.     /**
  192.      * Return the first eight accepted languages as array
  193.      *
  194.      * @return array The languages array
  195.      *
  196.      * @author Leo Unglaub <https://github.com/LeoUnglaub>
  197.      */
  198.     protected static function httpAcceptLanguage()
  199.     {
  200.         $arrAccepted = array();
  201.         $arrLanguages = array();
  202.         // The implementation differs from the original implementation and also works with .jp browsers
  203.         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);
  204.         // Remove all invalid locales
  205.         foreach ($arrAccepted[1] as $v)
  206.         {
  207.             $chunks explode('-'$v);
  208.             // Language plus dialect, e.g. en-US or fr-FR
  209.             if (isset($chunks[1]))
  210.             {
  211.                 $locale $chunks[0] . '-' strtoupper($chunks[1]);
  212.                 if (preg_match('/^[a-z]{2}(-[A-Z]{2})?$/'$locale))
  213.                 {
  214.                     $arrLanguages[] = $locale;
  215.                 }
  216.             }
  217.             $locale $chunks[0];
  218.             // Language only, e.g. en or fr (see #29)
  219.             if (preg_match('/^[a-z]{2}$/'$locale))
  220.             {
  221.                 $arrLanguages[] = $locale;
  222.             }
  223.         }
  224.         return \array_slice(array_unique($arrLanguages), 08);
  225.     }
  226.     /**
  227.      * Return accepted encoding types as array
  228.      *
  229.      * @return array The encoding types array
  230.      */
  231.     protected static function httpAcceptEncoding()
  232.     {
  233.         return array_values(array_unique(explode(','strtolower($_SERVER['HTTP_ACCEPT_ENCODING']))));
  234.     }
  235.     /**
  236.      * Return the user agent as string
  237.      *
  238.      * @return string The user agent string
  239.      */
  240.     protected static function httpUserAgent()
  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 relativ 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 relativ 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.     protected static function agent()
  433.     {
  434.         $ua = static::get('httpUserAgent');
  435.         $return = new \stdClass();
  436.         $return->string $ua;
  437.         $os 'unknown';
  438.         $mobile false;
  439.         $browser 'other';
  440.         $shorty '';
  441.         $version '';
  442.         $engine '';
  443.         // Operating system
  444.         foreach (Config::get('os') as $k=>$v)
  445.         {
  446.             if (stripos($ua$k) !== false)
  447.             {
  448.                 $os $v['os'];
  449.                 $mobile $v['mobile'];
  450.                 break;
  451.             }
  452.         }
  453.         $return->os $os;
  454.         // Browser and version
  455.         foreach (Config::get('browser') as $k=>$v)
  456.         {
  457.             if (stripos($ua$k) !== false)
  458.             {
  459.                 $browser $v['browser'];
  460.                 $shorty  $v['shorty'];
  461.                 $version preg_replace($v['version'], '$1'$ua);
  462.                 $engine  $v['engine'];
  463.                 break;
  464.             }
  465.         }
  466.         $versions explode('.'$version);
  467.         $version  $versions[0];
  468.         $return->class $os ' ' $browser ' ' $engine;
  469.         // Add the version number if available
  470.         if ($version)
  471.         {
  472.             $return->class .= ' ' $shorty $version;
  473.         }
  474.         // Android tablets are not mobile (see #4150 and #5869)
  475.         if ($os == 'android' && $engine != 'presto' && stripos($ua'mobile') === false)
  476.         {
  477.             $mobile false;
  478.         }
  479.         // Mark mobile devices
  480.         if ($mobile)
  481.         {
  482.             $return->class .= ' mobile';
  483.         }
  484.         $return->browser  $browser;
  485.         $return->shorty   $shorty;
  486.         $return->version  $version;
  487.         $return->engine   $engine;
  488.         $return->versions $versions;
  489.         $return->mobile   $mobile;
  490.         return $return;
  491.     }
  492.     /**
  493.      * Encode a request string preserving certain reserved characters
  494.      *
  495.      * @param string $strRequest The request string
  496.      *
  497.      * @return string The encoded request string
  498.      */
  499.     protected static function encodeRequestString($strRequest)
  500.     {
  501.         return preg_replace_callback('/[^A-Za-z0-9\-_.~&=+,\/?%\[\]]+/', static function ($matches) { return rawurlencode($matches[0]); }, $strRequest);
  502.     }
  503.     /**
  504.      * Prevent direct instantiation (Singleton)
  505.      *
  506.      * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0.
  507.      *             The Environment class is now static.
  508.      */
  509.     protected function __construct()
  510.     {
  511.     }
  512.     /**
  513.      * Prevent cloning of the object (Singleton)
  514.      *
  515.      * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0.
  516.      *             The Environment class is now static.
  517.      */
  518.     final public function __clone()
  519.     {
  520.     }
  521.     /**
  522.      * Return an environment variable
  523.      *
  524.      * @param string $strKey The variable name
  525.      *
  526.      * @return string The variable value
  527.      *
  528.      * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0.
  529.      *             Use Environment::get() instead.
  530.      */
  531.     public function __get($strKey)
  532.     {
  533.         return static::get($strKey);
  534.     }
  535.     /**
  536.      * Set an environment variable
  537.      *
  538.      * @param string $strKey   The variable name
  539.      * @param mixed  $varValue The variable value
  540.      *
  541.      * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0.
  542.      *             Use Environment::set() instead.
  543.      */
  544.     public function __set($strKey$varValue)
  545.     {
  546.         static::set($strKey$varValue);
  547.     }
  548.     /**
  549.      * Return the object instance (Singleton)
  550.      *
  551.      * @return Environment The object instance
  552.      *
  553.      * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0.
  554.      *             The Environment class is now static.
  555.      */
  556.     public static function getInstance()
  557.     {
  558.         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.');
  559.         if (static::$objInstance === null)
  560.         {
  561.             static::$objInstance = new static();
  562.         }
  563.         return static::$objInstance;
  564.     }
  565. }
  566. class_alias(Environment::class, 'Environment');