vendor/contao/core-bundle/src/Resources/contao/library/Contao/System.php line 206

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. use Contao\CoreBundle\Config\Loader\PhpFileLoader;
  11. use Contao\CoreBundle\Config\Loader\XliffFileLoader;
  12. use Contao\CoreBundle\Monolog\ContaoContext;
  13. use Contao\CoreBundle\Util\LocaleUtil;
  14. use Contao\Database\Installer;
  15. use Contao\Database\Updater;
  16. use Psr\Log\LogLevel;
  17. use Symfony\Component\DependencyInjection\Container;
  18. use Symfony\Component\DependencyInjection\ContainerInterface;
  19. use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
  20. use Symfony\Component\Filesystem\Path;
  21. use Symfony\Component\Finder\SplFileInfo;
  22. use Symfony\Component\HttpFoundation\Session\Session;
  23. /**
  24.  * Abstract library base class
  25.  *
  26.  * The class provides miscellaneous methods that are used all throughout the
  27.  * application. It is the base class of the Contao library which provides the
  28.  * central "import" method to load other library classes.
  29.  *
  30.  * Usage:
  31.  *
  32.  *     class MyClass extends System
  33.  *     {
  34.  *         public function __construct()
  35.  *         {
  36.  *             $this->import('Database');
  37.  *         }
  38.  *     }
  39.  *
  40.  * @property Automator                        $Automator   The automator object
  41.  * @property Config                           $Config      The config object
  42.  * @property Database                         $Database    The database object
  43.  * @property Environment                      $Environment The environment object
  44.  * @property Files                            $Files       The files object
  45.  * @property Input                            $Input       The input object
  46.  * @property Installer                        $Installer   The database installer object
  47.  * @property Updater                          $Updater     The database updater object
  48.  * @property Messages                         $Messages    The messages object
  49.  * @property Session                          $Session     The session object
  50.  * @property StyleSheets                      $StyleSheets The style sheets object
  51.  * @property BackendTemplate|FrontendTemplate $Template    The template object (TODO: remove this line in Contao 5.0)
  52.  * @property BackendUser|FrontendUser         $User        The user object
  53.  */
  54. abstract class System
  55. {
  56.     /**
  57.      * Container
  58.      * @var ContainerInterface
  59.      */
  60.     protected static $objContainer;
  61.     /**
  62.      * @var array|null
  63.      */
  64.     private static $removedServiceIds;
  65.     /**
  66.      * Cache
  67.      * @var array
  68.      * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0.
  69.      */
  70.     protected $arrCache = array();
  71.     /**
  72.      * Default libraries
  73.      * @var array
  74.      */
  75.     protected $arrObjects = array();
  76.     /**
  77.      * Static objects
  78.      * @var array
  79.      */
  80.     protected static $arrStaticObjects = array();
  81.     /**
  82.      * Singletons
  83.      * @var array
  84.      */
  85.     protected static $arrSingletons = array();
  86.     /**
  87.      * Available languages
  88.      * @var array
  89.      */
  90.     protected static $arrLanguages = array();
  91.     /**
  92.      * Loaded language files
  93.      * @var array
  94.      */
  95.     protected static $arrLanguageFiles = array();
  96.     /**
  97.      * Available image sizes
  98.      * @var array
  99.      */
  100.     protected static $arrImageSizes = array();
  101.     /**
  102.      * Available language files
  103.      * @var array|false|null
  104.      */
  105.     protected static $arrAvailableLanguageFiles;
  106.     /**
  107.      * Import the Config instance
  108.      */
  109.     protected function __construct()
  110.     {
  111.         $this->import(Config::class, 'Config');
  112.     }
  113.     /**
  114.      * Get an object property
  115.      *
  116.      * Lazy load the Input and Environment libraries (which are now static) and
  117.      * only include them as object property if an old module requires it
  118.      *
  119.      * @param string $strKey The property name
  120.      *
  121.      * @return mixed|null The property value or null
  122.      */
  123.     public function __get($strKey)
  124.     {
  125.         if (!isset($this->arrObjects[$strKey]))
  126.         {
  127.             /** @var Input|Environment|Session|string $strKey */
  128.             if ($strKey == 'Input' || $strKey == 'Environment' || $strKey == 'Session')
  129.             {
  130.                 $this->arrObjects[$strKey] = $strKey::getInstance();
  131.             }
  132.             else
  133.             {
  134.                 return null;
  135.             }
  136.         }
  137.         return $this->arrObjects[$strKey];
  138.     }
  139.     /**
  140.      * Import a library and make it accessible by its name or an optional key
  141.      *
  142.      * @param string|object $strClass The class name
  143.      * @param string|object $strKey   An optional key to store the object under
  144.      * @param boolean       $blnForce If true, existing objects will be overridden
  145.      *
  146.      * @throws ServiceNotFoundException
  147.      */
  148.     protected function import($strClass$strKey=null$blnForce=false)
  149.     {
  150.         $strKey $strKey ?: $strClass;
  151.         if (\is_object($strKey))
  152.         {
  153.             $strKey \get_class($strClass);
  154.         }
  155.         if ($blnForce || !isset($this->arrObjects[$strKey]))
  156.         {
  157.             $container = static::getContainer();
  158.             if (null === $container)
  159.             {
  160.                 throw new \RuntimeException('The Symfony container is not available, did you initialize the Contao framework?');
  161.             }
  162.             if (\is_object($strClass))
  163.             {
  164.                 $this->arrObjects[$strKey] = $strClass;
  165.             }
  166.             elseif (isset(static::$arrSingletons[$strClass]))
  167.             {
  168.                 $this->arrObjects[$strKey] = static::$arrSingletons[$strClass];
  169.             }
  170.             elseif ($container->has($strClass) && (strpos($strClass'\\') !== false || !class_exists($strClass)))
  171.             {
  172.                 $this->arrObjects[$strKey] = $container->get($strClass);
  173.             }
  174.             elseif (($container->getParameter('kernel.debug') || !class_exists($strClass)) && self::isServiceInlined($strClass))
  175.             {
  176.                 // In debug mode, we check for inlined services before trying to create a new instance of the class
  177.                 throw new ServiceNotFoundException($strClassnullnull, array(), sprintf('The "%s" service or alias has been removed or inlined when the container was compiled. You should either make it public, or stop using the container directly and use dependency injection instead.'$strClass));
  178.             }
  179.             elseif (!class_exists($strClass))
  180.             {
  181.                 throw new \RuntimeException('System::import() failed because class "' $strClass '" is not a valid class name or does not exist.');
  182.             }
  183.             elseif (\in_array('getInstance'get_class_methods($strClass)))
  184.             {
  185.                 $this->arrObjects[$strKey] = static::$arrSingletons[$strClass] = \call_user_func(array($strClass'getInstance'));
  186.             }
  187.             else
  188.             {
  189.                 try
  190.                 {
  191.                     $this->arrObjects[$strKey] = new $strClass();
  192.                 }
  193.                 catch (\Throwable $t)
  194.                 {
  195.                     if (!$container->getParameter('kernel.debug') && self::isServiceInlined($strClass))
  196.                     {
  197.                         throw new ServiceNotFoundException($strClassnullnull, array(), sprintf('The "%s" service or alias has been removed or inlined when the container was compiled. You should either make it public, or stop using the container directly and use dependency injection instead.'$strClass));
  198.                     }
  199.                     throw $t;
  200.                 }
  201.             }
  202.         }
  203.     }
  204.     /**
  205.      * Import a library in non-object context
  206.      *
  207.      * @param string|object $strClass The class name
  208.      * @param string|object $strKey   An optional key to store the object under
  209.      * @param boolean       $blnForce If true, existing objects will be overridden
  210.      *
  211.      * @throws ServiceNotFoundException
  212.      *
  213.      * @return object The imported object
  214.      */
  215.     public static function importStatic($strClass$strKey=null$blnForce=false)
  216.     {
  217.         $strKey $strKey ?: $strClass;
  218.         if (\is_object($strKey))
  219.         {
  220.             $strKey \get_class($strClass);
  221.         }
  222.         if ($blnForce || !isset(static::$arrStaticObjects[$strKey]))
  223.         {
  224.             $container = static::getContainer();
  225.             if (null === $container)
  226.             {
  227.                 throw new \RuntimeException('The Symfony container is not available, did you initialize the Contao framework?');
  228.             }
  229.             if (\is_object($strClass))
  230.             {
  231.                 static::$arrStaticObjects[$strKey] = $strClass;
  232.             }
  233.             elseif (isset(static::$arrSingletons[$strClass]))
  234.             {
  235.                 static::$arrStaticObjects[$strKey] = static::$arrSingletons[$strClass];
  236.             }
  237.             elseif ($container->has($strClass) && (strpos($strClass'\\') !== false || !class_exists($strClass)))
  238.             {
  239.                 static::$arrStaticObjects[$strKey] = $container->get($strClass);
  240.             }
  241.             elseif (($container->getParameter('kernel.debug') || !class_exists($strClass)) && self::isServiceInlined($strClass))
  242.             {
  243.                 // In debug mode, we check for inlined services before trying to create a new instance of the class
  244.                 throw new ServiceNotFoundException($strClassnullnull, array(), sprintf('The "%s" service or alias has been removed or inlined when the container was compiled. You should either make it public, or stop using the container directly and use dependency injection instead.'$strClass));
  245.             }
  246.             elseif (!class_exists($strClass))
  247.             {
  248.                 throw new \RuntimeException('System::importStatic() failed because class "' $strClass '" is not a valid class name or does not exist.');
  249.             }
  250.             elseif (\in_array('getInstance'get_class_methods($strClass)))
  251.             {
  252.                 static::$arrStaticObjects[$strKey] = static::$arrSingletons[$strClass] = \call_user_func(array($strClass'getInstance'));
  253.             }
  254.             else
  255.             {
  256.                 try
  257.                 {
  258.                     static::$arrStaticObjects[$strKey] = new $strClass();
  259.                 }
  260.                 catch (\Throwable $t)
  261.                 {
  262.                     if (!$container->getParameter('kernel.debug') && self::isServiceInlined($strClass))
  263.                     {
  264.                         throw new ServiceNotFoundException($strClassnullnull, array(), sprintf('The "%s" service or alias has been removed or inlined when the container was compiled. You should either make it public, or stop using the container directly and use dependency injection instead.'$strClass));
  265.                     }
  266.                     throw $t;
  267.                 }
  268.             }
  269.         }
  270.         return static::$arrStaticObjects[$strKey];
  271.     }
  272.     private static function isServiceInlined($strClass)
  273.     {
  274.         $container = static::getContainer();
  275.         if (!$container instanceof Container)
  276.         {
  277.             return false;
  278.         }
  279.         if (null === self::$removedServiceIds)
  280.         {
  281.             self::$removedServiceIds $container->getRemovedIds();
  282.         }
  283.         return isset(self::$removedServiceIds[$strClass]);
  284.     }
  285.     /**
  286.      * Return the container object
  287.      *
  288.      * @return ContainerInterface The container object
  289.      */
  290.     public static function getContainer()
  291.     {
  292.         return static::$objContainer;
  293.     }
  294.     /**
  295.      * Set the container object
  296.      *
  297.      * @param ContainerInterface $container The container object
  298.      */
  299.     public static function setContainer(ContainerInterface $container)
  300.     {
  301.         static::$objContainer $container;
  302.     }
  303.     /**
  304.      * Add a log entry to the database
  305.      *
  306.      * @param string $strText     The log message
  307.      * @param string $strFunction The function name
  308.      * @param string $strCategory The category name
  309.      *
  310.      * @deprecated Deprecated since Contao 4.2, to be removed in Contao 5.
  311.      *             Use the logger service with your context or any of the predefined monolog.logger.contao services instead.
  312.      */
  313.     public static function log($strText$strFunction$strCategory)
  314.     {
  315.         trigger_deprecation('contao/core-bundle''4.2''Using "Contao\System::log()" has been deprecated and will no longer work in Contao 5.0. Use the "logger" service or any of the predefined "monolog.logger.contao" services instead.');
  316.         $level 'ERROR' === $strCategory LogLevel::ERROR LogLevel::INFO;
  317.         $logger = static::getContainer()->get('monolog.logger.contao');
  318.         $logger->log($level$strText, array('contao' => new ContaoContext($strFunction$strCategory)));
  319.     }
  320.     /**
  321.      * Return the referer URL and optionally encode ampersands
  322.      *
  323.      * @param boolean $blnEncodeAmpersands If true, ampersands will be encoded
  324.      * @param string  $strTable            An optional table name
  325.      *
  326.      * @return string The referer URL
  327.      */
  328.     public static function getReferer($blnEncodeAmpersands=false$strTable=null)
  329.     {
  330.         $objSession = static::getContainer()->get('session');
  331.         $ref Input::get('ref');
  332.         $key Input::get('popup') ? 'popupReferer' 'referer';
  333.         $session $objSession->get($key);
  334.         $return null;
  335.         if (null !== $session)
  336.         {
  337.             // Unique referer ID
  338.             if ($ref && isset($session[$ref]))
  339.             {
  340.                 $session $session[$ref];
  341.             }
  342.             elseif (\defined('TL_MODE') && TL_MODE == 'BE' && \is_array($session))
  343.             {
  344.                 $session end($session);
  345.             }
  346.             // Use a specific referer
  347.             if ($strTable && isset($session[$strTable]) && Input::get('act') != 'select')
  348.             {
  349.                 $session['current'] = $session[$strTable];
  350.             }
  351.             // Remove parameters helper
  352.             $cleanUrl = static function ($url$params = array('rt''ref'))
  353.             {
  354.                 if (!$url || strpos($url'?') === false)
  355.                 {
  356.                     return $url;
  357.                 }
  358.                 list($path$query) = explode('?'$url2);
  359.                 parse_str($query$pairs);
  360.                 foreach ($params as $param)
  361.                 {
  362.                     unset($pairs[$param]);
  363.                 }
  364.                 if (empty($pairs))
  365.                 {
  366.                     return $path;
  367.                 }
  368.                 return $path '?' http_build_query($pairs'''&'PHP_QUERY_RFC3986);
  369.             };
  370.             // Determine current or last
  371.             $strUrl = ($cleanUrl($session['current'] ?? null) != $cleanUrl(Environment::get('request'))) ? ($session['current'] ?? null) : ($session['last'] ?? null);
  372.             // Remove the "toggle" and "toggle all" parameters
  373.             $return $cleanUrl($strUrl, array('tg''ptg'));
  374.         }
  375.         // Fallback to the generic referer in the front end
  376.         if (!$return && \defined('TL_MODE') && TL_MODE == 'FE')
  377.         {
  378.             $return Environment::get('httpReferer');
  379.         }
  380.         // Fallback to the current URL if there is no referer
  381.         if (!$return)
  382.         {
  383.             if (\defined('TL_MODE') && TL_MODE == 'BE')
  384.             {
  385.                 $return = static::getContainer()->get('router')->generate('contao_backend');
  386.             }
  387.             else
  388.             {
  389.                 $return Environment::get('url');
  390.             }
  391.         }
  392.         // Do not urldecode here!
  393.         return preg_replace('/&(amp;)?/i', ($blnEncodeAmpersands '&amp;' '&'), $return);
  394.     }
  395.     /**
  396.      * Load a set of language files
  397.      *
  398.      * @param string      $strName     The table name
  399.      * @param string|null $strLanguage An optional language code
  400.      * @param boolean     $blnNoCache  If true, the cache will be bypassed
  401.      */
  402.     public static function loadLanguageFile($strName$strLanguage=null$blnNoCache=false)
  403.     {
  404.         if ($strLanguage === null)
  405.         {
  406.             $strLanguage LocaleUtil::formatAsLocale($GLOBALS['TL_LANGUAGE'] ?? 'en');
  407.         }
  408.         // Fall back to English
  409.         if (!$strLanguage)
  410.         {
  411.             $strLanguage 'en';
  412.         }
  413.         if (!== preg_match('/^[a-z0-9_-]+$/i'$strName))
  414.         {
  415.             throw new \InvalidArgumentException(sprintf('Invalid language file name "%s"'$strName));
  416.         }
  417.         // Return if the language file has been loaded already
  418.         if (!$blnNoCache && array_key_last(static::$arrLanguageFiles[$strName] ?? array()) === $strLanguage)
  419.         {
  420.             return;
  421.         }
  422.         $strCacheKey $strLanguage;
  423.         // Make sure the language exists
  424.         if ($strLanguage != 'en' && !static::isInstalledLanguage($strLanguage))
  425.         {
  426.             $strShortLang substr($strLanguage02);
  427.             // Fall back to "de" if "de_DE" does not exist
  428.             if ($strShortLang != $strLanguage && static::isInstalledLanguage($strShortLang))
  429.             {
  430.                 $strLanguage $strShortLang;
  431.             }
  432.             // Fall back to English (see #6581)
  433.             else
  434.             {
  435.                 $strLanguage 'en';
  436.             }
  437.         }
  438.         // Unset to move the new array key to the last position
  439.         unset(static::$arrLanguageFiles[$strName][$strCacheKey]);
  440.         // Use a global cache variable to support nested calls
  441.         static::$arrLanguageFiles[$strName][$strCacheKey] = $strLanguage;
  442.         // Backwards compatibility
  443.         if ('languages' === $strName)
  444.         {
  445.             // Reset previously loaded languages without destroying references
  446.             foreach (array_keys($GLOBALS['TL_LANG']['LNG'] ?? array()) as $strLocale)
  447.             {
  448.                 $GLOBALS['TL_LANG']['LNG'][$strLocale] = null;
  449.             }
  450.             foreach (self::getContainer()->get('contao.intl.locales')->getLocales($strCacheKey) as $strLocale => $strLabel)
  451.             {
  452.                 $GLOBALS['TL_LANG']['LNG'][$strLocale] = $strLabel;
  453.             }
  454.         }
  455.         // Backwards compatibility
  456.         if ('countries' === $strName)
  457.         {
  458.             // Reset previously loaded countries without destroying references
  459.             foreach (array_keys($GLOBALS['TL_LANG']['CNT'] ?? array()) as $strLocale)
  460.             {
  461.                 $GLOBALS['TL_LANG']['CNT'][$strLocale] = null;
  462.             }
  463.             foreach (self::getContainer()->get('contao.intl.countries')->getCountries($strCacheKey) as $strCountryCode => $strLabel)
  464.             {
  465.                 $GLOBALS['TL_LANG']['CNT'][strtolower($strCountryCode)] = $strLabel;
  466.             }
  467.         }
  468.         // Fall back to English
  469.         $arrCreateLangs = ($strLanguage == 'en') ? array('en') : array('en'$strLanguage);
  470.         // Prepare the XLIFF loader
  471.         $xlfLoader = new XliffFileLoader(static::getContainer()->getParameter('kernel.project_dir'), true);
  472.         $strCacheDir = static::getContainer()->getParameter('kernel.cache_dir');
  473.         if (null === self::$arrAvailableLanguageFiles)
  474.         {
  475.             $availLangFilesPath Path::join($strCacheDir'contao/config/available-language-files.php');
  476.             self::$arrAvailableLanguageFiles file_exists($availLangFilesPath) ? include $availLangFilesPath false;
  477.         }
  478.         // Load the language(s)
  479.         foreach ($arrCreateLangs as $strCreateLang)
  480.         {
  481.             // Skip languages that are not available (#6454)
  482.             if (\is_array(self::$arrAvailableLanguageFiles) && !isset(self::$arrAvailableLanguageFiles[$strCreateLang][$strName]))
  483.             {
  484.                 continue;
  485.             }
  486.             // Try to load from cache
  487.             if (file_exists($strCacheDir '/contao/languages/' $strCreateLang '/' $strName '.php'))
  488.             {
  489.                 include $strCacheDir '/contao/languages/' $strCreateLang '/' $strName '.php';
  490.             }
  491.             else
  492.             {
  493.                 // Find the given filename either as .php or .xlf file
  494.                 $finder = static::getContainer()->get('contao.resource_finder')->findIn('languages/' $strCreateLang)->name('/^' $strName '\.(php|xlf)$/');
  495.                 /** @var SplFileInfo $file */
  496.                 foreach ($finder as $file)
  497.                 {
  498.                     switch ($file->getExtension())
  499.                     {
  500.                         case 'php':
  501.                             include $file;
  502.                             break;
  503.                         case 'xlf':
  504.                             $xlfLoader->load($file$strCreateLang);
  505.                             break;
  506.                         default:
  507.                             throw new \RuntimeException(sprintf('Invalid language file extension: %s'$file->getExtension()));
  508.                     }
  509.                 }
  510.             }
  511.         }
  512.         // Set MSC.textDirection (see #3360)
  513.         if ('default' === $strName)
  514.         {
  515.             $GLOBALS['TL_LANG']['MSC']['textDirection'] = (\ResourceBundle::create($strLanguage'ICUDATA'true)['layout']['characters'] ?? null) === 'right-to-left' 'rtl' 'ltr';
  516.         }
  517.         // HOOK: allow loading custom labels
  518.         if (isset($GLOBALS['TL_HOOKS']['loadLanguageFile']) && \is_array($GLOBALS['TL_HOOKS']['loadLanguageFile']))
  519.         {
  520.             foreach ($GLOBALS['TL_HOOKS']['loadLanguageFile'] as $callback)
  521.             {
  522.                 static::importStatic($callback[0])->{$callback[1]}($strName$strLanguage$strCacheKey);
  523.             }
  524.         }
  525.         // Handle single quotes in the deleteConfirm message
  526.         if ($strName == 'default' && isset($GLOBALS['TL_LANG']['MSC']['deleteConfirm']))
  527.         {
  528.             $GLOBALS['TL_LANG']['MSC']['deleteConfirm'] = str_replace("'""\\'"$GLOBALS['TL_LANG']['MSC']['deleteConfirm']);
  529.         }
  530.         $projectDir self::getContainer()->getParameter('kernel.project_dir');
  531.         // Local configuration file
  532.         if (file_exists($projectDir '/system/config/langconfig.php'))
  533.         {
  534.             trigger_deprecation('contao/core-bundle''4.3''Using the "langconfig.php" file has been deprecated and will no longer work in Contao 5.0. Create custom language files in the "contao/languages" folder instead.');
  535.             include $projectDir '/system/config/langconfig.php';
  536.         }
  537.     }
  538.     /**
  539.      * Check whether a language is installed
  540.      *
  541.      * @param boolean $strLanguage The language code
  542.      *
  543.      * @return boolean True if the language is installed
  544.      */
  545.     public static function isInstalledLanguage($strLanguage)
  546.     {
  547.         if (!isset(static::$arrLanguages[$strLanguage]))
  548.         {
  549.             if (LocaleUtil::canonicalize($strLanguage) !== $strLanguage)
  550.             {
  551.                 return false;
  552.             }
  553.             $projectDir self::getContainer()->getParameter('kernel.project_dir');
  554.             if (is_dir($projectDir '/vendor/contao/core-bundle/src/Resources/contao/languages/' $strLanguage))
  555.             {
  556.                 static::$arrLanguages[$strLanguage] = true;
  557.             }
  558.             elseif (is_dir(static::getContainer()->getParameter('kernel.cache_dir') . '/contao/languages/' $strLanguage))
  559.             {
  560.                 static::$arrLanguages[$strLanguage] = true;
  561.             }
  562.             else
  563.             {
  564.                 static::$arrLanguages[$strLanguage] = static::getContainer()->get('contao.resource_finder')->findIn('languages')->depth(0)->directories()->name($strLanguage)->hasResults();
  565.             }
  566.         }
  567.         return static::$arrLanguages[$strLanguage];
  568.     }
  569.     /**
  570.      * Return the countries as array
  571.      *
  572.      * @return array An array of country names
  573.      *
  574.      * @deprecated Deprecated since Contao 4.12, to be removed in Contao 5;
  575.      *             use the Contao\CoreBundle\Intl\Countries service instead
  576.      */
  577.     public static function getCountries()
  578.     {
  579.         trigger_deprecation('contao/core-bundle''4.12''Using the %s method has been deprecated and will no longer work in Contao 5.0. Use the "contao.intl.countries" service instead.'__METHOD__);
  580.         $arrCountries self::getContainer()->get('contao.intl.countries')->getCountries();
  581.         return array_combine(array_map('strtolower'array_keys($arrCountries)), $arrCountries);
  582.     }
  583.     /**
  584.      * Return the available languages as array
  585.      *
  586.      * @param boolean $blnInstalledOnly If true, return only installed languages
  587.      *
  588.      * @return array An array of languages
  589.      *
  590.      * @deprecated Deprecated since Contao 4.12, to be removed in Contao 5;
  591.      *             use the Contao\CoreBundle\Intl\Locales service instead
  592.      */
  593.     public static function getLanguages($blnInstalledOnly=false)
  594.     {
  595.         trigger_deprecation('contao/core-bundle''4.12''Using the %s method has been deprecated and will no longer work in Contao 5.0. Use the "contao.intl.locales" service instead.'__METHOD__);
  596.         if ($blnInstalledOnly)
  597.         {
  598.             return self::getContainer()->get('contao.intl.locales')->getEnabledLocales(nulltrue);
  599.         }
  600.         return self::getContainer()->get('contao.intl.locales')->getLocales(nulltrue);
  601.     }
  602.     /**
  603.      * Return the timezones as array
  604.      *
  605.      * @return array An array of timezones
  606.      */
  607.     public static function getTimeZones()
  608.     {
  609.         trigger_deprecation('contao/core-bundle''4.13''Using the %s method has been deprecated and will no longer work in Contao 5.0. Use the DateTimeZone::listIdentifiers() instead.'__METHOD__);
  610.         $arrReturn = array();
  611.         $timezones = array();
  612.         require __DIR__ '/../../config/timezones.php';
  613.         foreach ($timezones as $strGroup=>$arrTimezones)
  614.         {
  615.             foreach ($arrTimezones as $strTimezone)
  616.             {
  617.                 $arrReturn[$strGroup][] = $strTimezone;
  618.             }
  619.         }
  620.         return $arrReturn;
  621.     }
  622.     /**
  623.      * Return all image sizes as array
  624.      *
  625.      * @return array The available image sizes
  626.      *
  627.      * @deprecated Deprecated since Contao 4.1, to be removed in Contao 5.
  628.      *             Use the contao.image.sizes service instead.
  629.      */
  630.     public static function getImageSizes()
  631.     {
  632.         trigger_deprecation('contao/core-bundle''4.1''Using "Contao\System::getImageSizes()" has been deprecated and will no longer work in Contao 5.0. Use the "contao.image.sizes" service instead.');
  633.         return static::getContainer()->get('contao.image.sizes')->getAllOptions();
  634.     }
  635.     /**
  636.      * Urlencode a file path preserving slashes
  637.      *
  638.      * @param string $strPath The file path
  639.      *
  640.      * @return string The encoded file path
  641.      */
  642.     public static function urlEncode($strPath)
  643.     {
  644.         return str_replace('%2F''/'rawurlencode((string) $strPath));
  645.     }
  646.     /**
  647.      * Set a cookie
  648.      *
  649.      * @param string       $strName     The cookie name
  650.      * @param mixed        $varValue    The cookie value
  651.      * @param integer      $intExpires  The expiration date
  652.      * @param string|null  $strPath     An optional path
  653.      * @param string|null  $strDomain   An optional domain name
  654.      * @param boolean|null $blnSecure   If true, the secure flag will be set
  655.      * @param boolean      $blnHttpOnly If true, the http-only flag will be set
  656.      */
  657.     public static function setCookie($strName$varValue$intExpires$strPath=null$strDomain=null$blnSecure=null$blnHttpOnly=false)
  658.     {
  659.         if (!$strPath)
  660.         {
  661.             $strPath Environment::get('path') ?: '/'// see #4390
  662.         }
  663.         if ($blnSecure === null)
  664.         {
  665.             $blnSecure false;
  666.             if ($request = static::getContainer()->get('request_stack')->getCurrentRequest())
  667.             {
  668.                 $blnSecure $request->isSecure();
  669.             }
  670.         }
  671.         $objCookie = new \stdClass();
  672.         $objCookie->strName     $strName;
  673.         $objCookie->varValue    $varValue;
  674.         $objCookie->intExpires  $intExpires;
  675.         $objCookie->strPath     $strPath;
  676.         $objCookie->strDomain   $strDomain;
  677.         $objCookie->blnSecure   $blnSecure;
  678.         $objCookie->blnHttpOnly $blnHttpOnly;
  679.         // HOOK: allow adding custom logic
  680.         if (isset($GLOBALS['TL_HOOKS']['setCookie']) && \is_array($GLOBALS['TL_HOOKS']['setCookie']))
  681.         {
  682.             foreach ($GLOBALS['TL_HOOKS']['setCookie'] as $callback)
  683.             {
  684.                 $objCookie = static::importStatic($callback[0])->{$callback[1]}($objCookie);
  685.             }
  686.         }
  687.         setcookie($objCookie->strName$objCookie->varValue$objCookie->intExpires$objCookie->strPath$objCookie->strDomain$objCookie->blnSecure$objCookie->blnHttpOnly);
  688.     }
  689.     /**
  690.      * Convert a byte value into a human-readable format
  691.      *
  692.      * @param integer $intSize     The size in bytes
  693.      * @param integer $intDecimals The number of decimals to show
  694.      *
  695.      * @return string The human-readable size
  696.      */
  697.     public static function getReadableSize($intSize$intDecimals=1)
  698.     {
  699.         for ($i=0$intSize>=1024$i++)
  700.         {
  701.             $intSize /= 1024;
  702.         }
  703.         return static::getFormattedNumber($intSize$intDecimals) . ' ' $GLOBALS['TL_LANG']['UNITS'][$i];
  704.     }
  705.     /**
  706.      * Format a number
  707.      *
  708.      * @param mixed   $varNumber   An integer or float number
  709.      * @param integer $intDecimals The number of decimals to show
  710.      *
  711.      * @return mixed The formatted number
  712.      */
  713.     public static function getFormattedNumber($varNumber$intDecimals=2)
  714.     {
  715.         return number_format(round($varNumber$intDecimals), $intDecimals$GLOBALS['TL_LANG']['MSC']['decimalSeparator'], $GLOBALS['TL_LANG']['MSC']['thousandsSeparator']);
  716.     }
  717.     /**
  718.      * Return the session hash
  719.      *
  720.      * @param string $strCookie The cookie name
  721.      *
  722.      * @return string The session hash
  723.      *
  724.      * @deprecated Deprecated since Contao 4.5, to be removed in Contao 5.0.
  725.      *             Use Symfony authentication instead.
  726.      */
  727.     public static function getSessionHash($strCookie)
  728.     {
  729.         trigger_deprecation('contao/core-bundle''4.5''Using "Contao\System::getSessionHash()" has been deprecated and will no longer work in Contao 5.0. Use Symfony authentication instead.');
  730.         $session = static::getContainer()->get('session');
  731.         if (!$session->isStarted())
  732.         {
  733.             $session->start();
  734.         }
  735.         return sha1($session->getId() . $strCookie);
  736.     }
  737.     /**
  738.      * Anonymize an IP address by overriding the last chunk
  739.      *
  740.      * @param string $strIp The IP address
  741.      *
  742.      * @return string The encoded IP address
  743.      */
  744.     public static function anonymizeIp($strIp)
  745.     {
  746.         // Localhost
  747.         if ($strIp == '127.0.0.1' || $strIp == '::1')
  748.         {
  749.             return $strIp;
  750.         }
  751.         // IPv6
  752.         if (strpos($strIp':') !== false)
  753.         {
  754.             return substr_replace($strIp':0000'strrpos($strIp':'));
  755.         }
  756.         // IPv4
  757.         return substr_replace($strIp'.0'strrpos($strIp'.'));
  758.     }
  759.     /**
  760.      * Read the contents of a PHP file, stripping the opening and closing PHP tags
  761.      *
  762.      * @param string $strName The name of the PHP file
  763.      *
  764.      * @return string The PHP code without the PHP tags
  765.      *
  766.      * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0.
  767.      *             Use the Contao\CoreBundle\Config\Loader\PhpFileLoader class instead.
  768.      */
  769.     protected static function readPhpFileWithoutTags($strName)
  770.     {
  771.         trigger_deprecation('contao/core-bundle''4.0''Using "Contao\System::readPhpFileWithoutTags()" has been deprecated and will no longer work in Contao 5.0. Use the "Contao\CoreBundle\Config\Loader\PhpFileLoader" class instead.');
  772.         $projectDir self::getContainer()->getParameter('kernel.project_dir');
  773.         // Convert to absolute path
  774.         if (strpos($strName$projectDir '/') === false)
  775.         {
  776.             $strName $projectDir '/' $strName;
  777.         }
  778.         $loader = new PhpFileLoader();
  779.         return $loader->load($strName);
  780.     }
  781.     /**
  782.      * Convert an .xlf file into a PHP language file
  783.      *
  784.      * @param string  $strName     The name of the .xlf file
  785.      * @param string  $strLanguage The language code
  786.      * @param boolean $blnLoad     Add the labels to the global language array
  787.      *
  788.      * @return string The PHP code
  789.      *
  790.      * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0.
  791.      *             Use the Contao\CoreBundle\Config\Loader\XliffFileLoader class instead.
  792.      */
  793.     public static function convertXlfToPhp($strName$strLanguage$blnLoad=false)
  794.     {
  795.         trigger_deprecation('contao/core-bundle''4.0''Using "Contao\System::convertXlfToPhp()" has been deprecated and will no longer work in Contao 5.0. Use the "Contao\CoreBundle\Config\Loader\XliffFileLoader" class instead.');
  796.         $projectDir self::getContainer()->getParameter('kernel.project_dir');
  797.         // Convert to absolute path
  798.         if (strpos($strName$projectDir '/') === false)
  799.         {
  800.             $strName $projectDir '/' $strName;
  801.         }
  802.         $loader = new XliffFileLoader(static::getContainer()->getParameter('kernel.project_dir'), $blnLoad);
  803.         return $loader->load($strName$strLanguage);
  804.     }
  805.     /**
  806.      * Parse a date format string and translate textual representations
  807.      *
  808.      * @param string  $strFormat The date format string
  809.      * @param integer $intTstamp An optional timestamp
  810.      *
  811.      * @return string The textual representation of the date
  812.      *
  813.      * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0.
  814.      *             Use Date::parse() instead.
  815.      */
  816.     public static function parseDate($strFormat$intTstamp=null)
  817.     {
  818.         trigger_deprecation('contao/core-bundle''4.0''Using "Contao\System::parseDate()" has been deprecated and will no longer work in Contao 5.0. Use "Contao\Date::parse()" instead.');
  819.         return Date::parse($strFormat$intTstamp);
  820.     }
  821.     /**
  822.      * Add a request string to the current URL
  823.      *
  824.      * @param string $strRequest The string to be added
  825.      *
  826.      * @return string The new URL
  827.      *
  828.      * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0.
  829.      *             Use Controller::addToUrl() instead.
  830.      */
  831.     public static function addToUrl($strRequest)
  832.     {
  833.         trigger_deprecation('contao/core-bundle''4.0''Using "Contao\System::addToUrl()" has been deprecated and will no longer work in Contao 5.0. Use "Contao\Controller::addToUrl()" instead.');
  834.         return Controller::addToUrl($strRequest);
  835.     }
  836.     /**
  837.      * Reload the current page
  838.      *
  839.      * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0.
  840.      *             Use Controller::reload() instead.
  841.      */
  842.     public static function reload()
  843.     {
  844.         trigger_deprecation('contao/core-bundle''4.0''Using "Contao\System::reload()" has been deprecated and will no longer work in Contao 5.0. Use "Contao\Controller::reload()" instead.');
  845.         Controller::reload();
  846.     }
  847.     /**
  848.      * Redirect to another page
  849.      *
  850.      * @param string  $strLocation The target URL
  851.      * @param integer $intStatus   The HTTP status code (defaults to 303)
  852.      *
  853.      * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0.
  854.      *             Use Controller::redirect() instead.
  855.      */
  856.     public static function redirect($strLocation$intStatus=303)
  857.     {
  858.         trigger_deprecation('contao/core-bundle''4.0''Using "Contao\System::redirect()" has been deprecated and will no longer work in Contao 5.0. Use "Contao\Controller::redirect()" instead.');
  859.         Controller::redirect($strLocation$intStatus);
  860.     }
  861.     /**
  862.      * Add an error message
  863.      *
  864.      * @param string $strMessage The error message
  865.      *
  866.      * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0.
  867.      *             Use Message::addError() instead.
  868.      */
  869.     protected function addErrorMessage($strMessage)
  870.     {
  871.         trigger_deprecation('contao/core-bundle''4.0''Using "Contao\System::addErrorMessage()" has been deprecated and will no longer work in Contao 5.0. Use "Contao\Message::addError()" instead.');
  872.         Message::addError($strMessage);
  873.     }
  874.     /**
  875.      * Add a confirmation message
  876.      *
  877.      * @param string $strMessage The confirmation
  878.      *
  879.      * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0.
  880.      *             Use Message::addConfirmation() instead.
  881.      */
  882.     protected function addConfirmationMessage($strMessage)
  883.     {
  884.         trigger_deprecation('contao/core-bundle''4.0''Using "Contao\System::addConfirmationMessage()" has been deprecated and will no longer work in Contao 5.0. Use "Contao\Message::addConfirmation()" instead.');
  885.         Message::addConfirmation($strMessage);
  886.     }
  887.     /**
  888.      * Add a new message
  889.      *
  890.      * @param string $strMessage The new message
  891.      *
  892.      * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0.
  893.      *             Use Message::addNew() instead.
  894.      */
  895.     protected function addNewMessage($strMessage)
  896.     {
  897.         trigger_deprecation('contao/core-bundle''4.0''Using "Contao\System::addNewMessage()" has been deprecated and will no longer work in Contao 5.0. Use "Contao\Message::addNew()" instead.');
  898.         Message::addNew($strMessage);
  899.     }
  900.     /**
  901.      * Add an info message
  902.      *
  903.      * @param string $strMessage The info message
  904.      *
  905.      * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0.
  906.      *             Use Message::addInfo() instead.
  907.      */
  908.     protected function addInfoMessage($strMessage)
  909.     {
  910.         trigger_deprecation('contao/core-bundle''4.0''Using "Contao\System::addInfoMessage()" has been deprecated and will no longer work in Contao 5.0. Use "Contao\Message::addInfo()" instead.');
  911.         Message::addInfo($strMessage);
  912.     }
  913.     /**
  914.      * Add an unformatted message
  915.      *
  916.      * @param string $strMessage The unformatted message
  917.      *
  918.      * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0.
  919.      *             Use Message::addRaw() instead.
  920.      */
  921.     protected function addRawMessage($strMessage)
  922.     {
  923.         trigger_deprecation('contao/core-bundle''4.0''Using "Contao\System::addRawMessage()" has been deprecated and will no longer work in Contao 5.0. Use "Contao\Message::addRaw()" instead.');
  924.         Message::addRaw($strMessage);
  925.     }
  926.     /**
  927.      * Add a message
  928.      *
  929.      * @param string $strMessage The message
  930.      * @param string $strType    The message type
  931.      *
  932.      * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0.
  933.      *             Use Message::add() instead.
  934.      */
  935.     protected function addMessage($strMessage$strType)
  936.     {
  937.         trigger_deprecation('contao/core-bundle''4.0''Using "Contao\System::addMessage()" has been deprecated and will no longer work in Contao 5.0. Use "Contao\Message::add()" instead.');
  938.         Message::add($strMessage$strType);
  939.     }
  940.     /**
  941.      * Return all messages as HTML
  942.      *
  943.      * @param string $strScope An optional message scope
  944.      *
  945.      * @return string The messages HTML markup
  946.      *
  947.      * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0.
  948.      *             Use Message::generate() instead.
  949.      */
  950.     protected function getMessages($strScope=null)
  951.     {
  952.         trigger_deprecation('contao/core-bundle''4.0''Using "Contao\System::getMessages()" has been deprecated and will no longer work in Contao 5.0. Use "Contao\Message::generate()" instead.');
  953.         return Message::generate($strScope ?? TL_MODE);
  954.     }
  955.     /**
  956.      * Reset the message system
  957.      *
  958.      * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0.
  959.      *             Use Message::reset() instead.
  960.      */
  961.     protected function resetMessages()
  962.     {
  963.         trigger_deprecation('contao/core-bundle''4.0''Using "Contao\System::resetMessages()" has been deprecated and will no longer work in Contao 5.0. Use "Contao\Message::reset()" instead.');
  964.         Message::reset();
  965.     }
  966.     /**
  967.      * Return all available message types
  968.      *
  969.      * @return array An array of message types
  970.      *
  971.      * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0.
  972.      *             Use Message::getTypes() instead.
  973.      */
  974.     protected function getMessageTypes()
  975.     {
  976.         trigger_deprecation('contao/core-bundle''4.0''Using "Contao\System::getMessageTypes()" has been deprecated and will no longer work in Contao 5.0. Use "Contao\Message::getTypes()" instead.');
  977.         return Message::getTypes();
  978.     }
  979.     /**
  980.      * Encode an internationalized domain name
  981.      *
  982.      * @param string $strDomain The domain name
  983.      *
  984.      * @return string The encoded domain name
  985.      *
  986.      * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0.
  987.      *             Use Idna::encode() instead.
  988.      */
  989.     protected function idnaEncode($strDomain)
  990.     {
  991.         trigger_deprecation('contao/core-bundle''4.0''Using "Contao\System::idnaEncode()" has been deprecated and will no longer work in Contao 5.0. Use "Contao\Idna::encode()" instead.');
  992.         return Idna::encode($strDomain);
  993.     }
  994.     /**
  995.      * Decode an internationalized domain name
  996.      *
  997.      * @param string $strDomain The domain name
  998.      *
  999.      * @return string The decoded domain name
  1000.      *
  1001.      * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0.
  1002.      *             Use Idna::decode() instead.
  1003.      */
  1004.     protected function idnaDecode($strDomain)
  1005.     {
  1006.         trigger_deprecation('contao/core-bundle''4.0''Using "Contao\System::idnaDecode()" has been deprecated and will no longer work in Contao 5.0. Use "Contao\Idna::decode()" instead.');
  1007.         return Idna::decode($strDomain);
  1008.     }
  1009.     /**
  1010.      * Encode the domain in an e-mail address
  1011.      *
  1012.      * @param string $strEmail The e-mail address
  1013.      *
  1014.      * @return string The encoded e-mail address
  1015.      *
  1016.      * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0.
  1017.      *             Use Idna::encodeEmail() instead.
  1018.      */
  1019.     protected function idnaEncodeEmail($strEmail)
  1020.     {
  1021.         trigger_deprecation('contao/core-bundle''4.0''Using "Contao\System::idnaEncodeEmail()" has been deprecated and will no longer work in Contao 5.0. Use "Contao\Idna::encodeEmail()" instead.');
  1022.         return Idna::encodeEmail($strEmail);
  1023.     }
  1024.     /**
  1025.      * Encode the domain in a URL
  1026.      *
  1027.      * @param string $strUrl The URL
  1028.      *
  1029.      * @return string The encoded URL
  1030.      *
  1031.      * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0.
  1032.      *             Use Idna::encodeUrl() instead.
  1033.      */
  1034.     protected function idnaEncodeUrl($strUrl)
  1035.     {
  1036.         trigger_deprecation('contao/core-bundle''4.0''Using "Contao\System::idnaEncodeUrl()" has been deprecated and will no longer work in Contao 5.0. Use "Contao\Idna::encodeUrl()" instead.');
  1037.         return Idna::encodeUrl($strUrl);
  1038.     }
  1039.     /**
  1040.      * Validate an e-mail address
  1041.      *
  1042.      * @param string $strEmail The e-mail address
  1043.      *
  1044.      * @return boolean True if it is a valid e-mail address
  1045.      *
  1046.      * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0.
  1047.      *             Use Validator::isEmail() instead.
  1048.      */
  1049.     protected function isValidEmailAddress($strEmail)
  1050.     {
  1051.         trigger_deprecation('contao/core-bundle''4.0''Using "Contao\System::isValidEmailAddress()" has been deprecated and will no longer work in Contao 5.0. Use "Contao\Validator::isEmail()" instead.');
  1052.         return Validator::isEmail($strEmail);
  1053.     }
  1054.     /**
  1055.      * Split a friendly-name e-mail address and return name and e-mail as array
  1056.      *
  1057.      * @param string $strEmail A friendly-name e-mail address
  1058.      *
  1059.      * @return array An array with name and e-mail address
  1060.      *
  1061.      * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0.
  1062.      *             Use StringUtil::splitFriendlyEmail() instead.
  1063.      */
  1064.     public static function splitFriendlyName($strEmail)
  1065.     {
  1066.         trigger_deprecation('contao/core-bundle''4.0''Using "Contao\System::splitFriendlyName()" has been deprecated and will no longer work in Contao 5.0. Use "Contao\StringUtil::splitFriendlyEmail()" instead.');
  1067.         return StringUtil::splitFriendlyEmail($strEmail);
  1068.     }
  1069.     /**
  1070.      * Return the request string without the script name
  1071.      *
  1072.      * @param boolean $blnAmpersand If true, ampersands will be encoded
  1073.      *
  1074.      * @return string The request string
  1075.      *
  1076.      * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0.
  1077.      *             Use Environment::get("indexFreeRequest") instead.
  1078.      */
  1079.     public static function getIndexFreeRequest($blnAmpersand=true)
  1080.     {
  1081.         trigger_deprecation('contao/core-bundle''4.0''Using "Contao\System::getIndexFreeRequest()" has been deprecated and will no longer work in Contao 5.0. Use "Contao\Environment::get(\'indexFreeRequest\')" instead.');
  1082.         return StringUtil::ampersand(Environment::get('indexFreeRequest'), $blnAmpersand);
  1083.     }
  1084.     /**
  1085.      * Compile a Model class name from a table name (e.g. tl_form_field becomes FormFieldModel)
  1086.      *
  1087.      * @param string $strTable The table name
  1088.      *
  1089.      * @return string The model class name
  1090.      *
  1091.      * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0.
  1092.      *             Use Model::getClassFromTable() instead.
  1093.      */
  1094.     public static function getModelClassFromTable($strTable)
  1095.     {
  1096.         trigger_deprecation('contao/core-bundle''4.0''Using "Contao\System::getModelClassFromTable()" has been deprecated and will no longer work in Contao 5.0. Use "Contao\Model::getClassFromTable()" instead.');
  1097.         return Model::getClassFromTable($strTable);
  1098.     }
  1099.     /**
  1100.      * Enable a back end module
  1101.      *
  1102.      * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0.
  1103.      *             Use Composer to add or remove modules.
  1104.      */
  1105.     public static function enableModule()
  1106.     {
  1107.         trigger_deprecation('contao/core-bundle''4.0''Using "Contao\System::enableModule()" has been deprecated and will no longer work in Contao 5.0. Use Composer to add or remove modules.');
  1108.     }
  1109.     /**
  1110.      * Disable a back end module
  1111.      *
  1112.      * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0.
  1113.      *             Use Composer to add or remove modules.
  1114.      */
  1115.     public static function disableModule()
  1116.     {
  1117.         trigger_deprecation('contao/core-bundle''4.0''Using "Contao\System::disableModule()" has been deprecated and will no longer work in Contao 5.0. Use Composer to add or remove modules.');
  1118.     }
  1119. }
  1120. class_alias(System::class, 'System');