exportConfiguration(); $logManager = new LogManager($requestId); // LogManager is used by the core ErrorHandler (using GeneralUtility::makeInstance), // therefore we have to push the LogManager to GeneralUtility, in case there // happen errors before we call GeneralUtility::setContainer(). GeneralUtility::setSingletonInstance(LogManager::class, $logManager); static::initializeErrorHandling(); $disableCaching = $failsafe ? true : false; /** @var PhpFrontend $coreCache */ $coreCache = static::createCache('core', $disableCaching); $packageCache = static::createPackageCache($coreCache); $packageManager = static::createPackageManager( $failsafe ? FailsafePackageManager::class : PackageManager::class, $packageCache ); static::setDefaultTimezone(); static::setMemoryLimit(); $dependencyInjectionContainerCache = static::createCache('di'); $bootState = new \stdClass(); $bootState->complete = false; $bootState->cacheDisabled = $disableCaching; $builder = new ContainerBuilder([ ClassLoader::class => $classLoader, ApplicationContext::class => Environment::getContext(), ConfigurationManager::class => $configurationManager, LogManager::class => $logManager, RequestId::class => $requestId, 'cache.di' => $dependencyInjectionContainerCache, 'cache.core' => $coreCache, PackageManager::class => $packageManager, // @internal 'boot.state' => $bootState, ]); $container = $builder->createDependencyInjectionContainer($packageManager, $dependencyInjectionContainerCache, $failsafe); // Push the container to GeneralUtility as we want to make sure its // makeInstance() method creates classes using the container from now on. GeneralUtility::setContainer($container); // Reset LogManager singleton instance in order for GeneralUtility::makeInstance() // to proxy LogManager retrieval to ContainerInterface->get() from now on. GeneralUtility::removeSingletonInstance(LogManager::class, $logManager); // Push PackageManager instance to ExtensionManagementUtility ExtensionManagementUtility::setPackageManager($packageManager); if ($failsafe) { $bootState->complete = true; return $container; } // The encryption key is part of the system configuration and must be set up // before any extension code is executed. static::checkEncryptionKey(); $eventDispatcher = $container->get(EventDispatcherInterface::class); $container->get(ExtLocalconfFactory::class)->load(); $tca = $container->get(TcaFactory::class)->get(); $bootState->complete = true; // $GLOBALS['TCA'] is only published once the schema is built, so consumers // triggered by the schema factory can not work with a half-initialized state. $container->get(TcaSchemaFactory::class)->load($tca); $GLOBALS['TCA'] = $tca; $eventDispatcher->dispatch(new BootCompletedEvent(true)); return $container; } /** * Sets the class loader to the bootstrap * * @param ClassLoader $classLoader an instance of the class loader * @internal This is not a public API method, do not use in own extensions */ public static function initializeClassLoader(ClassLoader $classLoader): void { ClassLoadingInformation::setClassLoader($classLoader); } /** * checks if config/system/settings.php or PackageStates.php is missing, * used to see if a redirect to the installer is needed * * All file_exists checks are delayed as far as possible to avoid I/O impact * * @return bool TRUE when the essential configuration is available, otherwise FALSE * @internal This is not a public API method, do not use in own extensions */ public static function checkIfEssentialConfigurationExists(ConfigurationManager $configurationManager): bool { if (!Environment::isComposerMode() && !file_exists(Environment::getPackageStatesFile()) ) { // Early return in case system is not properly set up return false; } // The system configuration file (settings.php) is mandatory, the additional configuration // file (additional.php) is optional. return file_exists($configurationManager->getSystemConfigurationFileLocation()); } /** * Initializes the package system and loads the package configuration and settings * provided by the packages. * * @param string $packageManagerClassName Define an alternative package manager implementation (usually for the installer) * @internal This is not a public API method, do not use in own extensions */ public static function createPackageManager($packageManagerClassName, PackageCacheInterface $packageCache): PackageManager { $dependencyOrderingService = GeneralUtility::makeInstance(DependencyOrderingService::class); /** @var PackageManager $packageManager */ $packageManager = new $packageManagerClassName($dependencyOrderingService); $packageManager->setPackageCache($packageCache); $packageManager->initialize(); return $packageManager; } /** * @internal */ public static function createPackageCache(FrontendInterface $coreCache): PackageCacheInterface { if (!Environment::isComposerMode()) { return new PackageStatesPackageCache(Environment::getPackageStatesFile(), $coreCache); } $composerInstallersPath = InstalledVersions::getInstallPath('typo3/cms-composer-installers'); if ($composerInstallersPath === null) { throw new \RuntimeException('Package "typo3/cms-composer-installers" not found. Replacing the package is not allowed. Fork the package instead and pull in the fork with the same name.', 1636145677); } return new ComposerPackageArtifact(dirname($composerInstallersPath)); } /** * Instantiates an early cache instance * * Creates a cache instances independently of the CacheManager. * The is used to create the core cache during early bootstrap when the CacheManager * is not yet available (i.e. configuration is not yet loaded). * * @param class-string|null $enforcedCacheBackend * @internal */ public static function createCache( string $identifier, bool $disableCaching = false, ?string $enforcedCacheBackend = null ): FrontendInterface { $cacheConfigurations = $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations'] ?? []; $cacheConfigurations['di']['frontend'] = PhpFrontend::class; $cacheConfigurations['di']['backend'] = ContainerBackend::class; $cacheConfigurations['di']['options'] = []; $configuration = $cacheConfigurations[$identifier] ?? []; $frontend = $configuration['frontend'] ?? VariableFrontend::class; $backend = $enforcedCacheBackend ?? $configuration['backend'] ?? Typo3DatabaseBackend::class; $options = $configuration['options'] ?? []; if ($disableCaching) { $backend = NullBackend::class; $options = []; } $backendInstance = new $backend($options); if (!$backendInstance instanceof BackendInterface) { throw new InvalidBackendException('"' . $backend . '" is not a valid cache backend object.', 1545260108); } if (is_callable([$backendInstance, 'initializeObject'])) { $backendInstance->initializeObject(); } $frontendInstance = new $frontend($identifier, $backendInstance); if (!$frontendInstance instanceof FrontendInterface) { throw new InvalidCacheException('"' . $frontend . '" is not a valid cache frontend object.', 1545260109); } if (is_callable([$frontendInstance, 'initializeObject'])) { $frontendInstance->initializeObject(); } return $frontendInstance; } /** * Set default timezone */ protected static function setDefaultTimezone(): void { $timeZone = $GLOBALS['TYPO3_CONF_VARS']['SYS']['phpTimeZone']; if (empty($timeZone)) { // Time zone from the server environment (TZ env or OS query) $defaultTimeZone = @date_default_timezone_get(); if ($defaultTimeZone !== '') { $timeZone = $defaultTimeZone; } else { $timeZone = 'UTC'; } } // Set default to avoid E_WARNINGs with PHP > 5.3 date_default_timezone_set($timeZone); } /** * Configure and set up exception and error handling */ protected static function initializeErrorHandling(): void { $productionExceptionHandlerClassName = $GLOBALS['TYPO3_CONF_VARS']['SYS']['productionExceptionHandler']; $debugExceptionHandlerClassName = $GLOBALS['TYPO3_CONF_VARS']['SYS']['debugExceptionHandler']; $errorHandlerClassName = $GLOBALS['TYPO3_CONF_VARS']['SYS']['errorHandler']; $errorHandlerErrors = $GLOBALS['TYPO3_CONF_VARS']['SYS']['errorHandlerErrors'] | E_USER_DEPRECATED; $exceptionalErrors = $GLOBALS['TYPO3_CONF_VARS']['SYS']['exceptionalErrors']; $displayErrorsSetting = (int)$GLOBALS['TYPO3_CONF_VARS']['SYS']['displayErrors']; switch ($displayErrorsSetting) { case -1: $ipMatchesDevelopmentSystem = GeneralUtility::cmpIP(NormalizedParams::createFromServerParams($_SERVER)->getRemoteAddress(), $GLOBALS['TYPO3_CONF_VARS']['SYS']['devIPmask']); $exceptionHandlerClassName = $ipMatchesDevelopmentSystem ? $debugExceptionHandlerClassName : $productionExceptionHandlerClassName; $displayErrors = $ipMatchesDevelopmentSystem ? 1 : 0; $exceptionalErrors = $ipMatchesDevelopmentSystem ? $exceptionalErrors : 0; break; case 0: $exceptionHandlerClassName = $productionExceptionHandlerClassName; $displayErrors = 0; break; case 1: $exceptionHandlerClassName = $debugExceptionHandlerClassName; $displayErrors = 1; break; default: // Throw exception if an invalid option is set. A default for displayErrors is set // in very early install tool, coming from DefaultConfiguration.php. It is safe here // to just throw if there is no value for whatever reason. throw new \RuntimeException( 'The option $TYPO3_CONF_VARS[SYS][displayErrors] is not set to "-1", "0" or "1".', 1476046290 ); } @ini_set('display_errors', (string)$displayErrors); if (!empty($errorHandlerClassName)) { // Register an error handler for the given errorHandlerError $errorHandler = GeneralUtility::makeInstance($errorHandlerClassName, $errorHandlerErrors); $errorHandler->setExceptionalErrors($exceptionalErrors); if (is_callable([$errorHandler, 'setDebugMode'])) { $errorHandler->setDebugMode($displayErrors === 1); } if (is_callable([$errorHandler, 'registerErrorHandler'])) { $errorHandler->registerErrorHandler(); } } if (!empty($exceptionHandlerClassName)) { // Registering the exception handler is done in the constructor GeneralUtility::makeInstance($exceptionHandlerClassName); } } /** * Set PHP memory limit depending on value of * $GLOBALS['TYPO3_CONF_VARS']['SYS']['setMemoryLimit'] */ protected static function setMemoryLimit(): void { if ((int)$GLOBALS['TYPO3_CONF_VARS']['SYS']['setMemoryLimit'] > 16) { @ini_set('memory_limit', (string)((int)$GLOBALS['TYPO3_CONF_VARS']['SYS']['setMemoryLimit'] . 'm')); } } /** * Check if a configuration key has been configured */ protected static function checkEncryptionKey(): void { if (empty($GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'])) { throw new \RuntimeException( 'TYPO3 Encryption is empty. $GLOBALS[\'TYPO3_CONF_VARS\'][\'SYS\'][\'encryptionKey\'] needs to be set for TYPO3 to work securely', 1502987245 ); } } /** * Initialize backend user object in globals * * @param string $className usually \TYPO3\CMS\Core\Authentication\BackendUserAuthentication::class but can be used for CLI */ public static function initializeBackendUser($className = BackendUserAuthentication::class, ?ServerRequestInterface $request = null): BackendUserAuthentication { /** @var BackendUserAuthentication $backendUser */ $backendUser = GeneralUtility::makeInstance($className); // The global must be available very early, because methods below // might trigger code which relies on it. See: #45625 $GLOBALS['BE_USER'] = $backendUser; $backendUser->start($request); return $backendUser; } /** * Initializes and ensures authenticated access */ public static function initializeBackendAuthentication(): void { $GLOBALS['BE_USER']->backendCheckLogin(); } }