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

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($strClass, null, null, 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($strClass, null, null, 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($strClass, null, null, 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($strClass, null, null, 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('?', $url, 2);
  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 (1 !== 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($strLanguage, 0, 2);
  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(null, true);
  599. }
  600. return self::getContainer()->get('contao.intl.locales')->getLocales(null, true);
  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');