‪TYPO3CMS  11.5
InstallerController.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
20 use Doctrine\DBAL\DriverManager;
21 use Doctrine\DBAL\Exception as DBALException;
22 use Doctrine\DBAL\Exception\ConnectionException;
23 use Psr\Http\Message\ResponseInterface;
24 use Psr\Http\Message\ServerRequestInterface;
27 use TYPO3\CMS\Core\Configuration\ConfigurationManager;
73 
79 {
83  private ‪$lateBootService;
84 
89 
94 
99 
103  private ‪$siteConfiguration;
104 
108  private ‪$registry;
109 
113  private ‪$packageManager;
114 
118  private ‪$verifyHostHeader;
119 
124 
125  public function ‪__construct(
129  ConfigurationManager ‪$configurationManager,
135  ) {
136  $this->lateBootService = ‪$lateBootService;
137  $this->silentConfigurationUpgradeService = ‪$silentConfigurationUpgradeService;
138  $this->silentTemplateFileUpgradeService = ‪$silentTemplateFileUpgradeService;
139  $this->configurationManager = ‪$configurationManager;
140  $this->siteConfiguration = ‪$siteConfiguration;
141  $this->registry = ‪$registry;
142  $this->packageManager = ‪$packageManager;
143  $this->verifyHostHeader = ‪$verifyHostHeader;
144  $this->databasePermissionsCheck = ‪$databasePermissionsCheck;
145  }
146 
152  public function ‪initAction(): ResponseInterface
153  {
154  $bust = ‪$GLOBALS['EXEC_TIME'];
155  if (!‪Environment::getContext()->isDevelopment()) {
156  $bust = GeneralUtility::hmac((string)(new ‪Typo3Version()) . ‪Environment::getProjectPath());
157  }
158  $view = $this->‪initializeStandaloneView('Installer/Init.html');
159  $view->assign('bust', $bust);
160  $view->assign('packageResourcePaths', [
161  'backend' => ‪PathUtility::getPublicResourceWebPath('EXT:backend/Resources/Public/'),
162  'core' => ‪PathUtility::getPublicResourceWebPath('EXT:core/Resources/Public/'),
163  'install' => ‪PathUtility::getPublicResourceWebPath('EXT:install/Resources/Public/'),
164  ]);
165  return new HtmlResponse(
166  $view->render(),
167  200,
168  [
169  'Cache-Control' => 'no-cache, no-store',
170  'Pragma' => 'no-cache',
171  ]
172  );
173  }
174 
180  public function ‪mainLayoutAction(): ResponseInterface
181  {
182  $view = $this->‪initializeStandaloneView('Installer/MainLayout.html');
183  return new ‪JsonResponse([
184  'success' => true,
185  'html' => $view->render(),
186  ]);
187  }
188 
194  public function ‪showInstallerNotAvailableAction(): ResponseInterface
195  {
196  $view = $this->‪initializeStandaloneView('Installer/ShowInstallerNotAvailable.html');
197  return new ‪JsonResponse([
198  'success' => true,
199  'html' => $view->render(),
200  ]);
201  }
202 
208  public function ‪checkEnvironmentAndFoldersAction(): ResponseInterface
209  {
210  return new ‪JsonResponse([
211  'success' => @is_file($this->configurationManager->getLocalConfigurationFileLocation()),
212  ]);
213  }
214 
220  public function ‪showEnvironmentAndFoldersAction(): ResponseInterface
221  {
222  $view = $this->‪initializeStandaloneView('Installer/ShowEnvironmentAndFolders.html');
223  $systemCheckMessageQueue = new ‪FlashMessageQueue('install');
224  $checkMessages = (new ‪Check())->getStatus();
225  foreach ($checkMessages as $message) {
226  $systemCheckMessageQueue->enqueue($message);
227  }
228  $setupCheckMessages = (new SetupCheck())->getStatus();
229  foreach ($setupCheckMessages as $message) {
230  $systemCheckMessageQueue->enqueue($message);
231  }
232  $folderStructureFactory = GeneralUtility::makeInstance(DefaultFactory::class);
233  $structureFacade = $folderStructureFactory->getStructure();
234  $structureMessageQueue = $structureFacade->getStatus();
235  return new JsonResponse([
236  'success' => true,
237  'html' => $view->render(),
238  'environmentStatusErrors' => $systemCheckMessageQueue->getAllMessages(‪FlashMessage::ERROR),
239  'environmentStatusWarnings' => $systemCheckMessageQueue->getAllMessages(‪FlashMessage::WARNING),
240  'structureErrors' => $structureMessageQueue->getAllMessages(‪FlashMessage::ERROR),
241  ]);
242  }
243 
249  public function ‪executeEnvironmentAndFoldersAction(): ResponseInterface
250  {
251  $folderStructureFactory = GeneralUtility::makeInstance(DefaultFactory::class);
252  $structureFacade = $folderStructureFactory->getStructure();
253  $structureFixMessageQueue = $structureFacade->fix();
254  $errorsFromStructure = $structureFixMessageQueue->getAllMessages(‪FlashMessage::ERROR);
255 
256  if (@is_dir(‪Environment::getLegacyConfigPath())) {
257  $this->configurationManager->createLocalConfigurationFromFactoryConfiguration();
258  // Create a PackageStates.php with all packages activated marked as "part of factory default"
259  $this->packageManager->recreatePackageStatesFileIfMissing(true);
260  $extensionConfiguration = new ‪ExtensionConfiguration();
261  $extensionConfiguration->synchronizeExtConfTemplateWithLocalConfigurationOfAllExtensions();
262 
263  return new ‪JsonResponse([
264  'success' => true,
265  ]);
266  }
267  return new JsonResponse([
268  'success' => false,
269  'status' => $errorsFromStructure,
270  ]);
271  }
272 
279  public function ‪checkTrustedHostsPatternAction(ServerRequestInterface $request): ResponseInterface
280  {
281  $serverParams = $request->getServerParams();
282  $host = $serverParams['HTTP_HOST'] ?? '';
283 
284  return new ‪JsonResponse([
285  'success' => $this->verifyHostHeader->isAllowedHostHeaderValue($host, $serverParams),
286  ]);
287  }
288 
295  public function ‪executeAdjustTrustedHostsPatternAction(ServerRequestInterface $request): ResponseInterface
296  {
297  $serverParams = $request->getServerParams();
298  $host = $serverParams['HTTP_HOST'] ?? '';
299 
300  if (!$this->verifyHostHeader->isAllowedHostHeaderValue($host, $serverParams)) {
301  $this->configurationManager->setLocalConfigurationValueByPath('SYS/trustedHostsPattern', '.*');
302  }
303  return new JsonResponse([
304  'success' => true,
305  ]);
306  }
307 
313  public function ‪executeSilentConfigurationUpdateAction(): ResponseInterface
314  {
315  $success = true;
316  try {
317  $this->silentConfigurationUpgradeService->execute();
318  } catch (ConfigurationChangedException $e) {
319  $success = false;
320  }
321  return new JsonResponse([
322  'success' => $success,
323  ]);
324  }
325 
331  public function ‪executeSilentTemplateFileUpdateAction(): ResponseInterface
332  {
333  $success = true;
334  try {
335  $this->silentTemplateFileUpgradeService->execute();
336  } catch (TemplateFileChangedException $e) {
337  $success = false;
338  }
339  return new JsonResponse([
340  'success' => $success,
341  ]);
342  }
343 
349  public function ‪checkDatabaseConnectAction(): ResponseInterface
350  {
351  return new ‪JsonResponse([
353  ]);
354  }
355 
361  public function ‪showDatabaseConnectAction(): ResponseInterface
362  {
363  $view = $this->‪initializeStandaloneView('Installer/ShowDatabaseConnect.html');
364  $formProtection = ‪FormProtectionFactory::get(InstallToolFormProtection::class);
365  $hasAtLeastOneOption = false;
366  $activeAvailableOption = '';
367 
369  $hasAtLeastOneOption = true;
370  $view->assign('hasMysqliManualConfiguration', true);
371  $mysqliManualConfigurationOptions = [
372  'username' => ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['user'] ?? '',
373  'password' => ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['password'] ?? '',
374  'port' => ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['port'] ?? 3306,
375  ];
376  $host = ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['host'] ?? '127.0.0.1';
377  if ($host === 'localhost') {
378  $host = '127.0.0.1';
379  }
380  $mysqliManualConfigurationOptions['host'] = $host;
381  $view->assign('mysqliManualConfigurationOptions', $mysqliManualConfigurationOptions);
382  $activeAvailableOption = 'mysqliManualConfiguration';
383 
384  $view->assign('hasMysqliSocketManualConfiguration', true);
385  $view->assign(
386  'mysqliSocketManualConfigurationOptions',
387  [
388  'username' => ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['user'] ?? '',
389  'password' => ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['password'] ?? '',
390  'socket' => $this->‪getDatabaseConfiguredMysqliSocket(),
391  ]
392  );
393  if ((‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][ConnectionPool::DEFAULT_CONNECTION_NAME]['driver'] ?? '') === 'mysqli'
394  && (‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['host'] ?? '') === 'localhost') {
395  $activeAvailableOption = 'mysqliSocketManualConfiguration';
396  }
397  }
398 
400  $hasAtLeastOneOption = true;
401  $view->assign('hasPdoMysqlManualConfiguration', true);
402  $pdoMysqlManualConfigurationOptions = [
403  'username' => ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['user'] ?? '',
404  'password' => ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['password'] ?? '',
405  'port' => ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['port'] ?? 3306,
406  ];
407  $host = ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['host'] ?? '127.0.0.1';
408  if ($host === 'localhost') {
409  $host = '127.0.0.1';
410  }
411  $pdoMysqlManualConfigurationOptions['host'] = $host;
412  $view->assign('pdoMysqlManualConfigurationOptions', $pdoMysqlManualConfigurationOptions);
413 
414  // preselect PDO MySQL only if mysqli is not present
416  $activeAvailableOption = 'pdoMysqlManualConfiguration';
417  }
418 
419  $view->assign('hasPdoMysqlSocketManualConfiguration', true);
420  $view->assign(
421  'pdoMysqlSocketManualConfigurationOptions',
422  [
423  'username' => ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['user'] ?? '',
424  'password' => ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['password'] ?? '',
425  'socket' => $this->‪getDatabaseConfiguredPdoMysqlSocket(),
426  ]
427  );
428  if (‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][ConnectionPool::DEFAULT_CONNECTION_NAME]['driver'] === 'pdo_mysql'
429  && ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['host'] === 'localhost') {
430  $activeAvailableOption = 'pdoMysqlSocketManualConfiguration';
431  }
432  }
433 
435  $hasAtLeastOneOption = true;
436  $view->assign('hasPostgresManualConfiguration', true);
437  $view->assign(
438  'postgresManualConfigurationOptions',
439  [
440  'username' => ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['user'] ?? '',
441  'password' => ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['password'] ?? '',
442  'host' => ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['host'] ?? '127.0.0.1',
443  'port' => ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['port'] ?? 5432,
444  'database' => ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['dbname'] ?? '',
445  ]
446  );
447  if (‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['driver'] === 'pdo_pgsql') {
448  $activeAvailableOption = 'postgresManualConfiguration';
449  }
450  }
452  $hasAtLeastOneOption = true;
453  $view->assign('hasSqliteManualConfiguration', true);
454  $view->assign(
455  'sqliteManualConfigurationOptions',
456  []
457  );
458  if (‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['driver'] === 'pdo_sqlite') {
459  $activeAvailableOption = 'sqliteManualConfiguration';
460  }
461  }
462 
463  if (!empty($this->‪getDatabaseConfigurationFromEnvironment())) {
464  $hasAtLeastOneOption = true;
465  $activeAvailableOption = 'configurationFromEnvironment';
466  $view->assign('hasConfigurationFromEnvironment', true);
467  }
468 
469  $view->assignMultiple([
470  'hasAtLeastOneOption' => $hasAtLeastOneOption,
471  'activeAvailableOption' => $activeAvailableOption,
472  'executeDatabaseConnectToken' => $formProtection->generateToken('installTool', 'executeDatabaseConnect'),
473  ]);
474 
475  return new JsonResponse([
476  'success' => true,
477  'html' => $view->render(),
478  ]);
479  }
480 
487  public function ‪executeDatabaseConnectAction(ServerRequestInterface $request): ResponseInterface
488  {
489  $messages = [];
490  $postValues = $request->getParsedBody()['install']['values'];
491  $defaultConnectionSettings = [];
492 
493  if ($postValues['availableSet'] === 'configurationFromEnvironment') {
494  $defaultConnectionSettings = $this->‪getDatabaseConfigurationFromEnvironment();
495  } else {
496  if (isset($postValues['driver'])) {
497  $validDrivers = [
498  'mysqli',
499  'pdo_mysql',
500  'pdo_pgsql',
501  'mssql',
502  'pdo_sqlite',
503  ];
504  if (in_array($postValues['driver'], $validDrivers, true)) {
505  $defaultConnectionSettings['driver'] = $postValues['driver'];
506  } else {
507  $messages[] = new FlashMessage(
508  'Given driver must be one of ' . implode(', ', $validDrivers),
509  'Database driver unknown',
511  );
512  }
513  }
514  if (isset($postValues['username'])) {
515  $value = $postValues['username'];
516  if (strlen($value) <= 50) {
517  $defaultConnectionSettings['user'] = $value;
518  } else {
519  $messages[] = new FlashMessage(
520  'Given username must be shorter than fifty characters.',
521  'Database username not valid',
523  );
524  }
525  }
526  if (isset($postValues['password'])) {
527  $defaultConnectionSettings['password'] = $postValues['password'];
528  }
529  if (isset($postValues['host'])) {
530  $value = $postValues['host'];
531  if (preg_match('/^[a-zA-Z0-9_\\.-]+(:.+)?$/', $value) && strlen($value) <= 255) {
532  $defaultConnectionSettings['host'] = $value;
533  } else {
534  $messages[] = new FlashMessage(
535  'Given host is not alphanumeric (a-z, A-Z, 0-9 or _-.:) or longer than 255 characters.',
536  'Database host not valid',
538  );
539  }
540  }
541  if (isset($postValues['port']) && $postValues['host'] !== 'localhost') {
542  $value = $postValues['port'];
543  if (preg_match('/^[0-9]+(:.+)?$/', $value) && $value > 0 && $value <= 65535) {
544  $defaultConnectionSettings['port'] = (int)$value;
545  } else {
546  $messages[] = new FlashMessage(
547  'Given port is not numeric or within range 1 to 65535.',
548  'Database port not valid',
550  );
551  }
552  }
553  if (isset($postValues['socket']) && $postValues['socket'] !== '') {
554  if (@file_exists($postValues['socket'])) {
555  $defaultConnectionSettings['unix_socket'] = $postValues['socket'];
556  } else {
557  $messages[] = new FlashMessage(
558  'Given socket location does not exist on server.',
559  'Socket does not exist',
561  );
562  }
563  }
564  if (isset($postValues['database'])) {
565  $value = $postValues['database'];
566  if (strlen($value) <= 50) {
567  $defaultConnectionSettings['dbname'] = $value;
568  } else {
569  $messages[] = new FlashMessage(
570  'Given database name must be shorter than fifty characters.',
571  'Database name not valid',
573  );
574  }
575  }
576  // For sqlite a db path is automatically calculated
577  if (isset($postValues['driver']) && $postValues['driver'] === 'pdo_sqlite') {
578  $dbFilename = '/cms-' . (new Random())->generateRandomHexString(8) . '.sqlite';
579  // If the var/ folder exists outside of document root, put it into var/sqlite/
580  // Otherwise simply into typo3conf/
583  $defaultConnectionSettings['path'] = ‪Environment::getVarPath() . '/sqlite' . $dbFilename;
584  } else {
585  $defaultConnectionSettings['path'] = ‪Environment::getConfigPath() . $dbFilename;
586  }
587  }
588  // For mysql, set utf8mb4 as default charset
589  if (isset($postValues['driver']) && in_array($postValues['driver'], ['mysqli', 'pdo_mysql'])) {
590  $defaultConnectionSettings['charset'] = 'utf8mb4';
591  $defaultConnectionSettings['tableoptions'] = [
592  'charset' => 'utf8mb4',
593  'collate' => 'utf8mb4_unicode_ci',
594  ];
595  }
596  }
597 
598  $success = false;
599  if (!empty($defaultConnectionSettings)) {
600  // Test connection settings and write to config if connect is successful
601  try {
602  $connectionParams = $defaultConnectionSettings;
603  $connectionParams['wrapperClass'] = Connection::class;
604  if (!isset($connectionParams['charset'])) {
605  // utf-8 as default for non mysql
606  $connectionParams['charset'] = 'utf-8';
607  }
608  $connection = DriverManager::getConnection($connectionParams);
609  if ($connection->getWrappedConnection() !== null) {
610  $connection->executeQuery($connection->getDatabasePlatform()->getDummySelectSQL());
611  $success = true;
612  }
613  } catch (DBALException $e) {
614  $messages[] = new FlashMessage(
615  'Connecting to the database with given settings failed: ' . $e->getMessage(),
616  'Database connect not successful',
618  );
619  }
620  $localConfigurationPathValuePairs = [];
621  foreach ($defaultConnectionSettings as $settingsName => $value) {
622  $localConfigurationPathValuePairs['DB/Connections/Default/' . $settingsName] = $value;
623  }
624  // Remove full default connection array
625  $this->configurationManager->removeLocalConfigurationKeysByPath(['DB/Connections/Default']);
626  // Write new values
627  $this->configurationManager->setLocalConfigurationValuesByPathValuePairs($localConfigurationPathValuePairs);
628  }
629 
630  return new JsonResponse([
631  'success' => $success,
632  'status' => $messages,
633  ]);
634  }
635 
641  public function ‪checkDatabaseSelectAction(): ResponseInterface
642  {
643  $success = false;
644  if ((string)(‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['dbname'] ?? '') !== ''
645  || (string)(‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['path'] ?? '') !== ''
646  ) {
647  try {
648  $connection = GeneralUtility::makeInstance(ConnectionPool::class)
649  ->getConnectionByName(‪ConnectionPool::DEFAULT_CONNECTION_NAME);
650  if ($connection->getWrappedConnection() !== null) {
651  $connection->executeQuery($connection->getDatabasePlatform()->getDummySelectSQL());
652  $success = true;
653  }
654  } catch (DBALException $e) {
655  }
656  }
657  return new JsonResponse([
658  'success' => $success,
659  ]);
660  }
661 
667  public function ‪showDatabaseSelectAction(): ResponseInterface
668  {
669  $view = $this->‪initializeStandaloneView('Installer/ShowDatabaseSelect.html');
670  $formProtection = ‪FormProtectionFactory::get(InstallToolFormProtection::class);
671  ‪$errors = [];
672  try {
673  $view->assign('databaseList', $this->‪getDatabaseList());
674  } catch (\‪Exception $exception) {
675  ‪$errors[] = $exception->getMessage();
676  }
677  $view->assignMultiple([
678  'errors' => ‪$errors,
679  'executeDatabaseSelectToken' => $formProtection->generateToken('installTool', 'executeDatabaseSelect'),
680  'executeCheckDatabaseRequirementsToken' => $formProtection->generateToken('installTool', 'checkDatabaseRequirements'),
681  ]);
682  return new JsonResponse([
683  'success' => true,
684  'html' => $view->render(),
685  ]);
686  }
687 
693  public function ‪checkDatabaseRequirementsAction(ServerRequestInterface $request): ResponseInterface
694  {
695  $success = true;
696  $messages = [];
697  $databaseDriverName = ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['driver'];
698 
699  $databaseName = $this->‪retrieveDatabaseNameFromRequest($request);
700  if ($databaseName === '') {
701  return new ‪JsonResponse([
702  'success' => false,
703  'status' => [
704  new ‪FlashMessage(
705  'You must select a database.',
706  'No Database selected',
708  ),
709  ],
710  ]);
711  }
712 
713  ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['dbname'] = $databaseName;
714 
715  foreach ($this->‪checkDatabaseRequirementsForDriver($databaseDriverName) as $message) {
716  if ($message->getSeverity() === ‪FlashMessage::ERROR) {
717  $success = false;
718  $messages[] = $message;
719  }
720  }
721 
722  // Check create and drop permissions
723  $statusMessages = [];
724  foreach ($this->‪checkRequiredDatabasePermissions() as $checkRequiredPermission) {
725  $statusMessages[] = new FlashMessage(
726  $checkRequiredPermission,
727  'Missing required permissions',
729  );
730  }
731  if ($statusMessages !== []) {
732  return new JsonResponse([
733  'success' => false,
734  'status' => $statusMessages,
735  ]);
736  }
737 
738  // if requirements are not fulfilled
739  if ($success === false) {
740  // remove the database again if we created it
741  if ($request->getParsedBody()['install']['values']['type'] === 'new') {
742  $connection = GeneralUtility::makeInstance(ConnectionPool::class)
743  ->getConnectionByName(‪ConnectionPool::DEFAULT_CONNECTION_NAME);
744  $connection
745  ->createSchemaManager()
746  ->dropDatabase($connection->quoteIdentifier($databaseName));
747  }
748 
749  $this->configurationManager->removeLocalConfigurationKeysByPath(['DB/Connections/Default/dbname']);
750 
751  $message = new FlashMessage(
752  sprintf(
753  'Database with name "%s" has been removed due to the following errors. '
754  . 'Please solve them first and try again. If you tried to create a new database make also sure, that the DBMS charset is to use UTF-8',
755  $databaseName
756  ),
757  '',
759  );
760  array_unshift($messages, $message);
761  }
762 
763  unset(‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['dbname']);
764 
765  return new ‪JsonResponse([
766  'success' => $success,
767  'status' => $messages,
768  ]);
769  }
770 
771  private function ‪checkRequiredDatabasePermissions(): array
772  {
773  try {
774  return $this->databasePermissionsCheck
775  ->checkCreateAndDrop()
776  ->checkAlter()
777  ->checkIndex()
778  ->checkCreateTemporaryTable()
779  ->checkInsert()
780  ->checkSelect()
781  ->checkUpdate()
782  ->checkDelete()
783  ->getMessages();
784  } catch (\‪TYPO3\CMS\Install\Configuration\‪Exception $exception) {
785  return $this->databasePermissionsCheck->getMessages();
786  }
787  }
788 
789  private function ‪checkDatabaseRequirementsForDriver(string $databaseDriverName): FlashMessageQueue
790  {
791  $databaseCheck = GeneralUtility::makeInstance(DatabaseCheck::class);
792  try {
793  $databaseDriverClassName = ‪DatabaseCheck::retrieveDatabaseDriverClassByDriverName($databaseDriverName);
794 
795  $databaseCheck->checkDatabasePlatformRequirements($databaseDriverClassName);
796  $databaseCheck->checkDatabaseDriverRequirements($databaseDriverClassName);
797 
798  return $databaseCheck->getMessageQueue();
799  } catch (Exception $exception) {
800  $flashMessageQueue = new FlashMessageQueue('database-check-requirements');
801  $flashMessageQueue->enqueue(
802  new FlashMessage(
803  '',
804  $exception->getMessage(),
806  )
807  );
808  return $flashMessageQueue;
809  }
810  }
811 
812  private function ‪retrieveDatabaseNameFromRequest(ServerRequestInterface $request): string
813  {
814  $postValues = $request->getParsedBody()['install']['values'];
815  if ($postValues['type'] === 'new') {
816  return $postValues['new'];
817  }
818 
819  if ($postValues['type'] === 'existing' && !empty($postValues['existing'])) {
820  return $postValues['existing'];
821  }
822  return '';
823  }
824 
831  public function ‪executeDatabaseSelectAction(ServerRequestInterface $request): ResponseInterface
832  {
833  $databaseName = $this->‪retrieveDatabaseNameFromRequest($request);
834  if ($databaseName === '') {
835  return new ‪JsonResponse([
836  'success' => false,
837  'status' => [
838  new ‪FlashMessage(
839  'You must select a database.',
840  'No Database selected',
842  ),
843  ],
844  ]);
845  }
846 
847  $postValues = $request->getParsedBody()['install']['values'];
848  if ($postValues['type'] === 'new') {
849  $status = $this->‪createNewDatabase($databaseName);
850  if ($status->getSeverity() === ‪FlashMessage::ERROR) {
851  return new JsonResponse([
852  'success' => false,
853  'status' => [$status],
854  ]);
855  }
856  } elseif ($postValues['type'] === 'existing') {
857  $status = $this->‪checkExistingDatabase($databaseName);
858  if ($status->getSeverity() === ‪FlashMessage::ERROR) {
859  return new JsonResponse([
860  'success' => false,
861  'status' => [$status],
862  ]);
863  }
864  }
865  return new JsonResponse([
866  'success' => true,
867  ]);
868  }
869 
875  public function ‪checkDatabaseDataAction(): ResponseInterface
876  {
877  $existingTables = GeneralUtility::makeInstance(ConnectionPool::class)
878  ->getConnectionByName(‪ConnectionPool::DEFAULT_CONNECTION_NAME)
879  ->createSchemaManager()
880  ->listTableNames();
881  return new ‪JsonResponse([
882  'success' => !empty($existingTables),
883  ]);
884  }
885 
891  public function ‪showDatabaseDataAction(): ResponseInterface
892  {
893  $view = $this->‪initializeStandaloneView('Installer/ShowDatabaseData.html');
894  $formProtection = ‪FormProtectionFactory::get(InstallToolFormProtection::class);
895  $view->assignMultiple([
896  'siteName' => ‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'],
897  'executeDatabaseDataToken' => $formProtection->generateToken('installTool', 'executeDatabaseData'),
898  ]);
899  return new ‪JsonResponse([
900  'success' => true,
901  'html' => $view->render(),
902  ]);
903  }
904 
911  public function ‪executeDatabaseDataAction(ServerRequestInterface $request): ResponseInterface
912  {
913  $messages = [];
914  $postValues = $request->getParsedBody()['install']['values'];
915  $username = (string)$postValues['username'] !== '' ? $postValues['username'] : 'admin';
916  // Check password and return early if not good enough
917  $password = $postValues['password'];
918  $email = $postValues['email'] ?? '';
919  if (empty($password) || strlen($password) < 8) {
920  $messages[] = new ‪FlashMessage(
921  'You are setting an important password here! It gives an attacker full control over your instance if cracked.'
922  . ' It should be strong (include lower and upper case characters, special characters and numbers) and must be at least eight characters long.',
923  'Administrator password not secure enough!',
925  );
926  return new ‪JsonResponse([
927  'success' => false,
928  'status' => $messages,
929  ]);
930  }
931  // Set site name
932  if (!empty($postValues['sitename'])) {
933  $this->configurationManager->setLocalConfigurationValueByPath('SYS/sitename', $postValues['sitename']);
934  }
935  try {
936  $messages = $this->‪importDatabaseData();
937  if (!empty($messages)) {
938  return new JsonResponse([
939  'success' => false,
940  'status' => $messages,
941  ]);
942  }
943  } catch (StatementException $exception) {
944  $messages[] = new FlashMessage(
945  'Error detected in SQL statement:' . LF . $exception->getMessage(),
946  'Import of database data could not be performed',
948  );
949  return new JsonResponse([
950  'success' => false,
951  'status' => $messages,
952  ]);
953  }
954  // Insert admin user
955  $adminUserFields = [
956  'username' => $username,
957  'password' => $this->‪getHashedPassword($password),
958  'email' => GeneralUtility::validEmail($email) ? $email : '',
959  'admin' => 1,
960  'tstamp' => ‪$GLOBALS['EXEC_TIME'],
961  'crdate' => ‪$GLOBALS['EXEC_TIME'],
962  ];
963  $databaseConnection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('be_users');
964  try {
965  $databaseConnection->insert('be_users', $adminUserFields);
966  $adminUserUid = (int)$databaseConnection->lastInsertId('be_users');
967  } catch (DBALException $exception) {
968  $messages[] = new FlashMessage(
969  'The administrator account could not be created. The following error occurred:' . LF
970  . $exception->getPrevious()->getMessage(),
971  'Administrator account not created!',
973  );
974  return new JsonResponse([
975  'success' => false,
976  'status' => $messages,
977  ]);
978  }
979  // Set password as install tool password, add admin user to system maintainers
980  $this->configurationManager->setLocalConfigurationValuesByPathValuePairs([
981  'BE/installToolPassword' => $this->‪getHashedPassword($password),
982  'SYS/systemMaintainers' => [$adminUserUid],
983  ]);
984  return new JsonResponse([
985  'success' => true,
986  'status' => $messages,
987  ]);
988  }
989 
995  public function ‪showDefaultConfigurationAction(): ResponseInterface
996  {
997  $view = $this->‪initializeStandaloneView('Installer/ShowDefaultConfiguration.html');
998  $formProtection = ‪FormProtectionFactory::get(InstallToolFormProtection::class);
999  $view->assignMultiple([
1000  'composerMode' => ‪Environment::isComposerMode(),
1001  'executeDefaultConfigurationToken' => $formProtection->generateToken('installTool', 'executeDefaultConfiguration'),
1002  ]);
1003  return new ‪JsonResponse([
1004  'success' => true,
1005  'html' => $view->render(),
1006  ]);
1007  }
1008 
1015  public function ‪executeDefaultConfigurationAction(ServerRequestInterface $request): ResponseInterface
1016  {
1017  $featureManager = new ‪FeatureManager();
1018  // Get best matching configuration presets
1019  $configurationValues = $featureManager->getBestMatchingConfigurationForAllFeatures();
1020  $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
1021 
1022  $container = $this->lateBootService->loadExtLocalconfDatabaseAndExtTables();
1023  // Use the container here instead of makeInstance() to use the factory of the container for building the UriBuilder
1024  $uriBuilder = $container->get(UriBuilder::class);
1025  $nextStepUrl = $uriBuilder->buildUriFromRoute('login');
1026  // Let the admin user redirect to the distributions page on first login
1027  switch ($request->getParsedBody()['install']['values']['sitesetup']) {
1028  // Update the URL to redirect after login to the extension manager distributions list
1029  case 'loaddistribution':
1030  $nextStepUrl = $uriBuilder->buildUriWithRedirect(
1031  'login',
1032  [],
1034  'tools_ExtensionmanagerExtensionmanager',
1035  [
1036  'tx_extensionmanager_tools_extensionmanagerextensionmanager' => [
1037  'action' => 'distributions',
1038  ],
1039  ]
1040  )
1041  );
1042  break;
1043 
1044  // Create a page with UID 1 and PID1 and fluid_styled_content for page TS config, respect ownership
1045  case 'createsite':
1046  $databaseConnectionForPages = $connectionPool->getConnectionForTable('pages');
1047  $databaseConnectionForPages->insert(
1048  'pages',
1049  [
1050  'pid' => 0,
1051  'crdate' => time(),
1052  'cruser_id' => 1,
1053  'tstamp' => time(),
1054  'title' => 'Home',
1055  'slug' => '/',
1056  'doktype' => 1,
1057  'is_siteroot' => 1,
1058  'perms_userid' => 1,
1059  'perms_groupid' => 1,
1060  'perms_user' => 31,
1061  'perms_group' => 31,
1062  'perms_everybody' => 1,
1063  ]
1064  );
1065  $pageUid = $databaseConnectionForPages->lastInsertId('pages');
1066 
1067  // add a root sys_template with fluid_styled_content and a default PAGE typoscript snippet
1068  $connectionPool->getConnectionForTable('sys_template')->insert(
1069  'sys_template',
1070  [
1071  'pid' => $pageUid,
1072  'crdate' => time(),
1073  'cruser_id' => 1,
1074  'tstamp' => time(),
1075  'title' => 'Main TypoScript Rendering',
1076  'root' => 1,
1077  'clear' => 1,
1078  'include_static_file' => 'EXT:fluid_styled_content/Configuration/TypoScript/,EXT:fluid_styled_content/Configuration/TypoScript/Styling/',
1079  'constants' => '',
1080  'config' => 'page = PAGE
1081 page.10 = TEXT
1082 page.10.value (
1083  <div style="width: 800px; margin: 15% auto;">
1084  <div style="width: 300px;">
1085  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 150 42"><path d="M60.2 14.4v27h-3.8v-27h-6.7v-3.3h17.1v3.3h-6.6zm20.2 12.9v14h-3.9v-14l-7.7-16.2h4.1l5.7 12.2 5.7-12.2h3.9l-7.8 16.2zm19.5 2.6h-3.6v11.4h-3.8V11.1s3.7-.3 7.3-.3c6.6 0 8.5 4.1 8.5 9.4 0 6.5-2.3 9.7-8.4 9.7m.4-16c-2.4 0-4.1.3-4.1.3v12.6h4.1c2.4 0 4.1-1.6 4.1-6.3 0-4.4-1-6.6-4.1-6.6m21.5 27.7c-7.1 0-9-5.2-9-15.8 0-10.2 1.9-15.1 9-15.1s9 4.9 9 15.1c.1 10.6-1.8 15.8-9 15.8m0-27.7c-3.9 0-5.2 2.6-5.2 12.1 0 9.3 1.3 12.4 5.2 12.4 3.9 0 5.2-3.1 5.2-12.4 0-9.4-1.3-12.1-5.2-12.1m19.9 27.7c-2.1 0-5.3-.6-5.7-.7v-3.1c1 .2 3.7.7 5.6.7 2.2 0 3.6-1.9 3.6-5.2 0-3.9-.6-6-3.7-6H138V24h3.1c3.5 0 3.7-3.6 3.7-5.3 0-3.4-1.1-4.8-3.2-4.8-1.9 0-4.1.5-5.3.7v-3.2c.5-.1 3-.7 5.2-.7 4.4 0 7 1.9 7 8.3 0 2.9-1 5.5-3.3 6.3 2.6.2 3.8 3.1 3.8 7.3 0 6.6-2.5 9-7.3 9"/><path fill="#FF8700" d="M31.7 28.8c-.6.2-1.1.2-1.7.2-5.2 0-12.9-18.2-12.9-24.3 0-2.2.5-3 1.3-3.6C12 1.9 4.3 4.2 1.9 7.2 1.3 8 1 9.1 1 10.6c0 9.5 10.1 31 17.3 31 3.3 0 8.8-5.4 13.4-12.8M28.4.5c6.6 0 13.2 1.1 13.2 4.8 0 7.6-4.8 16.7-7.2 16.7-4.4 0-9.9-12.1-9.9-18.2C24.5 1 25.6.5 28.4.5"/></svg>
1086  </div>
1087  <h4 style="font-family: sans-serif;">Welcome to a default website made with <a href="https://typo3.org">TYPO3</a></h4>
1088  </div>
1089 )
1090 page.100 = CONTENT
1091 page.100 {
1092  table = tt_content
1093  select {
1094  orderBy = sorting
1095  where = {#colPos}=0
1096  }
1097 }
1098 ',
1099  'description' => 'This is an Empty Site Package TypoScript template.
1100 
1101 For each website you need a TypoScript template on the main page of your website (on the top level). For better maintenance all TypoScript should be extracted into external files via @import \'EXT:site_myproject/Configuration/TypoScript/setup.typoscript\'',
1102  ]
1103  );
1104 
1105  $this->‪createSiteConfiguration('main', (int)$pageUid, $request);
1106  break;
1107  }
1108 
1109  // Mark upgrade wizards as done
1110  if (!empty(‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update'])) {
1111  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update'] as $updateClassName) {
1112  if (!in_array(RepeatableInterface::class, class_implements($updateClassName) ?: [], true)) {
1113  $this->registry->set('installUpdate', $updateClassName, 1);
1114  }
1115  }
1116  }
1117  $this->registry->set('installUpdateRows', 'rowUpdatersDone', GeneralUtility::makeInstance(DatabaseRowsUpdateWizard::class)->getAvailableRowUpdater());
1118 
1119  $this->configurationManager->setLocalConfigurationValuesByPathValuePairs($configurationValues);
1120 
1121  $formProtection = ‪FormProtectionFactory::get(InstallToolFormProtection::class);
1122  $formProtection->clean();
1123 
1125 
1126  return new JsonResponse([
1127  'success' => true,
1128  'redirect' => (string)$nextStepUrl,
1129  ]);
1130  }
1131 
1139  protected function ‪initializeStandaloneView(string $templatePath): ‪StandaloneView
1140  {
1141  $viewRootPath = GeneralUtility::getFileAbsFileName('EXT:install/Resources/Private/');
1142  $view = GeneralUtility::makeInstance(StandaloneView::class);
1143  $view->getRequest()->setControllerExtensionName('Install');
1144  $view->setTemplatePathAndFilename($viewRootPath . 'Templates/' . $templatePath);
1145  $view->setLayoutRootPaths([$viewRootPath . 'Layouts/']);
1146  $view->setPartialRootPaths([$viewRootPath . 'Partials/']);
1147  return $view;
1148  }
1149 
1155  protected function ‪isDatabaseConnectSuccessful(): bool
1156  {
1157  try {
1158  $connection = GeneralUtility::makeInstance(ConnectionPool::class)
1159  ->getConnectionByName(‪ConnectionPool::DEFAULT_CONNECTION_NAME);
1160  if ($connection->getWrappedConnection() !== null) {
1161  $connection->executeQuery($connection->getDatabasePlatform()->getDummySelectSQL());
1162  return true;
1163  }
1164  } catch (DBALException $e) {
1165  }
1166  return false;
1167  }
1168 
1176  protected function ‪isDatabaseConfigurationComplete()
1177  {
1178  $configurationComplete = true;
1179  if (!isset(‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['user'])) {
1180  $configurationComplete = false;
1181  }
1182  if (!isset(‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['password'])) {
1183  $configurationComplete = false;
1184  }
1185  if (isset(‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['driver'])
1186  && ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['driver'] === 'pdo_sqlite'
1187  && !empty(‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['path'])
1188  ) {
1189  $configurationComplete = true;
1190  }
1191  return $configurationComplete;
1192  }
1193 
1199  protected function ‪getDatabaseConfiguredMysqliSocket(): string
1200  {
1201  return $this->‪getDefaultSocketFor('mysqli.default_socket');
1202  }
1203 
1209  protected function ‪getDatabaseConfiguredPdoMysqlSocket(): string
1210  {
1211  return $this->‪getDefaultSocketFor('pdo_mysql.default_socket');
1212  }
1213 
1219  private function ‪getDefaultSocketFor(string $phpIniSetting): string
1220  {
1221  $socket = ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['unix_socket'] ?? '';
1222  if ($socket === '') {
1223  // If no configured socket, use default php socket
1224  $defaultSocket = (string)ini_get($phpIniSetting);
1225  if ($defaultSocket !== '') {
1226  $socket = $defaultSocket;
1227  }
1228  }
1229  return $socket;
1230  }
1231 
1237  protected function ‪getDatabaseConfigurationFromEnvironment(): array
1238  {
1239  $envCredentials = [];
1240  foreach (['driver', 'host', 'user', 'password', 'port', 'dbname', 'unix_socket'] as $value) {
1241  $envVar = 'TYPO3_INSTALL_DB_' . strtoupper($value);
1242  if (getenv($envVar) !== false) {
1243  $envCredentials[$value] = getenv($envVar);
1244  }
1245  }
1246  if (!empty($envCredentials)) {
1247  $connectionParams = $envCredentials;
1248  $connectionParams['wrapperClass'] = Connection::class;
1249  $connectionParams['charset'] = 'utf-8';
1250  try {
1251  $connection = DriverManager::getConnection($connectionParams);
1252  if ($connection->getWrappedConnection() !== null) {
1253  $connection->executeQuery($connection->getDatabasePlatform()->getDummySelectSQL());
1254  return $envCredentials;
1255  }
1256  } catch (DBALException $e) {
1257  return [];
1258  }
1259  }
1260  return [];
1261  }
1262 
1268  protected function ‪getDatabaseList()
1269  {
1270  $connectionParams = ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME];
1271  unset($connectionParams['dbname']);
1272 
1273  // Establishing the connection using the Doctrine DriverManager directly
1274  // as we need a connection without selecting a database right away. Otherwise
1275  // an invalid database name would lead to exceptions which would prevent
1276  // changing the currently configured database.
1277  $connection = DriverManager::getConnection($connectionParams);
1278  // @todo: migrate to createSchemaManager() with Doctrine DBAL 3.2 requirement in TYPO3 v12.0
1279  $databaseArray = $connection->getSchemaManager()->listDatabases();
1280  $connection->close();
1281 
1282  // Remove organizational tables from database list
1283  $reservedDatabaseNames = ['mysql', 'information_schema', 'performance_schema'];
1284  $allPossibleDatabases = array_diff($databaseArray, $reservedDatabaseNames);
1285 
1286  // In first installation we show all databases but disable not empty ones (with tables)
1287  $databases = [];
1288  foreach ($allPossibleDatabases as $databaseName) {
1289  // Reestablishing the connection for each database since there is no
1290  // portable way to switch databases on the same Doctrine connection.
1291  // Directly using the Doctrine DriverManager here to avoid messing with
1292  // the $GLOBALS database configuration array.
1293  try {
1294  $connectionParams['dbname'] = $databaseName;
1295  $connection = DriverManager::getConnection($connectionParams);
1296 
1297  // @todo: migrate to createSchemaManager() with Doctrine DBAL 3.2 requirement in TYPO3 v12.0
1298  $databases[] = [
1299  'name' => $databaseName,
1300  'tables' => count($connection->getSchemaManager()->listTableNames()),
1301  'readonly' => false,
1302  ];
1303  $connection->close();
1304  } catch (ConnectionException $exception) {
1305  $databases[] = [
1306  'name' => $databaseName,
1307  'tables' => 0,
1308  'readonly' => true,
1309  ];
1310  // we ignore a connection exception here.
1311  // if this happens here, the show tables was successful
1312  // but the connection failed because of missing permissions.
1313  }
1314  }
1315 
1316  return $databases;
1317  }
1318 
1325  protected function ‪createNewDatabase($dbName)
1326  {
1327  try {
1328  $platform = GeneralUtility::makeInstance(ConnectionPool::class)
1329  ->getConnectionByName(‪ConnectionPool::DEFAULT_CONNECTION_NAME)
1330  ->getDatabasePlatform();
1331  $connection = GeneralUtility::makeInstance(ConnectionPool::class)
1332  ->getConnectionByName(‪ConnectionPool::DEFAULT_CONNECTION_NAME);
1333  $connection->exec(
1335  $platform,
1336  $connection->quoteIdentifier($dbName)
1337  )
1338  );
1339  $this->configurationManager
1340  ->setLocalConfigurationValueByPath('DB/Connections/Default/dbname', $dbName);
1341  } catch (DBALException $e) {
1342  return new FlashMessage(
1343  'Database with name "' . $dbName . '" could not be created.'
1344  . ' Either your database name contains a reserved keyword or your database'
1345  . ' user does not have sufficient permissions to create it or the database already exists.'
1346  . ' Please choose an existing (empty) database, choose another name or contact administration.',
1347  'Unable to create database',
1349  );
1350  }
1351  return new FlashMessage(
1352  '',
1353  'Database created'
1354  );
1355  }
1365  protected function ‪checkExistingDatabase($dbName)
1366  {
1367  $result = new ‪FlashMessage('');
1368  $localConfigurationPathValuePairs = [];
1369 
1370  ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['dbname'] = $dbName;
1371  try {
1372  $connection = GeneralUtility::makeInstance(ConnectionPool::class)
1373  ->getConnectionByName(‪ConnectionPool::DEFAULT_CONNECTION_NAME);
1374 
1375  if (!empty($connection->createSchemaManager()->listTableNames())) {
1376  $result = new ‪FlashMessage(
1377  sprintf('Cannot use database "%s"', $dbName)
1378  . ', because it already contains tables. Please select a different database or choose to create one!',
1379  'Selected database is not empty!',
1381  );
1382  }
1383  } catch (\‪Exception $e) {
1384  $result = new ‪FlashMessage(
1385  sprintf('Could not connect to database "%s"', $dbName)
1386  . '! Make sure it really exists and your database user has the permissions to select it!',
1387  'Could not connect to selected database!',
1389  );
1390  }
1391 
1392  if ($result->getSeverity() === ‪FlashMessage::OK) {
1393  $localConfigurationPathValuePairs['DB/Connections/Default/dbname'] = $dbName;
1394  }
1395 
1396  if ($result->getSeverity() === ‪FlashMessage::OK && !empty($localConfigurationPathValuePairs)) {
1397  $this->configurationManager->setLocalConfigurationValuesByPathValuePairs($localConfigurationPathValuePairs);
1398  }
1399 
1400  return $result;
1401  }
1402 
1415  protected function ‪getHashedPassword($password)
1416  {
1417  $okHashMethods = [
1418  Argon2iPasswordHash::class,
1419  Argon2idPasswordHash::class,
1420  BcryptPasswordHash::class,
1421  Pbkdf2PasswordHash::class,
1422  PhpassPasswordHash::class,
1423  ];
1424  foreach ($okHashMethods as $className) {
1426  $instance = GeneralUtility::makeInstance($className);
1427  if ($instance->isAvailable()) {
1428  return $instance->getHashedPassword($password);
1429  }
1430  }
1431  throw new \LogicException('No suitable hash method found', 1533988846);
1432  }
1433 
1439  protected function ‪importDatabaseData()
1440  {
1441  // Will load ext_localconf and ext_tables. This is pretty safe here since we are
1442  // in first install (database empty), so it is very likely that no extension is loaded
1443  // that could trigger a fatal at this point.
1444  $container = $this->lateBootService->loadExtLocalconfDatabaseAndExtTables();
1445 
1446  $sqlReader = $container->get(SqlReader::class);
1447  $sqlCode = $sqlReader->getTablesDefinitionString(true);
1448  $schemaMigrationService = GeneralUtility::makeInstance(SchemaMigrator::class);
1449  $createTableStatements = $sqlReader->getCreateTableStatementArray($sqlCode);
1450  $results = $schemaMigrationService->install($createTableStatements);
1451 
1452  // Only keep statements with error messages
1453  $results = array_filter($results);
1454  if (count($results) === 0) {
1455  $insertStatements = $sqlReader->getInsertStatementArray($sqlCode);
1456  $results = $schemaMigrationService->importStaticData($insertStatements);
1457  }
1458  foreach ($results as $statement => &$message) {
1459  if ($message === '') {
1460  unset($results[$statement]);
1461  continue;
1462  }
1463  $message = new FlashMessage(
1464  'Query:' . LF . ' ' . $statement . LF . 'Error:' . LF . ' ' . $message,
1465  'Database query failed!',
1467  );
1468  }
1469  return array_values($results);
1470  }
1480  protected function ‪createSiteConfiguration(string $identifier, int $rootPageId, ServerRequestInterface $request)
1481  {
1482  $normalizedParams = $request->getAttribute('normalizedParams', null);
1483  if (!($normalizedParams instanceof ‪NormalizedParams)) {
1484  $normalizedParams = ‪NormalizedParams::createFromRequest($request);
1485  }
1486  // Check for siteUrl, despite there currently is no UI to provide it,
1487  // to allow TYPO3 Console (for TYPO3 v10) to set this value to something reasonable,
1488  // because on cli there is no way to find out which hostname the site is supposed to have.
1489  // In the future this controller should be refactored to a generic service, where site URL is
1490  // just one input argument.
1491  $siteUrl = $request->getParsedBody()['install']['values']['siteUrl'] ?? $normalizedParams->getSiteUrl();
1492 
1493  // Create a default site configuration called "main" as best practice
1494  $this->siteConfiguration->createNewBasicSite($identifier, $rootPageId, $siteUrl);
1495  }
1496 }
‪TYPO3\CMS\Install\Controller\InstallerController\executeDatabaseSelectAction
‪ResponseInterface executeDatabaseSelectAction(ServerRequestInterface $request)
Definition: InstallerController.php:822
‪TYPO3\CMS\Install\Controller\InstallerController\checkEnvironmentAndFoldersAction
‪ResponseInterface checkEnvironmentAndFoldersAction()
Definition: InstallerController.php:199
‪TYPO3\CMS\Install\Controller\InstallerController\executeDefaultConfigurationAction
‪ResponseInterface executeDefaultConfigurationAction(ServerRequestInterface $request)
Definition: InstallerController.php:1006
‪TYPO3\CMS\Install\Controller\InstallerController\$verifyHostHeader
‪VerifyHostHeader $verifyHostHeader
Definition: InstallerController.php:110
‪TYPO3\CMS\Backend\Routing\RouteRedirect\create
‪static create(string $name, $params)
Definition: RouteRedirect.php:42
‪TYPO3\CMS\Core\FormProtection\FormProtectionFactory\get
‪static TYPO3 CMS Core FormProtection AbstractFormProtection get($classNameOrType='default',... $constructorArguments)
Definition: FormProtectionFactory.php:73
‪TYPO3\CMS\Core\Utility\PathUtility
Definition: PathUtility.php:25
‪TYPO3\CMS\Core\Crypto\PasswordHashing\BcryptPasswordHash
Definition: BcryptPasswordHash.php:32
‪TYPO3\CMS\Install\Updates\RepeatableInterface
Definition: RepeatableInterface.php:25
‪TYPO3\CMS\Install\Controller\InstallerController\$databasePermissionsCheck
‪PermissionsCheck $databasePermissionsCheck
Definition: InstallerController.php:114
‪TYPO3\CMS\Install\Configuration\FeatureManager
Definition: FeatureManager.php:30
‪TYPO3\CMS\Core\Core\Environment\getPublicPath
‪static string getPublicPath()
Definition: Environment.php:206
‪TYPO3\CMS\Core\Database\Schema\Exception\StatementException
Definition: StatementException.php:24
‪TYPO3\CMS\Install\Controller\InstallerController\executeAdjustTrustedHostsPatternAction
‪ResponseInterface executeAdjustTrustedHostsPatternAction(ServerRequestInterface $request)
Definition: InstallerController.php:286
‪TYPO3\CMS\Install\Controller\InstallerController\checkDatabaseConnectAction
‪ResponseInterface checkDatabaseConnectAction()
Definition: InstallerController.php:340
‪TYPO3\CMS\Install\Controller\InstallerController\createSiteConfiguration
‪createSiteConfiguration(string $identifier, int $rootPageId, ServerRequestInterface $request)
Definition: InstallerController.php:1471
‪TYPO3\CMS\Core\Package\FailsafePackageManager
Definition: FailsafePackageManager.php:27
‪TYPO3\CMS\Install\Controller\InstallerController\$silentTemplateFileUpgradeService
‪SilentTemplateFileUpgradeService $silentTemplateFileUpgradeService
Definition: InstallerController.php:90
‪TYPO3\CMS\Install\Service\Exception\ConfigurationChangedException
Definition: ConfigurationChangedException.php:25
‪TYPO3\CMS\Core\Information\Typo3Version
Definition: Typo3Version.php:21
‪TYPO3\CMS\Core\Configuration\ExtensionConfiguration
Definition: ExtensionConfiguration.php:45
‪TYPO3\CMS\Install\Controller\InstallerController\executeDatabaseDataAction
‪ResponseInterface executeDatabaseDataAction(ServerRequestInterface $request)
Definition: InstallerController.php:902
‪TYPO3\CMS\Install\Service\SilentConfigurationUpgradeService
Definition: SilentConfigurationUpgradeService.php:43
‪TYPO3\CMS\Core\Database\Platform\PlatformInformation\getDatabaseCreateStatementWithCharset
‪static string getDatabaseCreateStatementWithCharset(AbstractPlatform $platform, string $databaseName)
Definition: PlatformInformation.php:89
‪TYPO3\CMS\Install\Controller\InstallerController\$siteConfiguration
‪SiteConfiguration $siteConfiguration
Definition: InstallerController.php:98
‪TYPO3
‪TYPO3\CMS\Install\Controller\InstallerController\executeSilentTemplateFileUpdateAction
‪ResponseInterface executeSilentTemplateFileUpdateAction()
Definition: InstallerController.php:322
‪TYPO3\CMS\Install\Controller\InstallerController\getDatabaseConfiguredMysqliSocket
‪string getDatabaseConfiguredMysqliSocket()
Definition: InstallerController.php:1190
‪TYPO3\CMS\Install\Controller\InstallerController\checkDatabaseDataAction
‪ResponseInterface checkDatabaseDataAction()
Definition: InstallerController.php:866
‪TYPO3\CMS\Core\Registry
Definition: Registry.php:33
‪TYPO3\CMS\Install\Controller\InstallerController\getDefaultSocketFor
‪string getDefaultSocketFor(string $phpIniSetting)
Definition: InstallerController.php:1210
‪TYPO3\CMS\Install\SystemEnvironment\DatabaseCheck\isPdoSqlite
‪static isPdoSqlite()
Definition: DatabaseCheck.php:317
‪TYPO3\CMS\Core\Utility\PathUtility\getPublicResourceWebPath
‪static string getPublicResourceWebPath(string $resourcePath, bool $prefixWithSitePath=true)
Definition: PathUtility.php:98
‪TYPO3\CMS\Install\Controller\InstallerController\checkDatabaseRequirementsForDriver
‪checkDatabaseRequirementsForDriver(string $databaseDriverName)
Definition: InstallerController.php:780
‪TYPO3\CMS\Install\Controller\InstallerController\$registry
‪Registry $registry
Definition: InstallerController.php:102
‪TYPO3\CMS\Install\Service\EnableFileService
Definition: EnableFileService.php:26
‪TYPO3\CMS\Install\Controller\InstallerController\executeDatabaseConnectAction
‪ResponseInterface executeDatabaseConnectAction(ServerRequestInterface $request)
Definition: InstallerController.php:478
‪TYPO3\CMS\Install\Controller\InstallerController\createNewDatabase
‪FlashMessage createNewDatabase($dbName)
Definition: InstallerController.php:1316
‪TYPO3\CMS\Install\FolderStructure\DefaultFactory
Definition: DefaultFactory.php:25
‪TYPO3\CMS\Install\Controller\InstallerController\getDatabaseConfigurationFromEnvironment
‪array getDatabaseConfigurationFromEnvironment()
Definition: InstallerController.php:1228
‪TYPO3\CMS\Install\Controller\InstallerController\checkDatabaseSelectAction
‪ResponseInterface checkDatabaseSelectAction()
Definition: InstallerController.php:632
‪TYPO3\CMS\Install\Controller\InstallerController\getDatabaseConfiguredPdoMysqlSocket
‪string getDatabaseConfiguredPdoMysqlSocket()
Definition: InstallerController.php:1200
‪TYPO3\CMS\Core\Database\Schema\SqlReader
Definition: SqlReader.php:31
‪TYPO3\CMS\Core\Configuration\SiteConfiguration
Definition: SiteConfiguration.php:43
‪TYPO3\CMS\Install\Controller\InstallerController\executeEnvironmentAndFoldersAction
‪ResponseInterface executeEnvironmentAndFoldersAction()
Definition: InstallerController.php:240
‪TYPO3\CMS\Install\Controller\InstallerController\showDatabaseSelectAction
‪ResponseInterface showDatabaseSelectAction()
Definition: InstallerController.php:658
‪TYPO3\CMS\Install\Controller\InstallerController\isDatabaseConnectSuccessful
‪bool isDatabaseConnectSuccessful()
Definition: InstallerController.php:1146
‪TYPO3\CMS\Core\Database\ConnectionPool\DEFAULT_CONNECTION_NAME
‪const DEFAULT_CONNECTION_NAME
Definition: ConnectionPool.php:50
‪TYPO3\CMS\Core\Database\Schema\SchemaMigrator
Definition: SchemaMigrator.php:39
‪TYPO3\CMS\Core\FormProtection\InstallToolFormProtection
Definition: InstallToolFormProtection.php:61
‪TYPO3\CMS\Core\Core\Environment\getContext
‪static ApplicationContext getContext()
Definition: Environment.php:141
‪TYPO3\CMS\Install\Updates\DatabaseRowsUpdateWizard
Definition: DatabaseRowsUpdateWizard.php:50
‪TYPO3\CMS\Install\Controller\InstallerController\initAction
‪ResponseInterface initAction()
Definition: InstallerController.php:143
‪TYPO3\CMS\Install\Controller\InstallerController\checkDatabaseRequirementsAction
‪ResponseInterface checkDatabaseRequirementsAction(ServerRequestInterface $request)
Definition: InstallerController.php:684
‪TYPO3\CMS\Core\Messaging\AbstractMessage\WARNING
‪const WARNING
Definition: AbstractMessage.php:30
‪TYPO3\CMS\Install\Controller\InstallerController\$lateBootService
‪LateBootService $lateBootService
Definition: InstallerController.php:82
‪TYPO3\CMS\Core\Core\Environment\getProjectPath
‪static string getProjectPath()
Definition: Environment.php:177
‪TYPO3\CMS\Install\Controller\InstallerController\__construct
‪__construct(LateBootService $lateBootService, SilentConfigurationUpgradeService $silentConfigurationUpgradeService, SilentTemplateFileUpgradeService $silentTemplateFileUpgradeService, ConfigurationManager $configurationManager, SiteConfiguration $siteConfiguration, Registry $registry, FailsafePackageManager $packageManager, VerifyHostHeader $verifyHostHeader, PermissionsCheck $databasePermissionsCheck)
Definition: InstallerController.php:116
‪TYPO3\CMS\Install\Controller\InstallerController\$configurationManager
‪ConfigurationManager $configurationManager
Definition: InstallerController.php:94
‪TYPO3\CMS\Install\Exception
Definition: Exception.php:23
‪TYPO3\CMS\Install\Controller\InstallerController\$packageManager
‪FailsafePackageManager $packageManager
Definition: InstallerController.php:106
‪TYPO3\CMS\Install\Controller\InstallerController\executeSilentConfigurationUpdateAction
‪ResponseInterface executeSilentConfigurationUpdateAction()
Definition: InstallerController.php:304
‪TYPO3\CMS\Install\Service\EnableFileService\removeFirstInstallFile
‪static bool removeFirstInstallFile()
Definition: EnableFileService.php:87
‪TYPO3\CMS\Core\Utility\GeneralUtility\mkdir_deep
‪static mkdir_deep($directory)
Definition: GeneralUtility.php:1908
‪TYPO3\CMS\Install\Controller\InstallerController\checkRequiredDatabasePermissions
‪checkRequiredDatabasePermissions()
Definition: InstallerController.php:762
‪TYPO3\CMS\Install\Database\PermissionsCheck
Definition: PermissionsCheck.php:31
‪TYPO3\CMS\Install\Controller\InstallerController\showEnvironmentAndFoldersAction
‪ResponseInterface showEnvironmentAndFoldersAction()
Definition: InstallerController.php:211
‪TYPO3\CMS\Backend\Routing\RouteRedirect
Definition: RouteRedirect.php:30
‪TYPO3\CMS\Install\Controller
Definition: AbstractController.php:18
‪TYPO3\CMS\Backend\Routing\UriBuilder
Definition: UriBuilder.php:40
‪TYPO3\CMS\Install\Controller\InstallerController\showDatabaseDataAction
‪ResponseInterface showDatabaseDataAction()
Definition: InstallerController.php:882
‪TYPO3\CMS\Install\Service\SilentTemplateFileUpgradeService
Definition: SilentTemplateFileUpgradeService.php:35
‪TYPO3\CMS\Core\Crypto\PasswordHashing\Pbkdf2PasswordHash
Definition: Pbkdf2PasswordHash.php:28
‪TYPO3\CMS\Install\Controller\InstallerController\checkTrustedHostsPatternAction
‪ResponseInterface checkTrustedHostsPatternAction(ServerRequestInterface $request)
Definition: InstallerController.php:270
‪TYPO3\CMS\Install\Service\Exception\TemplateFileChangedException
Definition: TemplateFileChangedException.php:25
‪TYPO3\CMS\Install\Controller\InstallerController\showDefaultConfigurationAction
‪ResponseInterface showDefaultConfigurationAction()
Definition: InstallerController.php:986
‪TYPO3\CMS\Install\Controller\InstallerController\retrieveDatabaseNameFromRequest
‪retrieveDatabaseNameFromRequest(ServerRequestInterface $request)
Definition: InstallerController.php:803
‪TYPO3\CMS\Install\SystemEnvironment\DatabaseCheck\retrieveDatabaseDriverClassByDriverName
‪static string retrieveDatabaseDriverClassByDriverName(string $driverName)
Definition: DatabaseCheck.php:285
‪TYPO3\CMS\Install\Service\LateBootService
Definition: LateBootService.php:27
‪TYPO3\CMS\Install\Controller\InstallerController\initializeStandaloneView
‪StandaloneView initializeStandaloneView(string $templatePath)
Definition: InstallerController.php:1130
‪TYPO3\CMS\Install\SystemEnvironment\DatabaseCheck
‪TYPO3\CMS\Core\Crypto\PasswordHashing\PhpassPasswordHash
Definition: PhpassPasswordHash.php:35
‪TYPO3\CMS\Install\Controller\InstallerController\showDatabaseConnectAction
‪ResponseInterface showDatabaseConnectAction()
Definition: InstallerController.php:352
‪$errors
‪$errors
Definition: annotationChecker.php:123
‪TYPO3\CMS\Core\Messaging\AbstractMessage\OK
‪const OK
Definition: AbstractMessage.php:29
‪TYPO3\CMS\Install\Controller\InstallerController
Definition: InstallerController.php:79
‪TYPO3\CMS\Core\Database\Connection
Definition: Connection.php:38
‪TYPO3\CMS\Core\Core\Environment\isComposerMode
‪static bool isComposerMode()
Definition: Environment.php:152
‪TYPO3\CMS\Core\Messaging\AbstractMessage\INFO
‪const INFO
Definition: AbstractMessage.php:28
‪TYPO3\CMS\Core\Messaging\FlashMessage
Definition: FlashMessage.php:26
‪TYPO3\CMS\Core\FormProtection\FormProtectionFactory
Definition: FormProtectionFactory.php:48
‪TYPO3\CMS\Fluid\View\StandaloneView
Definition: StandaloneView.php:31
‪TYPO3\CMS\Install\SystemEnvironment\Check
Definition: Check.php:55
‪TYPO3\CMS\Install\Controller\InstallerController\getHashedPassword
‪string getHashedPassword($password)
Definition: InstallerController.php:1406
‪TYPO3\CMS\Core\Http\JsonResponse
Definition: JsonResponse.php:28
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Install\Controller\InstallerController\isDatabaseConfigurationComplete
‪bool isDatabaseConfigurationComplete()
Definition: InstallerController.php:1167
‪TYPO3\CMS\Core\Core\Environment
Definition: Environment.php:43
‪TYPO3\CMS\Core\Database\Platform\PlatformInformation
Definition: PlatformInformation.php:33
‪TYPO3\CMS\Install\Controller\InstallerController\importDatabaseData
‪FlashMessage[] importDatabaseData()
Definition: InstallerController.php:1430
‪TYPO3\CMS\Install\SystemEnvironment\SetupCheck
Definition: SetupCheck.php:37
‪TYPO3\CMS\Core\Core\Environment\getConfigPath
‪static string getConfigPath()
Definition: Environment.php:236
‪TYPO3\CMS\Core\Middleware\VerifyHostHeader
Definition: VerifyHostHeader.php:31
‪TYPO3\CMS\Core\Crypto\Random
Definition: Random.php:24
‪TYPO3\CMS\Install\Controller\InstallerController\checkExistingDatabase
‪FlashMessage checkExistingDatabase($dbName)
Definition: InstallerController.php:1356
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:46
‪TYPO3\CMS\Install\SystemEnvironment\DatabaseCheck\isPdoMysql
‪static isPdoMysql()
Definition: DatabaseCheck.php:307
‪TYPO3\CMS\Install\Controller\InstallerController\showInstallerNotAvailableAction
‪ResponseInterface showInstallerNotAvailableAction()
Definition: InstallerController.php:185
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:50
‪TYPO3\CMS\Core\Crypto\PasswordHashing\PasswordHashInterface
Definition: PasswordHashInterface.php:25
‪TYPO3\CMS\Core\Messaging\FlashMessageQueue
Definition: FlashMessageQueue.php:29
‪TYPO3\CMS\Install\Controller\InstallerController\$silentConfigurationUpgradeService
‪SilentConfigurationUpgradeService $silentConfigurationUpgradeService
Definition: InstallerController.php:86
‪TYPO3\CMS\Core\Http\NormalizedParams\createFromRequest
‪static static createFromRequest(ServerRequestInterface $request, array $systemConfiguration=null)
Definition: NormalizedParams.php:843
‪TYPO3\CMS\Core\Crypto\PasswordHashing\Argon2idPasswordHash
Definition: Argon2idPasswordHash.php:31
‪TYPO3\CMS\Core\Crypto\PasswordHashing\Argon2iPasswordHash
Definition: Argon2iPasswordHash.php:31
‪TYPO3\CMS\Core\Core\Environment\getLegacyConfigPath
‪static string getLegacyConfigPath()
Definition: Environment.php:308
‪TYPO3\CMS\Core\Messaging\AbstractMessage\ERROR
‪const ERROR
Definition: AbstractMessage.php:31
‪TYPO3\CMS\Install\Controller\InstallerController\mainLayoutAction
‪ResponseInterface mainLayoutAction()
Definition: InstallerController.php:171
‪TYPO3\CMS\Core\Http\NormalizedParams
Definition: NormalizedParams.php:35
‪TYPO3\CMS\Install\SystemEnvironment\DatabaseCheck\isPdoPgsql
‪static isPdoPgsql()
Definition: DatabaseCheck.php:312
‪TYPO3\CMS\Core\Http\HtmlResponse
Definition: HtmlResponse.php:26
‪TYPO3\CMS\Core\Core\Environment\getVarPath
‪static string getVarPath()
Definition: Environment.php:218
‪TYPO3\CMS\Install\SystemEnvironment\DatabaseCheck\isMysqli
‪static isMysqli()
Definition: DatabaseCheck.php:302
‪TYPO3\CMS\Install\Controller\InstallerController\getDatabaseList
‪array getDatabaseList()
Definition: InstallerController.php:1259