‪TYPO3CMS  10.4
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\DBALException;
21 use Doctrine\DBAL\DriverManager;
22 use Doctrine\DBAL\Exception\ConnectionException;
23 use Psr\Http\Message\ResponseInterface;
24 use Psr\Http\Message\ServerRequestInterface;
25 use TYPO3\CMS\Core\Configuration\ConfigurationManager;
68 
74 {
78  private ‪$lateBootService;
79 
84 
89 
94 
98  private ‪$registry;
99 
104 
109 
110  public function ‪__construct(
113  ConfigurationManager ‪$configurationManager,
118  ) {
119  $this->lateBootService = ‪$lateBootService;
120  $this->silentConfigurationUpgradeService = ‪$silentConfigurationUpgradeService;
121  $this->configurationManager = ‪$configurationManager;
122  $this->siteConfiguration = ‪$siteConfiguration;
123  $this->registry = ‪$registry;
124  $this->packageManager = ‪$packageManager;
125  $this->databasePermissionsCheck = ‪$databasePermissionsCheck;
126  }
127 
133  public function ‪initAction(): ResponseInterface
134  {
135  $bust = ‪$GLOBALS['EXEC_TIME'];
136  if (!‪Environment::getContext()->isDevelopment()) {
137  $bust = GeneralUtility::hmac((string)(new ‪Typo3Version()) . ‪Environment::getProjectPath());
138  }
139  $view = $this->‪initializeStandaloneView('Installer/Init.html');
140  $view->assign('bust', $bust);
141  return new HtmlResponse(
142  $view->render(),
143  200,
144  [
145  'Cache-Control' => 'no-cache, must-revalidate',
146  'Pragma' => 'no-cache'
147  ]
148  );
149  }
150 
156  public function ‪mainLayoutAction(): ResponseInterface
157  {
158  $view = $this->‪initializeStandaloneView('Installer/MainLayout.html');
159  return new ‪JsonResponse([
160  'success' => true,
161  'html' => $view->render(),
162  ]);
163  }
164 
170  public function ‪showInstallerNotAvailableAction(): ResponseInterface
171  {
172  $view = $this->‪initializeStandaloneView('Installer/ShowInstallerNotAvailable.html');
173  return new ‪JsonResponse([
174  'success' => true,
175  'html' => $view->render(),
176  ]);
177  }
178 
184  public function ‪checkEnvironmentAndFoldersAction(): ResponseInterface
185  {
186  return new ‪JsonResponse([
187  'success' => @is_file($this->configurationManager->getLocalConfigurationFileLocation()),
188  ]);
189  }
190 
196  public function ‪showEnvironmentAndFoldersAction(): ResponseInterface
197  {
198  $view = $this->‪initializeStandaloneView('Installer/ShowEnvironmentAndFolders.html');
199  $systemCheckMessageQueue = new ‪FlashMessageQueue('install');
200  $checkMessages = (new ‪Check())->getStatus();
201  foreach ($checkMessages as $message) {
202  $systemCheckMessageQueue->enqueue($message);
203  }
204  $setupCheckMessages = (new SetupCheck())->getStatus();
205  foreach ($setupCheckMessages as $message) {
206  $systemCheckMessageQueue->enqueue($message);
207  }
208  $folderStructureFactory = GeneralUtility::makeInstance(DefaultFactory::class);
209  $structureFacade = $folderStructureFactory->getStructure();
210  $structureMessageQueue = $structureFacade->getStatus();
211  return new JsonResponse([
212  'success' => true,
213  'html' => $view->render(),
214  'environmentStatusErrors' => $systemCheckMessageQueue->getAllMessages(‪FlashMessage::ERROR),
215  'environmentStatusWarnings' => $systemCheckMessageQueue->getAllMessages(‪FlashMessage::WARNING),
216  'structureErrors' => $structureMessageQueue->getAllMessages(‪FlashMessage::ERROR),
217  ]);
218  }
219 
225  public function ‪executeEnvironmentAndFoldersAction(): ResponseInterface
226  {
227  $folderStructureFactory = GeneralUtility::makeInstance(DefaultFactory::class);
228  $structureFacade = $folderStructureFactory->getStructure();
229  $structureFixMessageQueue = $structureFacade->fix();
230  $errorsFromStructure = $structureFixMessageQueue->getAllMessages(‪FlashMessage::ERROR);
231 
232  if (@is_dir(‪Environment::getLegacyConfigPath())) {
233  $this->configurationManager->createLocalConfigurationFromFactoryConfiguration();
234 
235  // Create a PackageStates.php with all packages activated marked as "part of factory default"
236  if (!file_exists(‪Environment::getLegacyConfigPath() . '/PackageStates.php')) {
237  $packages = $this->packageManager->getAvailablePackages();
238  foreach ($packages as $package) {
239  if ($package instanceof ‪PackageInterface
240  && $package->‪isPartOfFactoryDefault()
241  ) {
242  $this->packageManager->activatePackage($package->getPackageKey());
243  }
244  }
245  $this->packageManager->forceSortAndSavePackageStates();
246  }
247  $extensionConfiguration = new ‪ExtensionConfiguration();
248  $extensionConfiguration->synchronizeExtConfTemplateWithLocalConfigurationOfAllExtensions();
249 
250  return new ‪JsonResponse([
251  'success' => true,
252  ]);
253  }
254  return new JsonResponse([
255  'success' => false,
256  'status' => $errorsFromStructure,
257  ]);
258  }
259 
265  public function ‪checkTrustedHostsPatternAction(): ResponseInterface
266  {
267  return new ‪JsonResponse([
268  'success' => GeneralUtility::hostHeaderValueMatchesTrustedHostsPattern($_SERVER['HTTP_HOST']),
269  ]);
270  }
271 
277  public function ‪executeAdjustTrustedHostsPatternAction(): ResponseInterface
278  {
279  if (!GeneralUtility::hostHeaderValueMatchesTrustedHostsPattern($_SERVER['HTTP_HOST'])) {
280  $this->configurationManager->setLocalConfigurationValueByPath('SYS/trustedHostsPattern', '.*');
281  }
282  return new JsonResponse([
283  'success' => true,
284  ]);
285  }
286 
292  public function ‪executeSilentConfigurationUpdateAction(): ResponseInterface
293  {
294  $success = true;
295  try {
296  $this->silentConfigurationUpgradeService->execute();
297  } catch (ConfigurationChangedException $e) {
298  $success = false;
299  }
300  return new JsonResponse([
301  'success' => $success,
302  ]);
303  }
304 
310  public function ‪checkDatabaseConnectAction(): ResponseInterface
311  {
312  return new ‪JsonResponse([
313  'success' => $this->‪isDatabaseConfigurationComplete() && $this->‪isDatabaseConnectSuccessful(),
314  ]);
315  }
316 
322  public function ‪showDatabaseConnectAction(): ResponseInterface
323  {
324  $view = $this->‪initializeStandaloneView('Installer/ShowDatabaseConnect.html');
325  $formProtection = ‪FormProtectionFactory::get(InstallToolFormProtection::class);
326  $hasAtLeastOneOption = false;
327  $activeAvailableOption = '';
328 
330  $hasAtLeastOneOption = true;
331  $view->assign('hasMysqliManualConfiguration', true);
332  $mysqliManualConfigurationOptions = [
333  'username' => ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['user'] ?? '',
334  'password' => ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['password'] ?? '',
335  'port' => ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['port'] ?? 3306,
336  ];
337  $host = ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['host'] ?? '127.0.0.1';
338  if ($host === 'localhost') {
339  $host = '127.0.0.1';
340  }
341  $mysqliManualConfigurationOptions['host'] = $host;
342  $view->assign('mysqliManualConfigurationOptions', $mysqliManualConfigurationOptions);
343  $activeAvailableOption = 'mysqliManualConfiguration';
344 
345  $view->assign('hasMysqliSocketManualConfiguration', true);
346  $view->assign(
347  'mysqliSocketManualConfigurationOptions',
348  [
349  'username' => ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['user'] ?? '',
350  'password' => ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['password'] ?? '',
351  'socket' => $this->‪getDatabaseConfiguredMysqliSocket(),
352  ]
353  );
354  if (‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][ConnectionPool::DEFAULT_CONNECTION_NAME]['driver'] === 'mysqli'
355  && ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['host'] === 'localhost') {
356  $activeAvailableOption = 'mysqliSocketManualConfiguration';
357  }
358  }
359 
361  $hasAtLeastOneOption = true;
362  $view->assign('hasPdoMysqlManualConfiguration', true);
363  $pdoMysqlManualConfigurationOptions = [
364  'username' => ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['user'] ?? '',
365  'password' => ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['password'] ?? '',
366  'port' => ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['port'] ?? 3306,
367  ];
368  $host = ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['host'] ?? '127.0.0.1';
369  if ($host === 'localhost') {
370  $host = '127.0.0.1';
371  }
372  $pdoMysqlManualConfigurationOptions['host'] = $host;
373  $view->assign('pdoMysqlManualConfigurationOptions', $pdoMysqlManualConfigurationOptions);
374 
375  // preselect PDO MySQL only if mysqli is not present
377  $activeAvailableOption = 'pdoMysqlManualConfiguration';
378  }
379 
380  $view->assign('hasPdoMysqlSocketManualConfiguration', true);
381  $view->assign(
382  'pdoMysqlSocketManualConfigurationOptions',
383  [
384  'username' => ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['user'] ?? '',
385  'password' => ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['password'] ?? '',
386  'socket' => $this->‪getDatabaseConfiguredPdoMysqlSocket(),
387  ]
388  );
389  if (‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][ConnectionPool::DEFAULT_CONNECTION_NAME]['driver'] === 'pdo_mysql'
390  && ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['host'] === 'localhost') {
391  $activeAvailableOption = 'pdoMysqlSocketManualConfiguration';
392  }
393  }
394 
396  $hasAtLeastOneOption = true;
397  $view->assign('hasPostgresManualConfiguration', true);
398  $view->assign(
399  'postgresManualConfigurationOptions',
400  [
401  'username' => ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['user'] ?? '',
402  'password' => ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['password'] ?? '',
403  'host' => ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['host'] ?? '127.0.0.1',
404  'port' => ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['port'] ?? 5432,
405  'database' => ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['dbname'] ?? '',
406  ]
407  );
408  if (‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['driver'] === 'pdo_pgsql') {
409  $activeAvailableOption = 'postgresManualConfiguration';
410  }
411  }
413  $hasAtLeastOneOption = true;
414  $view->assign('hasSqliteManualConfiguration', true);
415  $view->assign(
416  'sqliteManualConfigurationOptions',
417  []
418  );
419  if (‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['driver'] === 'pdo_sqlite') {
420  $activeAvailableOption = 'sqliteManualConfiguration';
421  }
422  }
423 
424  if (!empty($this->‪getDatabaseConfigurationFromEnvironment())) {
425  $hasAtLeastOneOption = true;
426  $activeAvailableOption = 'configurationFromEnvironment';
427  $view->assign('hasConfigurationFromEnvironment', true);
428  }
429 
430  $view->assignMultiple([
431  'hasAtLeastOneOption' => $hasAtLeastOneOption,
432  'activeAvailableOption' => $activeAvailableOption,
433  'executeDatabaseConnectToken' => $formProtection->generateToken('installTool', 'executeDatabaseConnect'),
434  ]);
435 
436  return new JsonResponse([
437  'success' => true,
438  'html' => $view->render(),
439  ]);
440  }
441 
448  public function ‪executeDatabaseConnectAction(ServerRequestInterface $request): ResponseInterface
449  {
450  $messages = [];
451  $postValues = $request->getParsedBody()['install']['values'];
452  $defaultConnectionSettings = [];
453 
454  if ($postValues['availableSet'] === 'configurationFromEnvironment') {
455  $defaultConnectionSettings = $this->‪getDatabaseConfigurationFromEnvironment();
456  } else {
457  if (isset($postValues['driver'])) {
458  $validDrivers = [
459  'mysqli',
460  'pdo_mysql',
461  'pdo_pgsql',
462  'mssql',
463  'pdo_sqlite',
464  ];
465  if (in_array($postValues['driver'], $validDrivers, true)) {
466  $defaultConnectionSettings['driver'] = $postValues['driver'];
467  } else {
468  $messages[] = new ‪FlashMessage(
469  'Given driver must be one of ' . implode(', ', $validDrivers),
470  'Database driver unknown',
472  );
473  }
474  }
475  if (isset($postValues['username'])) {
476  $value = $postValues['username'];
477  if (strlen($value) <= 50) {
478  $defaultConnectionSettings['user'] = $value;
479  } else {
480  $messages[] = new ‪FlashMessage(
481  'Given username must be shorter than fifty characters.',
482  'Database username not valid',
484  );
485  }
486  }
487  if (isset($postValues['password'])) {
488  $defaultConnectionSettings['password'] = $postValues['password'];
489  }
490  if (isset($postValues['host'])) {
491  $value = $postValues['host'];
492  if (preg_match('/^[a-zA-Z0-9_\\.-]+(:.+)?$/', $value) && strlen($value) <= 255) {
493  $defaultConnectionSettings['host'] = $value;
494  } else {
495  $messages[] = new ‪FlashMessage(
496  'Given host is not alphanumeric (a-z, A-Z, 0-9 or _-.:) or longer than 255 characters.',
497  'Database host not valid',
499  );
500  }
501  }
502  if (isset($postValues['port']) && $postValues['host'] !== 'localhost') {
503  $value = $postValues['port'];
504  if (preg_match('/^[0-9]+(:.+)?$/', $value) && $value > 0 && $value <= 65535) {
505  $defaultConnectionSettings['port'] = (int)$value;
506  } else {
507  $messages[] = new ‪FlashMessage(
508  'Given port is not numeric or within range 1 to 65535.',
509  'Database port not valid',
511  );
512  }
513  }
514  if (isset($postValues['socket']) && $postValues['socket'] !== '') {
515  if (@file_exists($postValues['socket'])) {
516  $defaultConnectionSettings['unix_socket'] = $postValues['socket'];
517  } else {
518  $messages[] = new ‪FlashMessage(
519  'Given socket location does not exist on server.',
520  'Socket does not exist',
522  );
523  }
524  }
525  if (isset($postValues['database'])) {
526  $value = $postValues['database'];
527  if (strlen($value) <= 50) {
528  $defaultConnectionSettings['dbname'] = $value;
529  } else {
530  $messages[] = new ‪FlashMessage(
531  'Given database name must be shorter than fifty characters.',
532  'Database name not valid',
534  );
535  }
536  }
537  // For sqlite a db path is automatically calculated
538  if (isset($postValues['driver']) && $postValues['driver'] === 'pdo_sqlite') {
539  $dbFilename = '/cms-' . (new ‪Random())->generateRandomHexString(8) . '.sqlite';
540  // If the var/ folder exists outside of document root, put it into var/sqlite/
541  // Otherwise simply into typo3conf/
544  $defaultConnectionSettings['path'] = ‪Environment::getVarPath() . '/sqlite' . $dbFilename;
545  } else {
546  $defaultConnectionSettings['path'] = ‪Environment::getConfigPath() . $dbFilename;
547  }
548  }
549  // For mysql, set utf8mb4 as default charset
550  if (isset($postValues['driver']) && in_array($postValues['driver'], ['mysqli', 'pdo_mysql'])) {
551  $defaultConnectionSettings['charset'] = 'utf8mb4';
552  $defaultConnectionSettings['tableoptions'] = [
553  'charset' => 'utf8mb4',
554  'collate' => 'utf8mb4_unicode_ci',
555  ];
556  }
557  }
558 
559  $success = false;
560  if (!empty($defaultConnectionSettings)) {
561  // Test connection settings and write to config if connect is successful
562  try {
563  $connectionParams = $defaultConnectionSettings;
564  $connectionParams['wrapperClass'] = Connection::class;
565  if (!isset($connectionParams['charset'])) {
566  // utf-8 as default for non mysql
567  $connectionParams['charset'] = 'utf-8';
568  }
569  DriverManager::getConnection($connectionParams)->ping();
570  $success = true;
571  } catch (DBALException $e) {
572  $messages[] = new ‪FlashMessage(
573  'Connecting to the database with given settings failed: ' . $e->getMessage(),
574  'Database connect not successful',
576  );
577  }
578  $localConfigurationPathValuePairs = [];
579  foreach ($defaultConnectionSettings as $settingsName => $value) {
580  $localConfigurationPathValuePairs['DB/Connections/Default/' . $settingsName] = $value;
581  }
582  // Remove full default connection array
583  $this->configurationManager->removeLocalConfigurationKeysByPath(['DB/Connections/Default']);
584  // Write new values
585  $this->configurationManager->setLocalConfigurationValuesByPathValuePairs($localConfigurationPathValuePairs);
586  }
587 
588  return new ‪JsonResponse([
589  'success' => $success,
590  'status' => $messages,
591  ]);
592  }
593 
599  public function ‪checkDatabaseSelectAction(): ResponseInterface
600  {
601  $success = false;
602  if ((string)‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['dbname'] !== ''
603  || (string)‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['path'] !== ''
604  ) {
605  try {
606  $success = GeneralUtility::makeInstance(ConnectionPool::class)
607  ->getConnectionByName(‪ConnectionPool::DEFAULT_CONNECTION_NAME)
608  ->ping();
609  } catch (DBALException $e) {
610  }
611  }
612  return new JsonResponse([
613  'success' => $success,
614  ]);
615  }
616 
622  public function ‪showDatabaseSelectAction(): ResponseInterface
623  {
624  $view = $this->‪initializeStandaloneView('Installer/ShowDatabaseSelect.html');
625  $formProtection = ‪FormProtectionFactory::get(InstallToolFormProtection::class);
626  ‪$errors = [];
627  try {
628  $view->assign('databaseList', $this->‪getDatabaseList());
629  } catch (\‪Exception $exception) {
630  ‪$errors[] = $exception->getMessage();
631  }
632  $view->assignMultiple([
633  'errors' => ‪$errors,
634  'executeDatabaseSelectToken' => $formProtection->generateToken('installTool', 'executeDatabaseSelect'),
635  'executeCheckDatabaseRequirementsToken' => $formProtection->generateToken('installTool', 'checkDatabaseRequirements'),
636  ]);
637  return new JsonResponse([
638  'success' => true,
639  'html' => $view->render(),
640  ]);
641  }
642 
648  public function ‪checkDatabaseRequirementsAction(ServerRequestInterface $request): ResponseInterface
649  {
650  $success = true;
651  $messages = [];
652  $databaseDriverName = ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['driver'];
653 
654  $databaseName = $this->‪retrieveDatabaseNameFromRequest($request);
655  if ($databaseName === '') {
656  return new ‪JsonResponse([
657  'success' => false,
658  'status' => [
659  new ‪FlashMessage(
660  'You must select a database.',
661  'No Database selected',
663  ),
664  ],
665  ]);
666  }
667 
668  ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['dbname'] = $databaseName;
669 
670  foreach ($this->‪checkDatabaseRequirementsForDriver($databaseDriverName) as $message) {
671  if ($message->getSeverity() === ‪FlashMessage::ERROR) {
672  $success = false;
673  $messages[] = $message;
674  }
675  }
676 
677  // Check create and drop permissions
678  $statusMessages = [];
679  foreach ($this->‪checkRequiredDatabasePermissions() as $checkRequiredPermission) {
680  $statusMessages[] = new FlashMessage(
681  $checkRequiredPermission,
682  'Missing required permissions',
684  );
685  }
686  if ($statusMessages !== []) {
687  return new JsonResponse([
688  'success' => false,
689  'status' => $statusMessages,
690  ]);
691  }
692 
693  // if requirements are not fulfilled
694  if ($success === false) {
695  // remove the database again if we created it
696  if ($request->getParsedBody()['install']['values']['type'] === 'new') {
697  $connection = GeneralUtility::makeInstance(ConnectionPool::class)
698  ->getConnectionByName(‪ConnectionPool::DEFAULT_CONNECTION_NAME);
699  $connection
700  ->getSchemaManager()
701  ->dropDatabase($connection->quoteIdentifier($databaseName));
702  }
703 
704  $this->configurationManager->removeLocalConfigurationKeysByPath(['DB/Connections/Default/dbname']);
705 
706  $message = new FlashMessage(
707  sprintf(
708  'Database with name "%s" has been removed due to the following errors. '
709  . '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',
710  $databaseName
711  ),
712  '',
714  );
715  array_unshift($messages, $message);
716  }
717 
718  unset(‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['dbname']);
719 
720  return new ‪JsonResponse([
721  'success' => $success,
722  'status' => $messages,
723  ]);
724  }
725 
726  private function ‪checkRequiredDatabasePermissions(): array
727  {
728  try {
729  return $this->databasePermissionsCheck
730  ->checkCreateAndDrop()
731  ->checkAlter()
732  ->checkIndex()
733  ->checkCreateTemporaryTable()
734  ->checkInsert()
735  ->checkSelect()
736  ->checkUpdate()
737  ->checkDelete()
738  ->getMessages();
739  } catch (\‪TYPO3\CMS\Install\Configuration\‪Exception $exception) {
740  return $this->databasePermissionsCheck->getMessages();
741  }
742  }
743 
744  private function ‪checkDatabaseRequirementsForDriver(string $databaseDriverName): FlashMessageQueue
745  {
746  $databaseCheck = GeneralUtility::makeInstance(DatabaseCheck::class);
747  try {
748  $databaseDriverClassName = ‪DatabaseCheck::retrieveDatabaseDriverClassByDriverName($databaseDriverName);
749 
750  $databaseCheck->checkDatabasePlatformRequirements($databaseDriverClassName);
751  $databaseCheck->checkDatabaseDriverRequirements($databaseDriverClassName);
752 
753  return $databaseCheck->getMessageQueue();
754  } catch (Exception $exception) {
755  $flashMessageQueue = new FlashMessageQueue('database-check-requirements');
756  $flashMessageQueue->enqueue(
757  new FlashMessage(
758  '',
759  $exception->getMessage(),
761  )
762  );
763  return $flashMessageQueue;
764  }
765  }
766 
767  private function ‪retrieveDatabaseNameFromRequest(ServerRequestInterface $request): string
768  {
769  $postValues = $request->getParsedBody()['install']['values'];
770  if ($postValues['type'] === 'new') {
771  return $postValues['new'];
772  }
773 
774  if ($postValues['type'] === 'existing' && !empty($postValues['existing'])) {
775  return $postValues['existing'];
776  }
777  return '';
778  }
779 
786  public function ‪executeDatabaseSelectAction(ServerRequestInterface $request): ResponseInterface
787  {
788  $databaseName = $this->‪retrieveDatabaseNameFromRequest($request);
789  if ($databaseName === '') {
790  return new ‪JsonResponse([
791  'success' => false,
792  'status' => [
793  new ‪FlashMessage(
794  'You must select a database.',
795  'No Database selected',
797  ),
798  ],
799  ]);
800  }
801 
802  $postValues = $request->getParsedBody()['install']['values'];
803  if ($postValues['type'] === 'new') {
804  $status = $this->‪createNewDatabase($databaseName);
805  if ($status->getSeverity() === ‪FlashMessage::ERROR) {
806  return new ‪JsonResponse([
807  'success' => false,
808  'status' => [$status],
809  ]);
810  }
811  } elseif ($postValues['type'] === 'existing') {
812  $status = $this->‪checkExistingDatabase($databaseName);
813  if ($status->getSeverity() === ‪FlashMessage::ERROR) {
814  return new ‪JsonResponse([
815  'success' => false,
816  'status' => [$status],
817  ]);
818  }
819  }
820  return new ‪JsonResponse([
821  'success' => true,
822  ]);
823  }
824 
830  public function ‪checkDatabaseDataAction(): ResponseInterface
831  {
832  $existingTables = GeneralUtility::makeInstance(ConnectionPool::class)
833  ->getConnectionByName(‪ConnectionPool::DEFAULT_CONNECTION_NAME)
834  ->getSchemaManager()
835  ->listTableNames();
836  return new ‪JsonResponse([
837  'success' => !empty($existingTables),
838  ]);
839  }
840 
846  public function ‪showDatabaseDataAction(): ResponseInterface
847  {
848  $view = $this->‪initializeStandaloneView('Installer/ShowDatabaseData.html');
849  $formProtection = ‪FormProtectionFactory::get(InstallToolFormProtection::class);
850  $view->assignMultiple([
851  'siteName' => ‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'],
852  'executeDatabaseDataToken' => $formProtection->generateToken('installTool', 'executeDatabaseData'),
853  ]);
854  return new ‪JsonResponse([
855  'success' => true,
856  'html' => $view->render(),
857  ]);
858  }
859 
866  public function ‪executeDatabaseDataAction(ServerRequestInterface $request): ResponseInterface
867  {
868  $messages = [];
869  $postValues = $request->getParsedBody()['install']['values'];
870  $username = (string)$postValues['username'] !== '' ? $postValues['username'] : 'admin';
871  // Check password and return early if not good enough
872  $password = $postValues['password'];
873  $email = $postValues['email'] ?? '';
874  if (empty($password) || strlen($password) < 8) {
875  $messages[] = new ‪FlashMessage(
876  'You are setting an important password here! It gives an attacker full control over your instance if cracked.'
877  . ' It should be strong (include lower and upper case characters, special characters and numbers) and must be at least eight characters long.',
878  'Administrator password not secure enough!',
880  );
881  return new ‪JsonResponse([
882  'success' => false,
883  'status' => $messages,
884  ]);
885  }
886  // Set site name
887  if (!empty($postValues['sitename'])) {
888  $this->configurationManager->setLocalConfigurationValueByPath('SYS/sitename', $postValues['sitename']);
889  }
890  try {
891  $messages = $this->‪importDatabaseData();
892  if (!empty($messages)) {
893  return new ‪JsonResponse([
894  'success' => false,
895  'status' => $messages,
896  ]);
897  }
898  } catch (‪StatementException $exception) {
899  $messages[] = new ‪FlashMessage(
900  'Error detected in SQL statement:' . LF . $exception->getMessage(),
901  'Import of database data could not be performed',
903  );
904  return new ‪JsonResponse([
905  'success' => false,
906  'status' => $messages,
907  ]);
908  }
909  // Insert admin user
910  $adminUserFields = [
911  'username' => $username,
912  'password' => $this->‪getHashedPassword($password),
913  'email' => GeneralUtility::validEmail($email) ? $email : '',
914  'admin' => 1,
915  'tstamp' => ‪$GLOBALS['EXEC_TIME'],
916  'crdate' => ‪$GLOBALS['EXEC_TIME']
917  ];
918  $databaseConnection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('be_users');
919  try {
920  $databaseConnection->insert('be_users', $adminUserFields);
921  $adminUserUid = (int)$databaseConnection->lastInsertId('be_users');
922  } catch (DBALException $exception) {
923  $messages[] = new ‪FlashMessage(
924  'The administrator account could not be created. The following error occurred:' . LF
925  . $exception->getPrevious()->getMessage(),
926  'Administrator account not created!',
928  );
929  return new ‪JsonResponse([
930  'success' => false,
931  'status' => $messages,
932  ]);
933  }
934  // Set password as install tool password, add admin user to system maintainers
935  $this->configurationManager->setLocalConfigurationValuesByPathValuePairs([
936  'BE/installToolPassword' => $this->‪getHashedPassword($password),
937  'SYS/systemMaintainers' => [$adminUserUid]
938  ]);
939  return new ‪JsonResponse([
940  'success' => true,
941  'status' => $messages,
942  ]);
943  }
944 
950  public function ‪showDefaultConfigurationAction(): ResponseInterface
951  {
952  $view = $this->‪initializeStandaloneView('Installer/ShowDefaultConfiguration.html');
953  $formProtection = ‪FormProtectionFactory::get(InstallToolFormProtection::class);
954  $view->assignMultiple([
955  'composerMode' => ‪Environment::isComposerMode(),
956  'executeDefaultConfigurationToken' => $formProtection->generateToken('installTool', 'executeDefaultConfiguration'),
957  ]);
958  return new ‪JsonResponse([
959  'success' => true,
960  'html' => $view->render(),
961  ]);
962  }
963 
970  public function ‪executeDefaultConfigurationAction(ServerRequestInterface $request): ResponseInterface
971  {
972  $featureManager = new ‪FeatureManager();
973  // Get best matching configuration presets
974  $configurationValues = $featureManager->getBestMatchingConfigurationForAllFeatures();
975  $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
976 
977  // Let the admin user redirect to the distributions page on first login
978  switch ($request->getParsedBody()['install']['values']['sitesetup']) {
979  // Update the admin backend user to show the distribution management on login
980  case 'loaddistribution':
981  $adminUserFirstLogin = [
982  'startModuleOnFirstLogin' => 'tools_ExtensionmanagerExtensionmanager->tx_extensionmanager_tools_extensionmanagerextensionmanager%5Baction%5D=distributions&tx_extensionmanager_tools_extensionmanagerextensionmanager%5Bcontroller%5D=List',
983  'ucSetByInstallTool' => '1',
984  ];
985  $connectionPool->getConnectionForTable('be_users')->update(
986  'be_users',
987  ['uc' => serialize($adminUserFirstLogin)],
988  ['admin' => 1],
989  ['uc' => ‪Connection::PARAM_LOB]
990  );
991  break;
992 
993  // Create a page with UID 1 and PID1 and fluid_styled_content for page TS config, respect ownership
994  case 'createsite':
995  $databaseConnectionForPages = $connectionPool->getConnectionForTable('pages');
996  $databaseConnectionForPages->insert(
997  'pages',
998  [
999  'pid' => 0,
1000  'crdate' => time(),
1001  'cruser_id' => 1,
1002  'tstamp' => time(),
1003  'title' => 'Home',
1004  'slug' => '/',
1005  'doktype' => 1,
1006  'is_siteroot' => 1,
1007  'perms_userid' => 1,
1008  'perms_groupid' => 1,
1009  'perms_user' => 31,
1010  'perms_group' => 31,
1011  'perms_everybody' => 1
1012  ]
1013  );
1014  $pageUid = $databaseConnectionForPages->lastInsertId('pages');
1015 
1016  // add a root sys_template with fluid_styled_content and a default PAGE typoscript snippet
1017  $connectionPool->getConnectionForTable('sys_template')->insert(
1018  'sys_template',
1019  [
1020  'pid' => $pageUid,
1021  'crdate' => time(),
1022  'cruser_id' => 1,
1023  'tstamp' => time(),
1024  'title' => 'Main TypoScript Rendering',
1025  'sitetitle' => ‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'],
1026  'root' => 1,
1027  'clear' => 1,
1028  'include_static_file' => 'EXT:fluid_styled_content/Configuration/TypoScript/,EXT:fluid_styled_content/Configuration/TypoScript/Styling/',
1029  'constants' => '',
1030  'config' => 'page = PAGE
1031 page.10 = TEXT
1032 page.10.value (
1033  <div style="width: 800px; margin: 15% auto;">
1034  <div style="width: 300px;">
1035  <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>
1036  </div>
1037  <h4 style="font-family: sans-serif;">Welcome to a default website made with <a href="https://typo3.org">TYPO3</a></h4>
1038  </div>
1039 )
1040 page.100 = CONTENT
1041 page.100 {
1042  table = tt_content
1043  select {
1044  orderBy = sorting
1045  where = {#colPos}=0
1046  }
1047 }
1048 ',
1049  'description' => 'This is an Empty Site Package TypoScript template.
1050 
1051 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\''
1052  ]
1053  );
1054 
1055  $this->‪createSiteConfiguration('main', (int)$pageUid, $request);
1056  break;
1057  }
1058 
1059  // Mark upgrade wizards as done
1060  $this->lateBootService->loadExtLocalconfDatabaseAndExtTables();
1061  if (!empty(‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update'])) {
1062  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update'] as $updateClassName) {
1063  if (!in_array(RepeatableInterface::class, class_implements($updateClassName), true)) {
1064  $this->registry->set('installUpdate', $updateClassName, 1);
1065  }
1066  }
1067  }
1068  $this->registry->set('installUpdateRows', 'rowUpdatersDone', GeneralUtility::makeInstance(DatabaseRowsUpdateWizard::class)->getAvailableRowUpdater());
1069 
1070  $this->configurationManager->setLocalConfigurationValuesByPathValuePairs($configurationValues);
1071 
1072  $formProtection = ‪FormProtectionFactory::get(InstallToolFormProtection::class);
1073  $formProtection->clean();
1074 
1076 
1077  return new ‪JsonResponse([
1078  'success' => true,
1079  'redirect' => GeneralUtility::getIndpEnv('TYPO3_SITE_URL') . TYPO3_mainDir . 'index.php',
1080  ]);
1081  }
1082 
1090  protected function ‪initializeStandaloneView(string $templatePath): ‪StandaloneView
1091  {
1092  $viewRootPath = GeneralUtility::getFileAbsFileName('EXT:install/Resources/Private/');
1093  $view = GeneralUtility::makeInstance(StandaloneView::class);
1094  $view->getRequest()->setControllerExtensionName('Install');
1095  $view->setTemplatePathAndFilename($viewRootPath . 'Templates/' . $templatePath);
1096  $view->setLayoutRootPaths([$viewRootPath . 'Layouts/']);
1097  $view->setPartialRootPaths([$viewRootPath . 'Partials/']);
1098  return $view;
1099  }
1100 
1106  protected function ‪isDatabaseConnectSuccessful(): bool
1107  {
1108  try {
1109  GeneralUtility::makeInstance(ConnectionPool::class)
1110  ->getConnectionByName(‪ConnectionPool::DEFAULT_CONNECTION_NAME)
1111  ->ping();
1112  } catch (DBALException $e) {
1113  return false;
1114  }
1115  return true;
1116  }
1117 
1125  protected function ‪isDatabaseConfigurationComplete()
1126  {
1127  $configurationComplete = true;
1128  if (!isset(‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['user'])) {
1129  $configurationComplete = false;
1130  }
1131  if (!isset(‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['password'])) {
1132  $configurationComplete = false;
1133  }
1134  if (isset(‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['driver'])
1135  && ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['driver'] === 'pdo_sqlite'
1136  && !empty(‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['path'])
1137  ) {
1138  $configurationComplete = true;
1139  }
1140  return $configurationComplete;
1141  }
1142 
1148  protected function ‪getDatabaseConfiguredMysqliSocket(): string
1149  {
1150  return $this->‪getDefaultSocketFor('mysqli.default_socket');
1151  }
1152 
1158  protected function ‪getDatabaseConfiguredPdoMysqlSocket(): string
1159  {
1160  return $this->‪getDefaultSocketFor('pdo_mysql.default_socket');
1161  }
1162 
1168  private function ‪getDefaultSocketFor(string $phpIniSetting): string
1169  {
1170  $socket = ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['unix_socket'] ?? '';
1171  if ($socket === '') {
1172  // If no configured socket, use default php socket
1173  $defaultSocket = (string)ini_get($phpIniSetting);
1174  if ($defaultSocket !== '') {
1175  $socket = $defaultSocket;
1176  }
1177  }
1178  return $socket;
1179  }
1180 
1186  protected function ‪getDatabaseConfigurationFromEnvironment(): array
1187  {
1188  $envCredentials = [];
1189  foreach (['driver', 'host', 'user', 'password', 'port', 'dbname', 'unix_socket'] as $value) {
1190  $envVar = 'TYPO3_INSTALL_DB_' . strtoupper($value);
1191  if (getenv($envVar) !== false) {
1192  $envCredentials[$value] = getenv($envVar);
1193  }
1194  }
1195  if (!empty($envCredentials)) {
1196  $connectionParams = $envCredentials;
1197  $connectionParams['wrapperClass'] = Connection::class;
1198  $connectionParams['charset'] = 'utf-8';
1199  try {
1200  DriverManager::getConnection($connectionParams)->ping();
1201  return $envCredentials;
1202  } catch (DBALException $e) {
1203  return [];
1204  }
1205  }
1206  return [];
1207  }
1208 
1214  protected function ‪getDatabaseList()
1215  {
1216  $connectionParams = ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME];
1217  unset($connectionParams['dbname']);
1218 
1219  // Establishing the connection using the Doctrine DriverManager directly
1220  // as we need a connection without selecting a database right away. Otherwise
1221  // an invalid database name would lead to exceptions which would prevent
1222  // changing the currently configured database.
1223  $connection = DriverManager::getConnection($connectionParams);
1224  $databaseArray = $connection->getSchemaManager()->listDatabases();
1225  $connection->close();
1226 
1227  // Remove organizational tables from database list
1228  $reservedDatabaseNames = ['mysql', 'information_schema', 'performance_schema'];
1229  $allPossibleDatabases = array_diff($databaseArray, $reservedDatabaseNames);
1230 
1231  // In first installation we show all databases but disable not empty ones (with tables)
1232  $databases = [];
1233  foreach ($allPossibleDatabases as $databaseName) {
1234  // Reestablishing the connection for each database since there is no
1235  // portable way to switch databases on the same Doctrine connection.
1236  // Directly using the Doctrine DriverManager here to avoid messing with
1237  // the $GLOBALS database configuration array.
1238  try {
1239  $connectionParams['dbname'] = $databaseName;
1240  $connection = DriverManager::getConnection($connectionParams);
1241 
1242  $databases[] = [
1243  'name' => $databaseName,
1244  'tables' => count($connection->getSchemaManager()->listTableNames()),
1245  'readonly' => false
1246  ];
1247  $connection->close();
1248  } catch (ConnectionException $exception) {
1249  $databases[] = [
1250  'name' => $databaseName,
1251  'tables' => 0,
1252  'readonly' => true
1253  ];
1254  // we ignore a connection exception here.
1255  // if this happens here, the show tables was successful
1256  // but the connection failed because of missing permissions.
1257  }
1258  }
1259 
1260  return $databases;
1261  }
1269  protected function ‪createNewDatabase($dbName)
1270  {
1271  try {
1272  $platform = GeneralUtility::makeInstance(ConnectionPool::class)
1273  ->getConnectionByName(‪ConnectionPool::DEFAULT_CONNECTION_NAME)
1274  ->getDatabasePlatform();
1275  $connection = GeneralUtility::makeInstance(ConnectionPool::class)
1276  ->getConnectionByName(‪ConnectionPool::DEFAULT_CONNECTION_NAME);
1277  $connection->exec(
1279  $platform,
1280  $connection->quoteIdentifier($dbName)
1281  )
1282  );
1283  $this->configurationManager
1284  ->setLocalConfigurationValueByPath('DB/Connections/Default/dbname', $dbName);
1285  } catch (DBALException $e) {
1286  return new ‪FlashMessage(
1287  'Database with name "' . $dbName . '" could not be created.'
1288  . ' Either your database name contains a reserved keyword or your database'
1289  . ' user does not have sufficient permissions to create it or the database already exists.'
1290  . ' Please choose an existing (empty) database, choose another name or contact administration.',
1291  'Unable to create database',
1293  );
1294  }
1295  return new ‪FlashMessage(
1296  '',
1297  'Database created'
1298  );
1299  }
1300 
1309  protected function ‪checkExistingDatabase($dbName)
1310  {
1311  $result = new ‪FlashMessage('');
1312  $localConfigurationPathValuePairs = [];
1313 
1314  ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][‪ConnectionPool::DEFAULT_CONNECTION_NAME]['dbname'] = $dbName;
1315  try {
1316  $connection = GeneralUtility::makeInstance(ConnectionPool::class)
1317  ->getConnectionByName(‪ConnectionPool::DEFAULT_CONNECTION_NAME);
1318 
1319  if (!empty($connection->getSchemaManager()->listTableNames())) {
1320  $result = new ‪FlashMessage(
1321  sprintf('Cannot use database "%s"', $dbName)
1322  . ', because it already contains tables. Please select a different database or choose to create one!',
1323  'Selected database is not empty!',
1325  );
1326  }
1327  } catch (\Exception $e) {
1328  $result = new FlashMessage(
1329  sprintf('Could not connect to database "%s"', $dbName)
1330  . '! Make sure it really exists and your database user has the permissions to select it!',
1331  'Could not connect to selected database!',
1333  );
1334  }
1335 
1336  if ($result->getSeverity() === ‪FlashMessage::OK) {
1337  $localConfigurationPathValuePairs['DB/Connections/Default/dbname'] = $dbName;
1338  }
1339 
1340  if ($result->getSeverity() === ‪FlashMessage::OK && !empty($localConfigurationPathValuePairs)) {
1341  $this->configurationManager->setLocalConfigurationValuesByPathValuePairs($localConfigurationPathValuePairs);
1342  }
1343 
1344  return $result;
1345  }
1346 
1359  protected function ‪getHashedPassword($password)
1360  {
1361  $okHashMethods = [
1362  Argon2iPasswordHash::class,
1363  Argon2idPasswordHash::class,
1364  BcryptPasswordHash::class,
1365  Pbkdf2PasswordHash::class,
1366  PhpassPasswordHash::class,
1367  ];
1368  foreach ($okHashMethods as $className) {
1370  $instance = GeneralUtility::makeInstance($className);
1371  if ($instance->isAvailable()) {
1372  return $instance->getHashedPassword($password);
1373  }
1374  }
1375  throw new \LogicException('No suitable hash method found', 1533988846);
1376  }
1377 
1383  protected function ‪importDatabaseData()
1384  {
1385  // Will load ext_localconf and ext_tables. This is pretty safe here since we are
1386  // in first install (database empty), so it is very likely that no extension is loaded
1387  // that could trigger a fatal at this point.
1388  $container = $this->lateBootService->loadExtLocalconfDatabaseAndExtTables();
1389 
1390  $sqlReader = $container->get(SqlReader::class);
1391  $sqlCode = $sqlReader->getTablesDefinitionString(true);
1392  $schemaMigrationService = GeneralUtility::makeInstance(SchemaMigrator::class);
1393  $createTableStatements = $sqlReader->getCreateTableStatementArray($sqlCode);
1394  $results = $schemaMigrationService->install($createTableStatements);
1395 
1396  // Only keep statements with error messages
1397  $results = array_filter($results);
1398  if (count($results) === 0) {
1399  $insertStatements = $sqlReader->getInsertStatementArray($sqlCode);
1400  $results = $schemaMigrationService->importStaticData($insertStatements);
1401  }
1402  foreach ($results as $statement => &$message) {
1403  if ($message === '') {
1404  unset($results[$statement]);
1405  continue;
1406  }
1407  $message = new FlashMessage(
1408  'Query:' . LF . ' ' . $statement . LF . 'Error:' . LF . ' ' . $message,
1409  'Database query failed!',
1411  );
1412  }
1413  return array_values($results);
1414  }
1415 
1424  protected function ‪createSiteConfiguration(string $identifier, int $rootPageId, ServerRequestInterface $request)
1425  {
1426  $normalizedParams = $request->getAttribute('normalizedParams', null);
1427  if (!($normalizedParams instanceof NormalizedParams)) {
1428  $normalizedParams = ‪NormalizedParams::createFromRequest($request);
1429  }
1430  // Check for siteUrl, despite there currently is no UI to provide it,
1431  // to allow TYPO3 Console (for TYPO3 v10) to set this value to something reasonable,
1432  // because on cli there is no way to find out which hostname the site is supposed to have.
1433  // In the future this controller should be refactored to a generic service, where site URL is
1434  // just one input argument.
1435  $siteUrl = $request->getParsedBody()['install']['values']['siteUrl'] ?? $normalizedParams->getSiteUrl();
1436 
1437  // Create a default site configuration called "main" as best practice
1438  $this->siteConfiguration->createNewBasicSite($identifier, $rootPageId, $siteUrl);
1439  }
1440 }
‪TYPO3\CMS\Install\Controller\InstallerController\executeDatabaseSelectAction
‪ResponseInterface executeDatabaseSelectAction(ServerRequestInterface $request)
Definition: InstallerController.php:779
‪TYPO3\CMS\Install\Controller\InstallerController\checkEnvironmentAndFoldersAction
‪ResponseInterface checkEnvironmentAndFoldersAction()
Definition: InstallerController.php:177
‪TYPO3\CMS\Install\Controller\InstallerController\executeDefaultConfigurationAction
‪ResponseInterface executeDefaultConfigurationAction(ServerRequestInterface $request)
Definition: InstallerController.php:963
‪TYPO3\CMS\Core\FormProtection\FormProtectionFactory\get
‪static TYPO3 CMS Core FormProtection AbstractFormProtection get($classNameOrType='default',... $constructorArguments)
Definition: FormProtectionFactory.php:74
‪TYPO3\CMS\Core\Crypto\PasswordHashing\BcryptPasswordHash
Definition: BcryptPasswordHash.php:32
‪TYPO3\CMS\Install\Updates\RepeatableInterface
Definition: RepeatableInterface.php:26
‪TYPO3\CMS\Install\Controller\InstallerController\$databasePermissionsCheck
‪PermissionsCheck $databasePermissionsCheck
Definition: InstallerController.php:101
‪TYPO3\CMS\Install\Configuration\FeatureManager
Definition: FeatureManager.php:30
‪TYPO3\CMS\Core\Core\Environment\getPublicPath
‪static string getPublicPath()
Definition: Environment.php:180
‪TYPO3\CMS\Core\Database\Schema\Exception\StatementException
Definition: StatementException.php:24
‪TYPO3\CMS\Install\Controller\InstallerController\checkDatabaseConnectAction
‪ResponseInterface checkDatabaseConnectAction()
Definition: InstallerController.php:303
‪TYPO3\CMS\Install\Controller\InstallerController\createSiteConfiguration
‪createSiteConfiguration(string $identifier, int $rootPageId, ServerRequestInterface $request)
Definition: InstallerController.php:1417
‪TYPO3\CMS\Core\Package\FailsafePackageManager
Definition: FailsafePackageManager.php:26
‪TYPO3\CMS\Install\Service\Exception\ConfigurationChangedException
Definition: ConfigurationChangedException.php:26
‪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:859
‪TYPO3\CMS\Install\Service\SilentConfigurationUpgradeService
Definition: SilentConfigurationUpgradeService.php:44
‪TYPO3\CMS\Core\Package\PackageInterface\isPartOfFactoryDefault
‪bool isPartOfFactoryDefault()
‪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:89
‪TYPO3
‪TYPO3\CMS\Install\Controller\InstallerController\getDatabaseConfiguredMysqliSocket
‪string getDatabaseConfiguredMysqliSocket()
Definition: InstallerController.php:1141
‪TYPO3\CMS\Install\Controller\InstallerController\checkDatabaseDataAction
‪ResponseInterface checkDatabaseDataAction()
Definition: InstallerController.php:823
‪TYPO3\CMS\Core\Registry
Definition: Registry.php:33
‪TYPO3\CMS\Install\Controller\InstallerController\getDefaultSocketFor
‪string getDefaultSocketFor(string $phpIniSetting)
Definition: InstallerController.php:1161
‪TYPO3\CMS\Install\SystemEnvironment\DatabaseCheck\isPdoSqlite
‪static isPdoSqlite()
Definition: DatabaseCheck.php:317
‪TYPO3\CMS\Install\Controller\InstallerController\checkDatabaseRequirementsForDriver
‪checkDatabaseRequirementsForDriver(string $databaseDriverName)
Definition: InstallerController.php:737
‪TYPO3\CMS\Install\Controller\InstallerController\$registry
‪Registry $registry
Definition: InstallerController.php:93
‪TYPO3\CMS\Install\Service\EnableFileService
Definition: EnableFileService.php:26
‪TYPO3\CMS\Install\Controller\InstallerController\executeDatabaseConnectAction
‪ResponseInterface executeDatabaseConnectAction(ServerRequestInterface $request)
Definition: InstallerController.php:441
‪TYPO3\CMS\Install\Controller\InstallerController\createNewDatabase
‪FlashMessage createNewDatabase($dbName)
Definition: InstallerController.php:1262
‪TYPO3\CMS\Install\FolderStructure\DefaultFactory
Definition: DefaultFactory.php:25
‪TYPO3\CMS\Install\Controller\InstallerController\getDatabaseConfigurationFromEnvironment
‪array getDatabaseConfigurationFromEnvironment()
Definition: InstallerController.php:1179
‪TYPO3\CMS\Install\Controller\InstallerController\checkDatabaseSelectAction
‪ResponseInterface checkDatabaseSelectAction()
Definition: InstallerController.php:592
‪TYPO3\CMS\Install\Controller\InstallerController\getDatabaseConfiguredPdoMysqlSocket
‪string getDatabaseConfiguredPdoMysqlSocket()
Definition: InstallerController.php:1151
‪TYPO3\CMS\Core\Database\Schema\SqlReader
Definition: SqlReader.php:31
‪TYPO3\CMS\Core\Configuration\SiteConfiguration
Definition: SiteConfiguration.php:41
‪TYPO3\CMS\Install\Controller\InstallerController\executeEnvironmentAndFoldersAction
‪ResponseInterface executeEnvironmentAndFoldersAction()
Definition: InstallerController.php:218
‪TYPO3\CMS\Install\Controller\InstallerController\showDatabaseSelectAction
‪ResponseInterface showDatabaseSelectAction()
Definition: InstallerController.php:615
‪TYPO3\CMS\Install\Controller\InstallerController\executeAdjustTrustedHostsPatternAction
‪ResponseInterface executeAdjustTrustedHostsPatternAction()
Definition: InstallerController.php:270
‪TYPO3\CMS\Install\Controller\InstallerController\isDatabaseConnectSuccessful
‪bool isDatabaseConnectSuccessful()
Definition: InstallerController.php:1099
‪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:36
‪TYPO3\CMS\Core\Package\PackageInterface
Definition: PackageInterface.php:22
‪TYPO3\CMS\Core\FormProtection\InstallToolFormProtection
Definition: InstallToolFormProtection.php:61
‪TYPO3\CMS\Core\Core\Environment\getContext
‪static ApplicationContext getContext()
Definition: Environment.php:133
‪TYPO3\CMS\Install\Updates\DatabaseRowsUpdateWizard
Definition: DatabaseRowsUpdateWizard.php:47
‪TYPO3\CMS\Install\Controller\InstallerController\initAction
‪ResponseInterface initAction()
Definition: InstallerController.php:126
‪TYPO3\CMS\Install\Controller\InstallerController\checkDatabaseRequirementsAction
‪ResponseInterface checkDatabaseRequirementsAction(ServerRequestInterface $request)
Definition: InstallerController.php:641
‪TYPO3\CMS\Core\Messaging\AbstractMessage\WARNING
‪const WARNING
Definition: AbstractMessage.php:30
‪TYPO3\CMS\Install\Controller\InstallerController\$lateBootService
‪LateBootService $lateBootService
Definition: InstallerController.php:77
‪TYPO3\CMS\Core\Core\Environment\getProjectPath
‪static string getProjectPath()
Definition: Environment.php:169
‪TYPO3\CMS\Install\Controller\InstallerController\$configurationManager
‪ConfigurationManager $configurationManager
Definition: InstallerController.php:85
‪TYPO3\CMS\Install\Exception
Definition: Exception.php:24
‪TYPO3\CMS\Install\Controller\InstallerController\$packageManager
‪FailsafePackageManager $packageManager
Definition: InstallerController.php:97
‪TYPO3\CMS\Install\Controller\InstallerController\executeSilentConfigurationUpdateAction
‪ResponseInterface executeSilentConfigurationUpdateAction()
Definition: InstallerController.php:285
‪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:2022
‪TYPO3\CMS\Install\Controller\InstallerController\checkRequiredDatabasePermissions
‪checkRequiredDatabasePermissions()
Definition: InstallerController.php:719
‪TYPO3\CMS\Install\Database\PermissionsCheck
Definition: PermissionsCheck.php:31
‪TYPO3\CMS\Install\Controller\InstallerController\showEnvironmentAndFoldersAction
‪ResponseInterface showEnvironmentAndFoldersAction()
Definition: InstallerController.php:189
‪TYPO3\CMS\Install\Controller
Definition: AbstractController.php:18
‪TYPO3\CMS\Install\Controller\InstallerController\showDatabaseDataAction
‪ResponseInterface showDatabaseDataAction()
Definition: InstallerController.php:839
‪TYPO3\CMS\Core\Crypto\PasswordHashing\Pbkdf2PasswordHash
Definition: Pbkdf2PasswordHash.php:28
‪TYPO3\CMS\Install\Controller\InstallerController\showDefaultConfigurationAction
‪ResponseInterface showDefaultConfigurationAction()
Definition: InstallerController.php:943
‪TYPO3\CMS\Install\Controller\InstallerController\retrieveDatabaseNameFromRequest
‪retrieveDatabaseNameFromRequest(ServerRequestInterface $request)
Definition: InstallerController.php:760
‪TYPO3\CMS\Install\SystemEnvironment\DatabaseCheck\retrieveDatabaseDriverClassByDriverName
‪static string retrieveDatabaseDriverClassByDriverName(string $driverName)
Definition: DatabaseCheck.php:285
‪TYPO3\CMS\Install\Service\LateBootService
Definition: LateBootService.php:34
‪TYPO3\CMS\Install\Controller\InstallerController\initializeStandaloneView
‪StandaloneView initializeStandaloneView(string $templatePath)
Definition: InstallerController.php:1083
‪TYPO3\CMS\Install\SystemEnvironment\DatabaseCheck
‪TYPO3\CMS\Core\Crypto\PasswordHashing\PhpassPasswordHash
Definition: PhpassPasswordHash.php:35
‪TYPO3\CMS\Install\Controller\InstallerController\checkTrustedHostsPatternAction
‪ResponseInterface checkTrustedHostsPatternAction()
Definition: InstallerController.php:258
‪TYPO3\CMS\Install\Controller\InstallerController\showDatabaseConnectAction
‪ResponseInterface showDatabaseConnectAction()
Definition: InstallerController.php:315
‪$errors
‪$errors
Definition: annotationChecker.php:121
‪TYPO3\CMS\Core\Messaging\AbstractMessage\OK
‪const OK
Definition: AbstractMessage.php:29
‪TYPO3\CMS\Install\Controller\InstallerController
Definition: InstallerController.php:74
‪TYPO3\CMS\Core\Database\Connection
Definition: Connection.php:36
‪TYPO3\CMS\Core\Core\Environment\isComposerMode
‪static bool isComposerMode()
Definition: Environment.php:144
‪TYPO3\CMS\Core\Messaging\AbstractMessage\INFO
‪const INFO
Definition: AbstractMessage.php:28
‪TYPO3\CMS\Core\Messaging\FlashMessage
Definition: FlashMessage.php:24
‪TYPO3\CMS\Core\FormProtection\FormProtectionFactory
Definition: FormProtectionFactory.php:47
‪TYPO3\CMS\Fluid\View\StandaloneView
Definition: StandaloneView.php:34
‪TYPO3\CMS\Install\SystemEnvironment\Check
Definition: Check.php:55
‪TYPO3\CMS\Install\Controller\InstallerController\getHashedPassword
‪string getHashedPassword($password)
Definition: InstallerController.php:1352
‪TYPO3\CMS\Install\Controller\InstallerController\__construct
‪__construct(LateBootService $lateBootService, SilentConfigurationUpgradeService $silentConfigurationUpgradeService, ConfigurationManager $configurationManager, SiteConfiguration $siteConfiguration, Registry $registry, FailsafePackageManager $packageManager, PermissionsCheck $databasePermissionsCheck)
Definition: InstallerController.php:103
‪TYPO3\CMS\Core\Http\JsonResponse
Definition: JsonResponse.php:26
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Install\Controller\InstallerController\isDatabaseConfigurationComplete
‪bool isDatabaseConfigurationComplete()
Definition: InstallerController.php:1118
‪TYPO3\CMS\Core\Core\Environment
Definition: Environment.php:40
‪TYPO3\CMS\Core\Database\Platform\PlatformInformation
Definition: PlatformInformation.php:33
‪TYPO3\CMS\Install\Controller\InstallerController\importDatabaseData
‪FlashMessage[] importDatabaseData()
Definition: InstallerController.php:1376
‪TYPO3\CMS\Install\SystemEnvironment\SetupCheck
Definition: SetupCheck.php:36
‪TYPO3\CMS\Core\Core\Environment\getConfigPath
‪static string getConfigPath()
Definition: Environment.php:210
‪TYPO3\CMS\Core\Crypto\Random
Definition: Random.php:24
‪TYPO3\CMS\Install\Controller\InstallerController\checkExistingDatabase
‪FlashMessage checkExistingDatabase($dbName)
Definition: InstallerController.php:1302
‪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:163
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:46
‪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:81
‪TYPO3\CMS\Core\Http\NormalizedParams\createFromRequest
‪static static createFromRequest(ServerRequestInterface $request, array $systemConfiguration=null)
Definition: NormalizedParams.php:848
‪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:282
‪TYPO3\CMS\Core\Messaging\AbstractMessage\ERROR
‪const ERROR
Definition: AbstractMessage.php:31
‪TYPO3\CMS\Install\Controller\InstallerController\mainLayoutAction
‪ResponseInterface mainLayoutAction()
Definition: InstallerController.php:149
‪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:192
‪TYPO3\CMS\Install\SystemEnvironment\DatabaseCheck\isMysqli
‪static isMysqli()
Definition: DatabaseCheck.php:302
‪TYPO3\CMS\Core\Database\Connection\PARAM_LOB
‪const PARAM_LOB
Definition: Connection.php:57
‪TYPO3\CMS\Install\Controller\InstallerController\getDatabaseList
‪array getDatabaseList()
Definition: InstallerController.php:1207