1<?php
2
3/*
4 * This file is part of the TYPO3 CMS project.
5 *
6 * It is free software; you can redistribute it and/or modify it under
7 * the terms of the GNU General Public License, either version 2
8 * of the License, or any later version.
9 *
10 * For the full copyright and license information, please read the
11 * LICENSE.txt file that was distributed with this source code.
12 *
13 * The TYPO3 project - inspiring people to share!
14 */
15
16namespace TYPO3\CMS\Core\Core;
17
18use Composer\Autoload\ClassLoader;
19use Doctrine\Common\Annotations\AnnotationReader;
20use Doctrine\Common\Annotations\AnnotationRegistry;
21use Psr\Container\ContainerInterface;
22use Psr\EventDispatcher\EventDispatcherInterface;
23use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
24use TYPO3\CMS\Core\Cache\Backend\BackendInterface;
25use TYPO3\CMS\Core\Cache\Backend\NullBackend;
26use TYPO3\CMS\Core\Cache\Backend\Typo3DatabaseBackend;
27use TYPO3\CMS\Core\Cache\CacheManager;
28use TYPO3\CMS\Core\Cache\Exception\InvalidBackendException;
29use TYPO3\CMS\Core\Cache\Exception\InvalidCacheException;
30use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
31use TYPO3\CMS\Core\Cache\Frontend\PhpFrontend;
32use TYPO3\CMS\Core\Cache\Frontend\VariableFrontend;
33use TYPO3\CMS\Core\Configuration\ConfigurationManager;
34use TYPO3\CMS\Core\Database\TableConfigurationPostProcessingHookInterface;
35use TYPO3\CMS\Core\DependencyInjection\Cache\ContainerBackend;
36use TYPO3\CMS\Core\DependencyInjection\ContainerBuilder;
37use TYPO3\CMS\Core\Imaging\IconRegistry;
38use TYPO3\CMS\Core\IO\PharStreamWrapperInterceptor;
39use TYPO3\CMS\Core\Localization\LanguageService;
40use TYPO3\CMS\Core\Log\LogManager;
41use TYPO3\CMS\Core\Package\FailsafePackageManager;
42use TYPO3\CMS\Core\Package\PackageManager;
43use TYPO3\CMS\Core\Page\PageRenderer;
44use TYPO3\CMS\Core\Service\DependencyOrderingService;
45use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
46use TYPO3\CMS\Core\Utility\GeneralUtility;
47use TYPO3\CMS\Core\Utility\StringUtility;
48use TYPO3\PharStreamWrapper\Behavior;
49use TYPO3\PharStreamWrapper\Interceptor\ConjunctionInterceptor;
50use TYPO3\PharStreamWrapper\Interceptor\PharMetaDataInterceptor;
51use TYPO3\PharStreamWrapper\Manager;
52use TYPO3\PharStreamWrapper\PharStreamWrapper;
53
54/**
55 * This class encapsulates bootstrap related methods.
56 * It is required directly as the very first thing in entry scripts and
57 * used to define all base things like constants and paths and so on.
58 *
59 * Most methods in this class have dependencies to each other. They can
60 * not be called in arbitrary order. The methods are ordered top down, so
61 * a method at the beginning has lower dependencies than a method further
62 * down. Do not fiddle with the load order in own scripts except you know
63 * exactly what you are doing!
64 */
65class Bootstrap
66{
67    /**
68     * Bootstrap TYPO3 and return a Container that may be used
69     * to initialize an Application class.
70     *
71     * @param ClassLoader $classLoader an instance of the class loader
72     * @param bool $failsafe true if no caching and a failsafe package manager should be used
73     * @return ContainerInterface
74     */
75    public static function init(
76        ClassLoader $classLoader,
77        bool $failsafe = false
78    ): ContainerInterface {
79        $requestId = substr(md5(StringUtility::getUniqueId()), 0, 13);
80
81        static::initializeClassLoader($classLoader);
82        if (!Environment::isComposerMode() && ClassLoadingInformation::isClassLoadingInformationAvailable()) {
83            ClassLoadingInformation::registerClassLoadingInformation();
84        }
85
86        static::startOutputBuffering();
87
88        $configurationManager = static::createConfigurationManager();
89        if (!static::checkIfEssentialConfigurationExists($configurationManager)) {
90            $failsafe = true;
91        }
92        static::populateLocalConfiguration($configurationManager);
93
94        $logManager = new LogManager($requestId);
95        // LogManager is used by the core ErrorHandler (using GeneralUtility::makeInstance),
96        // therefore we have to push the LogManager to GeneralUtility, in case there
97        // happen errors before we call GeneralUtility::setContainer().
98        GeneralUtility::setSingletonInstance(LogManager::class, $logManager);
99
100        static::initializeErrorHandling();
101        static::initializeIO();
102
103        $disableCaching = $failsafe ? true : false;
104        $coreCache = static::createCache('core', $disableCaching);
105        $packageManager = static::createPackageManager(
106            $failsafe ? FailsafePackageManager::class : PackageManager::class,
107            $coreCache
108        );
109
110        // Push PackageManager instance to ExtensionManagementUtility
111        // Should be fetched through the container (later) but currently a PackageManager
112        // singleton instance is required by PackageManager->activePackageDuringRuntime
113        GeneralUtility::setSingletonInstance(PackageManager::class, $packageManager);
114        ExtensionManagementUtility::setPackageManager($packageManager);
115        static::initializeRuntimeActivatedPackagesFromConfiguration($packageManager);
116
117        static::setDefaultTimezone();
118        static::setMemoryLimit();
119
120        $assetsCache = static::createCache('assets', $disableCaching);
121        $dependencyInjectionContainerCache = static::createCache('di');
122
123        $bootState = new \stdClass();
124        $bootState->done = false;
125        $bootState->cacheDisabled = $disableCaching;
126
127        $builder = new ContainerBuilder([
128            ClassLoader::class => $classLoader,
129            ApplicationContext::class => Environment::getContext(),
130            ConfigurationManager::class => $configurationManager,
131            LogManager::class => $logManager,
132            'cache.di' => $dependencyInjectionContainerCache,
133            'cache.core' => $coreCache,
134            'cache.assets' => $assetsCache,
135            PackageManager::class => $packageManager,
136
137            // @internal
138            'boot.state' => $bootState,
139        ]);
140
141        $container = $builder->createDependencyInjectionContainer($packageManager, $dependencyInjectionContainerCache, $failsafe);
142
143        // Push the container to GeneralUtility as we want to make sure its
144        // makeInstance() method creates classes using the container from now on.
145        GeneralUtility::setContainer($container);
146
147        // Reset singleton instances in order for GeneralUtility::makeInstance() to use
148        // ContainerInterface->get() for early services from now on.
149        GeneralUtility::removeSingletonInstance(LogManager::class, $logManager);
150        GeneralUtility::removeSingletonInstance(PackageManager::class, $packageManager);
151
152        if ($failsafe) {
153            $bootState->done = true;
154            return $container;
155        }
156
157        IconRegistry::setCache($assetsCache);
158        PageRenderer::setCache($assetsCache);
159        ExtensionManagementUtility::setEventDispatcher($container->get(EventDispatcherInterface::class));
160        static::loadTypo3LoadedExtAndExtLocalconf(true, $coreCache);
161        static::unsetReservedGlobalVariables();
162        $bootState->done = true;
163        static::loadBaseTca(true, $coreCache);
164        static::checkEncryptionKey();
165
166        return $container;
167    }
168
169    /**
170     * Prevent any unwanted output that may corrupt AJAX/compression.
171     * This does not interfere with "die()" or "echo"+"exit()" messages!
172     *
173     * @internal This is not a public API method, do not use in own extensions
174     */
175    public static function startOutputBuffering()
176    {
177        ob_start();
178    }
179
180    /**
181     * Run the base setup that checks server environment, determines paths,
182     * populates base files and sets common configuration.
183     *
184     * Script execution will be aborted if something fails here.
185     *
186     * @throws \RuntimeException when TYPO3_REQUESTTYPE was not set before, setRequestType() needs to be called before
187     * @internal This is not a public API method, do not use in own extensions
188     */
189    public static function baseSetup()
190    {
191        if (!defined('TYPO3_REQUESTTYPE')) {
192            throw new \RuntimeException('No Request Type was set, TYPO3 does not know in which context it is run.', 1450561838);
193        }
194        if (!Environment::isComposerMode() && ClassLoadingInformation::isClassLoadingInformationAvailable()) {
195            ClassLoadingInformation::registerClassLoadingInformation();
196        }
197    }
198
199    /**
200     * Sets the class loader to the bootstrap
201     *
202     * @param ClassLoader $classLoader an instance of the class loader
203     * @internal This is not a public API method, do not use in own extensions
204     */
205    public static function initializeClassLoader(ClassLoader $classLoader)
206    {
207        ClassLoadingInformation::setClassLoader($classLoader);
208
209        /** @see initializeAnnotationRegistry */
210        AnnotationRegistry::registerLoader([$classLoader, 'loadClass']);
211
212        // Annotations used in unit tests
213        AnnotationReader::addGlobalIgnoredName('test');
214
215        // Annotations that control the extension scanner
216        AnnotationReader::addGlobalIgnoredName('extensionScannerIgnoreFile');
217        AnnotationReader::addGlobalIgnoredName('extensionScannerIgnoreLine');
218    }
219
220    /**
221     * checks if LocalConfiguration.php or PackageStates.php is missing,
222     * used to see if a redirect to the install tool is needed
223     *
224     * @param ConfigurationManager $configurationManager
225     * @return bool TRUE when the essential configuration is available, otherwise FALSE
226     * @internal This is not a public API method, do not use in own extensions
227     */
228    protected static function checkIfEssentialConfigurationExists(ConfigurationManager $configurationManager): bool
229    {
230        return file_exists($configurationManager->getLocalConfigurationFileLocation())
231            && file_exists(Environment::getLegacyConfigPath() . '/PackageStates.php');
232    }
233
234    /**
235     * Initializes the package system and loads the package configuration and settings
236     * provided by the packages.
237     *
238     * @param string $packageManagerClassName Define an alternative package manager implementation (usually for the installer)
239     * @param FrontendInterface $coreCache
240     * @return PackageManager
241     * @internal This is not a public API method, do not use in own extensions
242     */
243    public static function createPackageManager($packageManagerClassName, FrontendInterface $coreCache): PackageManager
244    {
245        $dependencyOrderingService = GeneralUtility::makeInstance(DependencyOrderingService::class);
246        /** @var \TYPO3\CMS\Core\Package\PackageManager $packageManager */
247        $packageManager = new $packageManagerClassName($dependencyOrderingService);
248        $packageManager->injectCoreCache($coreCache);
249        $packageManager->initialize();
250
251        return $packageManager;
252    }
253
254    /**
255     * Activates a package during runtime. This is used in AdditionalConfiguration.php
256     * to enable extensions under conditions.
257     *
258     * @param PackageManager $packageManager
259     */
260    protected static function initializeRuntimeActivatedPackagesFromConfiguration(PackageManager $packageManager)
261    {
262        $packages = $GLOBALS['TYPO3_CONF_VARS']['EXT']['runtimeActivatedPackages'] ?? [];
263        if (!empty($packages)) {
264            trigger_error('Support for runtime activated packages will be removed in TYPO3 v11.0.', E_USER_DEPRECATED);
265            foreach ($packages as $runtimeAddedPackageKey) {
266                $packageManager->activatePackageDuringRuntime($runtimeAddedPackageKey);
267            }
268        }
269    }
270
271    /**
272     * Load ext_localconf of extensions
273     *
274     * @param bool $allowCaching
275     * @param FrontendInterface $coreCache
276     * @internal This is not a public API method, do not use in own extensions
277     */
278    public static function loadTypo3LoadedExtAndExtLocalconf($allowCaching = true, FrontendInterface $coreCache = null)
279    {
280        if ($allowCaching) {
281            $coreCache = $coreCache ?? GeneralUtility::makeInstance(CacheManager::class)->getCache('core');
282        }
283        ExtensionManagementUtility::loadExtLocalconf($allowCaching, $coreCache);
284    }
285
286    /**
287     * We need an early instance of the configuration manager.
288     * Since makeInstance relies on the object configuration, we create it here with new instead.
289     *
290     * @return ConfigurationManager
291     */
292    public static function createConfigurationManager(): ConfigurationManager
293    {
294        return new ConfigurationManager();
295    }
296
297    /**
298     * We need an early instance of the configuration manager.
299     * Since makeInstance relies on the object configuration, we create it here with new instead.
300     *
301     * @param ConfigurationManager $configurationManager
302     * @internal This is not a public API method, do not use in own extensions
303     */
304    protected static function populateLocalConfiguration(ConfigurationManager $configurationManager)
305    {
306        $configurationManager->exportConfiguration();
307    }
308
309    /**
310     * Instantiates an early cache instance
311     *
312     * Creates a cache instances independently from the CacheManager.
313     * The is used to create the core cache during early bootstrap when the CacheManager
314     * is not yet available (i.e. configuration is not yet loaded).
315     *
316     * @param string $identifier
317     * @param bool $disableCaching
318     * @return FrontendInterface
319     * @internal
320     */
321    public static function createCache(string $identifier, bool $disableCaching = false): FrontendInterface
322    {
323        $cacheConfigurations = $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations'] ?? [];
324        $cacheConfigurations['di']['frontend'] = PhpFrontend::class;
325        $cacheConfigurations['di']['backend'] = ContainerBackend::class;
326        $cacheConfigurations['di']['options'] = [];
327        $configuration = $cacheConfigurations[$identifier] ?? [];
328
329        $frontend = $configuration['frontend'] ?? VariableFrontend::class;
330        $backend = $configuration['backend'] ?? Typo3DatabaseBackend::class;
331        $options = $configuration['options'] ?? [];
332
333        if ($disableCaching) {
334            $backend = NullBackend::class;
335            $options = [];
336        }
337
338        $backendInstance = new $backend('production', $options);
339        if (!$backendInstance instanceof BackendInterface) {
340            throw new InvalidBackendException('"' . $backend . '" is not a valid cache backend object.', 1545260108);
341        }
342        if (is_callable([$backendInstance, 'initializeObject'])) {
343            $backendInstance->initializeObject();
344        }
345
346        $frontendInstance = new $frontend($identifier, $backendInstance);
347        if (!$frontendInstance instanceof FrontendInterface) {
348            throw new InvalidCacheException('"' . $frontend . '" is not a valid cache frontend object.', 1545260109);
349        }
350        if (is_callable([$frontendInstance, 'initializeObject'])) {
351            $frontendInstance->initializeObject();
352        }
353
354        return $frontendInstance;
355    }
356
357    /**
358     * Set default timezone
359     */
360    protected static function setDefaultTimezone()
361    {
362        $timeZone = $GLOBALS['TYPO3_CONF_VARS']['SYS']['phpTimeZone'];
363        if (empty($timeZone)) {
364            // Time zone from the server environment (TZ env or OS query)
365            $defaultTimeZone = @date_default_timezone_get();
366            if ($defaultTimeZone !== '') {
367                $timeZone = $defaultTimeZone;
368            } else {
369                $timeZone = 'UTC';
370            }
371        }
372        // Set default to avoid E_WARNINGs with PHP > 5.3
373        date_default_timezone_set($timeZone);
374    }
375
376    /**
377     * Configure and set up exception and error handling
378     *
379     * @throws \RuntimeException
380     */
381    protected static function initializeErrorHandling()
382    {
383        static::initializeBasicErrorReporting();
384        $displayErrors = 0;
385        $exceptionHandlerClassName = null;
386        $productionExceptionHandlerClassName = $GLOBALS['TYPO3_CONF_VARS']['SYS']['productionExceptionHandler'];
387        $debugExceptionHandlerClassName = $GLOBALS['TYPO3_CONF_VARS']['SYS']['debugExceptionHandler'];
388
389        $errorHandlerClassName = $GLOBALS['TYPO3_CONF_VARS']['SYS']['errorHandler'];
390        $errorHandlerErrors = $GLOBALS['TYPO3_CONF_VARS']['SYS']['errorHandlerErrors'] | E_USER_DEPRECATED;
391        $exceptionalErrors = $GLOBALS['TYPO3_CONF_VARS']['SYS']['exceptionalErrors'];
392
393        $displayErrorsSetting = (int)$GLOBALS['TYPO3_CONF_VARS']['SYS']['displayErrors'];
394        switch ($displayErrorsSetting) {
395            case -1:
396                $ipMatchesDevelopmentSystem = GeneralUtility::cmpIP(GeneralUtility::getIndpEnv('REMOTE_ADDR'), $GLOBALS['TYPO3_CONF_VARS']['SYS']['devIPmask']);
397                $exceptionHandlerClassName = $ipMatchesDevelopmentSystem ? $debugExceptionHandlerClassName : $productionExceptionHandlerClassName;
398                $displayErrors = $ipMatchesDevelopmentSystem ? 1 : 0;
399                $exceptionalErrors = $ipMatchesDevelopmentSystem ? $exceptionalErrors : 0;
400                break;
401            case 0:
402                $exceptionHandlerClassName = $productionExceptionHandlerClassName;
403                $displayErrors = 0;
404                break;
405            case 1:
406                $exceptionHandlerClassName = $debugExceptionHandlerClassName;
407                $displayErrors = 1;
408                break;
409            default:
410                if (!(TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_INSTALL)) {
411                    // Throw exception if an invalid option is set.
412                    throw new \RuntimeException(
413                        'The option $TYPO3_CONF_VARS[SYS][displayErrors] is not set to "-1", "0" or "1".',
414                        1476046290
415                    );
416                }
417        }
418        @ini_set('display_errors', (string)$displayErrors);
419
420        if (!empty($errorHandlerClassName)) {
421            // Register an error handler for the given errorHandlerError
422            $errorHandler = GeneralUtility::makeInstance($errorHandlerClassName, $errorHandlerErrors);
423            $errorHandler->setExceptionalErrors($exceptionalErrors);
424            if (is_callable([$errorHandler, 'setDebugMode'])) {
425                $errorHandler->setDebugMode($displayErrors === 1);
426            }
427            if (is_callable([$errorHandler, 'registerErrorHandler'])) {
428                $errorHandler->registerErrorHandler();
429            }
430        }
431        if (!empty($exceptionHandlerClassName)) {
432            // Registering the exception handler is done in the constructor
433            GeneralUtility::makeInstance($exceptionHandlerClassName);
434        }
435    }
436
437    /**
438     * Initialize basic error reporting.
439     *
440     * There are a lot of extensions that have no strict / notice / deprecated free
441     * ext_localconf or ext_tables. Since the final error reporting must be set up
442     * after those extension files are read, a default configuration is needed to
443     * suppress error reporting meanwhile during further bootstrap.
444     *
445     * Please note: if you comment out this code, TYPO3 would never set any error reporting
446     * which would need to have TYPO3 Core and ALL used extensions to be notice free and deprecation
447     * free. However, commenting this out and running functional and acceptance tests shows what
448     * needs to be done to make TYPO3 Core mostly notice-free (unit tests do not execute this code here).
449     */
450    protected static function initializeBasicErrorReporting(): void
451    {
452        // Core should be notice free at least until this point ...
453        error_reporting(E_ALL & ~(E_STRICT | E_NOTICE | E_DEPRECATED));
454    }
455
456    /**
457     * Initializes IO and stream wrapper related behavior.
458     */
459    protected static function initializeIO()
460    {
461        if (in_array('phar', stream_get_wrappers())) {
462            // destroy and re-initialize PharStreamWrapper for TYPO3 core
463            Manager::destroy();
464            Manager::initialize(
465                (new Behavior())
466                    ->withAssertion(new ConjunctionInterceptor([
467                        new PharStreamWrapperInterceptor(),
468                        new PharMetaDataInterceptor()
469                    ]))
470            );
471
472            stream_wrapper_unregister('phar');
473            stream_wrapper_register('phar', PharStreamWrapper::class);
474        }
475    }
476
477    /**
478     * Set PHP memory limit depending on value of
479     * $GLOBALS['TYPO3_CONF_VARS']['SYS']['setMemoryLimit']
480     */
481    protected static function setMemoryLimit()
482    {
483        if ((int)$GLOBALS['TYPO3_CONF_VARS']['SYS']['setMemoryLimit'] > 16) {
484            @ini_set('memory_limit', (string)((int)$GLOBALS['TYPO3_CONF_VARS']['SYS']['setMemoryLimit'] . 'm'));
485        }
486    }
487
488    /**
489     * Unsetting reserved global variables:
490     * Those are set in "ext:core/ext_tables.php" file:
491     *
492     * @internal This is not a public API method, do not use in own extensions
493     */
494    public static function unsetReservedGlobalVariables()
495    {
496        unset($GLOBALS['PAGES_TYPES']);
497        unset($GLOBALS['TCA']);
498        unset($GLOBALS['TBE_MODULES']);
499        unset($GLOBALS['TBE_STYLES']);
500        unset($GLOBALS['BE_USER']);
501        // Those set otherwise:
502        unset($GLOBALS['TBE_MODULES_EXT']);
503        unset($GLOBALS['TCA_DESCR']);
504        unset($GLOBALS['LOCAL_LANG']);
505    }
506
507    /**
508     * Load $TCA
509     *
510     * This will mainly set up $TCA through extMgm API.
511     *
512     * @param bool $allowCaching True, if loading TCA from cache is allowed
513     * @param FrontendInterface $coreCache
514     * @internal This is not a public API method, do not use in own extensions
515     */
516    public static function loadBaseTca(bool $allowCaching = true, FrontendInterface $coreCache = null)
517    {
518        if ($allowCaching) {
519            $coreCache = $coreCache ?? GeneralUtility::makeInstance(CacheManager::class)->getCache('core');
520        }
521        ExtensionManagementUtility::loadBaseTca($allowCaching, $coreCache);
522    }
523
524    /**
525     * Check if a configuration key has been configured
526     */
527    protected static function checkEncryptionKey()
528    {
529        if (empty($GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'])) {
530            throw new \RuntimeException(
531                'TYPO3 Encryption is empty. $GLOBALS[\'TYPO3_CONF_VARS\'][\'SYS\'][\'encryptionKey\'] needs to be set for TYPO3 to work securely',
532                1502987245
533            );
534        }
535    }
536
537    /**
538     * Load ext_tables and friends.
539     *
540     * This will mainly load and execute ext_tables.php files of loaded extensions
541     * or the according cache file if exists.
542     *
543     * @param bool $allowCaching True, if reading compiled ext_tables file from cache is allowed
544     * @internal This is not a public API method, do not use in own extensions
545     */
546    public static function loadExtTables(bool $allowCaching = true)
547    {
548        ExtensionManagementUtility::loadExtTables($allowCaching);
549        static::runExtTablesPostProcessingHooks();
550    }
551
552    /**
553     * Check for registered ext tables hooks and run them
554     *
555     * @throws \UnexpectedValueException
556     */
557    protected static function runExtTablesPostProcessingHooks()
558    {
559        foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['extTablesInclusion-PostProcessing'] ?? [] as $className) {
560            /** @var \TYPO3\CMS\Core\Database\TableConfigurationPostProcessingHookInterface $hookObject */
561            $hookObject = GeneralUtility::makeInstance($className);
562            if (!$hookObject instanceof TableConfigurationPostProcessingHookInterface) {
563                throw new \UnexpectedValueException(
564                    '$hookObject "' . $className . '" must implement interface TYPO3\\CMS\\Core\\Database\\TableConfigurationPostProcessingHookInterface',
565                    1320585902
566                );
567            }
568            $hookObject->processData();
569        }
570    }
571
572    /**
573     * Initialize the Routing for the TYPO3 Backend
574     * Loads all routes registered inside all packages and stores them inside the Router
575     *
576     * @internal This is not a public API method, do not use in own extensions
577     * @deprecated this does not do anything anymore, as TYPO3's dependency injection already loads the routes on demand.
578     */
579    public static function initializeBackendRouter()
580    {
581        // TODO: Once typo3/testing-framework is adapted, this code can be dropped / deprecated. As DI is already
582        // loading all routes on demand, this method is not needed anymore.
583    }
584
585    /**
586     * Initialize backend user object in globals
587     *
588     * @param string $className usually \TYPO3\CMS\Core\Authentication\BackendUserAuthentication::class but can be used for CLI
589     * @internal This is not a public API method, do not use in own extensions
590     */
591    public static function initializeBackendUser($className = BackendUserAuthentication::class)
592    {
593        /** @var \TYPO3\CMS\Core\Authentication\BackendUserAuthentication $backendUser */
594        $backendUser = GeneralUtility::makeInstance($className);
595        // The global must be available very early, because methods below
596        // might trigger code which relies on it. See: #45625
597        $GLOBALS['BE_USER'] = $backendUser;
598        $backendUser->start();
599    }
600
601    /**
602     * Initializes and ensures authenticated access
603     *
604     * @internal This is not a public API method, do not use in own extensions
605     * @param bool $proceedIfNoUserIsLoggedIn if set to TRUE, no forced redirect to the login page will be done
606     */
607    public static function initializeBackendAuthentication($proceedIfNoUserIsLoggedIn = false)
608    {
609        $GLOBALS['BE_USER']->backendCheckLogin($proceedIfNoUserIsLoggedIn);
610    }
611
612    /**
613     * Initialize language object
614     *
615     * @internal This is not a public API method, do not use in own extensions
616     */
617    public static function initializeLanguageObject()
618    {
619        /** @var \TYPO3\CMS\Core\Localization\LanguageService $GLOBALS['LANG'] */
620        $GLOBALS['LANG'] = LanguageService::createFromUserPreferences($GLOBALS['BE_USER']);
621    }
622}
623