1430ed1cbSGreg Roach<?php 2430ed1cbSGreg Roach 3430ed1cbSGreg Roach/** 4430ed1cbSGreg Roach * webtrees: online genealogy 51fe542e9SGreg Roach * Copyright (C) 2021 webtrees development team 6430ed1cbSGreg Roach * This program is free software: you can redistribute it and/or modify 7430ed1cbSGreg Roach * it under the terms of the GNU General Public License as published by 8430ed1cbSGreg Roach * the Free Software Foundation, either version 3 of the License, or 9430ed1cbSGreg Roach * (at your option) any later version. 10430ed1cbSGreg Roach * This program is distributed in the hope that it will be useful, 11430ed1cbSGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of 12430ed1cbSGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13430ed1cbSGreg Roach * GNU General Public License for more details. 14430ed1cbSGreg Roach * You should have received a copy of the GNU General Public License 15*89f7189bSGreg Roach * along with this program. If not, see <https://www.gnu.org/licenses/>. 16430ed1cbSGreg Roach */ 17430ed1cbSGreg Roach 18430ed1cbSGreg Roachdeclare(strict_types=1); 19430ed1cbSGreg Roach 20430ed1cbSGreg Roachnamespace Fisharebest\Webtrees\Http\RequestHandlers; 21430ed1cbSGreg Roach 22430ed1cbSGreg Roachuse Exception; 23430ed1cbSGreg Roachuse Fisharebest\Localization\Locale; 24430ed1cbSGreg Roachuse Fisharebest\Localization\Locale\LocaleEnUs; 25430ed1cbSGreg Roachuse Fisharebest\Localization\Locale\LocaleInterface; 26430ed1cbSGreg Roachuse Fisharebest\Webtrees\Auth; 27430ed1cbSGreg Roachuse Fisharebest\Webtrees\Cache; 281fe542e9SGreg Roachuse Fisharebest\Webtrees\Contracts\UserInterface; 2955037a57SGreg Roachuse Fisharebest\Webtrees\Factories\CacheFactory; 30430ed1cbSGreg Roachuse Fisharebest\Webtrees\Http\ViewResponseTrait; 31430ed1cbSGreg Roachuse Fisharebest\Webtrees\I18N; 32430ed1cbSGreg Roachuse Fisharebest\Webtrees\Module\ModuleLanguageInterface; 336b9cb339SGreg Roachuse Fisharebest\Webtrees\Registry; 34430ed1cbSGreg Roachuse Fisharebest\Webtrees\Services\MigrationService; 35430ed1cbSGreg Roachuse Fisharebest\Webtrees\Services\ModuleService; 36430ed1cbSGreg Roachuse Fisharebest\Webtrees\Services\ServerCheckService; 37430ed1cbSGreg Roachuse Fisharebest\Webtrees\Services\UserService; 38430ed1cbSGreg Roachuse Fisharebest\Webtrees\Session; 39430ed1cbSGreg Roachuse Fisharebest\Webtrees\Webtrees; 40430ed1cbSGreg Roachuse Illuminate\Database\Capsule\Manager as DB; 41430ed1cbSGreg Roachuse Psr\Http\Message\ResponseInterface; 42430ed1cbSGreg Roachuse Psr\Http\Message\ServerRequestInterface; 43430ed1cbSGreg Roachuse Psr\Http\Server\RequestHandlerInterface; 44430ed1cbSGreg Roachuse Symfony\Component\Cache\Adapter\NullAdapter; 45430ed1cbSGreg Roachuse Throwable; 46430ed1cbSGreg Roach 47430ed1cbSGreg Roachuse function app; 48430ed1cbSGreg Roachuse function e; 49430ed1cbSGreg Roachuse function file_get_contents; 50430ed1cbSGreg Roachuse function file_put_contents; 51430ed1cbSGreg Roachuse function ini_get; 52430ed1cbSGreg Roachuse function random_bytes; 53430ed1cbSGreg Roachuse function realpath; 54430ed1cbSGreg Roachuse function redirect; 55430ed1cbSGreg Roachuse function substr; 56430ed1cbSGreg Roachuse function touch; 57430ed1cbSGreg Roachuse function unlink; 58430ed1cbSGreg Roachuse function view; 59430ed1cbSGreg Roach 60430ed1cbSGreg Roach/** 61430ed1cbSGreg Roach * Controller for the installation wizard 62430ed1cbSGreg Roach */ 63430ed1cbSGreg Roachclass SetupWizard implements RequestHandlerInterface 64430ed1cbSGreg Roach{ 65430ed1cbSGreg Roach use ViewResponseTrait; 66430ed1cbSGreg Roach 67430ed1cbSGreg Roach private const DEFAULT_DBTYPE = 'mysql'; 68430ed1cbSGreg Roach private const DEFAULT_PREFIX = 'wt_'; 69430ed1cbSGreg Roach private const DEFAULT_DATA = [ 70430ed1cbSGreg Roach 'baseurl' => '', 71430ed1cbSGreg Roach 'lang' => '', 72430ed1cbSGreg Roach 'dbtype' => self::DEFAULT_DBTYPE, 73430ed1cbSGreg Roach 'dbhost' => '', 74430ed1cbSGreg Roach 'dbport' => '', 75430ed1cbSGreg Roach 'dbuser' => '', 76430ed1cbSGreg Roach 'dbpass' => '', 77430ed1cbSGreg Roach 'dbname' => '', 78430ed1cbSGreg Roach 'tblpfx' => self::DEFAULT_PREFIX, 79430ed1cbSGreg Roach 'wtname' => '', 80430ed1cbSGreg Roach 'wtuser' => '', 81430ed1cbSGreg Roach 'wtpass' => '', 82430ed1cbSGreg Roach 'wtemail' => '', 83430ed1cbSGreg Roach ]; 84430ed1cbSGreg Roach 85354679afSGreg Roach private const DEFAULT_PORTS = [ 86354679afSGreg Roach 'mysql' => '3306', 87354679afSGreg Roach 'pgsql' => '5432', 88354679afSGreg Roach 'sqlite' => '', 89354679afSGreg Roach 'sqlsvr' => '1433', 90354679afSGreg Roach ]; 91354679afSGreg Roach 92430ed1cbSGreg Roach /** @var MigrationService */ 93430ed1cbSGreg Roach private $migration_service; 94430ed1cbSGreg Roach 95430ed1cbSGreg Roach /** @var ModuleService */ 96430ed1cbSGreg Roach private $module_service; 97430ed1cbSGreg Roach 98430ed1cbSGreg Roach /** @var ServerCheckService */ 99430ed1cbSGreg Roach private $server_check_service; 100430ed1cbSGreg Roach 101430ed1cbSGreg Roach /** @var UserService */ 102430ed1cbSGreg Roach private $user_service; 103430ed1cbSGreg Roach 104430ed1cbSGreg Roach /** 105430ed1cbSGreg Roach * SetupWizard constructor. 106430ed1cbSGreg Roach * 107430ed1cbSGreg Roach * @param MigrationService $migration_service 108430ed1cbSGreg Roach * @param ModuleService $module_service 109430ed1cbSGreg Roach * @param ServerCheckService $server_check_service 110430ed1cbSGreg Roach * @param UserService $user_service 111430ed1cbSGreg Roach */ 112430ed1cbSGreg Roach public function __construct( 113430ed1cbSGreg Roach MigrationService $migration_service, 114430ed1cbSGreg Roach ModuleService $module_service, 115430ed1cbSGreg Roach ServerCheckService $server_check_service, 116430ed1cbSGreg Roach UserService $user_service 117430ed1cbSGreg Roach ) { 118430ed1cbSGreg Roach $this->user_service = $user_service; 119430ed1cbSGreg Roach $this->migration_service = $migration_service; 120430ed1cbSGreg Roach $this->module_service = $module_service; 121430ed1cbSGreg Roach $this->server_check_service = $server_check_service; 122430ed1cbSGreg Roach } 123430ed1cbSGreg Roach 124430ed1cbSGreg Roach /** 125430ed1cbSGreg Roach * Installation wizard - check user input and proceed to the next step. 126430ed1cbSGreg Roach * 127430ed1cbSGreg Roach * @param ServerRequestInterface $request 128430ed1cbSGreg Roach * 129430ed1cbSGreg Roach * @return ResponseInterface 130430ed1cbSGreg Roach */ 131430ed1cbSGreg Roach public function handle(ServerRequestInterface $request): ResponseInterface 132430ed1cbSGreg Roach { 133430ed1cbSGreg Roach $this->layout = 'layouts/setup'; 134430ed1cbSGreg Roach 13555037a57SGreg Roach // Some functions need a cache, but we don't have one yet. 1366b9cb339SGreg Roach Registry::cache(new CacheFactory()); 13755037a57SGreg Roach 138430ed1cbSGreg Roach // We will need an IP address for the logs. 139430ed1cbSGreg Roach $ip_address = $request->getServerParams()['REMOTE_ADDR'] ?? '127.0.0.1'; 140430ed1cbSGreg Roach $request = $request->withAttribute('client-ip', $ip_address); 141430ed1cbSGreg Roach 142430ed1cbSGreg Roach app()->instance(ServerRequestInterface::class, $request); 143430ed1cbSGreg Roach app()->instance('cache.array', new Cache(new NullAdapter())); 144430ed1cbSGreg Roach 145430ed1cbSGreg Roach $data = $this->userData($request); 146430ed1cbSGreg Roach 147430ed1cbSGreg Roach $params = (array) $request->getParsedBody(); 148430ed1cbSGreg Roach $step = (int) ($params['step'] ?? '1'); 149430ed1cbSGreg Roach 150430ed1cbSGreg Roach $locales = $this->module_service 151430ed1cbSGreg Roach ->setupLanguages() 152430ed1cbSGreg Roach ->map(static function (ModuleLanguageInterface $module): LocaleInterface { 153430ed1cbSGreg Roach return $module->locale(); 154430ed1cbSGreg Roach }); 155430ed1cbSGreg Roach 156430ed1cbSGreg Roach if ($data['lang'] === '') { 157430ed1cbSGreg Roach $default = new LocaleEnUs(); 158430ed1cbSGreg Roach 159430ed1cbSGreg Roach $locale = Locale::httpAcceptLanguage($request->getServerParams(), $locales->all(), $default); 160430ed1cbSGreg Roach 161430ed1cbSGreg Roach $data['lang'] = $locale->languageTag(); 162430ed1cbSGreg Roach } 163430ed1cbSGreg Roach 164430ed1cbSGreg Roach I18N::init($data['lang'], true); 165430ed1cbSGreg Roach 166430ed1cbSGreg Roach $data['cpu_limit'] = $this->maxExecutionTime(); 167430ed1cbSGreg Roach $data['locales'] = $locales->all(); 168430ed1cbSGreg Roach $data['memory_limit'] = $this->memoryLimit(); 169430ed1cbSGreg Roach 170430ed1cbSGreg Roach // Only show database errors after the user has chosen a driver. 171430ed1cbSGreg Roach if ($step >= 4) { 172430ed1cbSGreg Roach $data['errors'] = $this->server_check_service->serverErrors($data['dbtype']); 173430ed1cbSGreg Roach $data['warnings'] = $this->server_check_service->serverWarnings($data['dbtype']); 174430ed1cbSGreg Roach } else { 175430ed1cbSGreg Roach $data['errors'] = $this->server_check_service->serverErrors(); 176430ed1cbSGreg Roach $data['warnings'] = $this->server_check_service->serverWarnings(); 177430ed1cbSGreg Roach } 178430ed1cbSGreg Roach 179430ed1cbSGreg Roach if (!$this->checkFolderIsWritable(Webtrees::DATA_DIR)) { 180430ed1cbSGreg Roach $data['errors']->push( 181430ed1cbSGreg Roach '<code>' . e(realpath(Webtrees::DATA_DIR)) . '</code><br>' . 182430ed1cbSGreg Roach I18N::translate('Oops! webtrees was unable to create files in this folder.') . ' ' . 183430ed1cbSGreg Roach I18N::translate('This usually means that you need to change the folder permissions to 777.') 184430ed1cbSGreg Roach ); 185430ed1cbSGreg Roach } 186430ed1cbSGreg Roach 187430ed1cbSGreg Roach switch ($step) { 188430ed1cbSGreg Roach default: 189430ed1cbSGreg Roach case 1: 190430ed1cbSGreg Roach return $this->step1Language($data); 191430ed1cbSGreg Roach case 2: 192430ed1cbSGreg Roach return $this->step2CheckServer($data); 193430ed1cbSGreg Roach case 3: 194430ed1cbSGreg Roach return $this->step3DatabaseType($data); 195430ed1cbSGreg Roach case 4: 196430ed1cbSGreg Roach return $this->step4DatabaseConnection($data); 197430ed1cbSGreg Roach case 5: 198430ed1cbSGreg Roach return $this->step5Administrator($data); 199430ed1cbSGreg Roach case 6: 200430ed1cbSGreg Roach return $this->step6Install($data); 201430ed1cbSGreg Roach } 202430ed1cbSGreg Roach } 203430ed1cbSGreg Roach 204430ed1cbSGreg Roach /** 205430ed1cbSGreg Roach * @param ServerRequestInterface $request 206430ed1cbSGreg Roach * 207430ed1cbSGreg Roach * @return array<string,mixed> 208430ed1cbSGreg Roach */ 209430ed1cbSGreg Roach private function userData(ServerRequestInterface $request): array 210430ed1cbSGreg Roach { 211430ed1cbSGreg Roach $params = (array) $request->getParsedBody(); 212430ed1cbSGreg Roach 213430ed1cbSGreg Roach $data = []; 214430ed1cbSGreg Roach 215430ed1cbSGreg Roach foreach (self::DEFAULT_DATA as $key => $default) { 216430ed1cbSGreg Roach $data[$key] = $params[$key] ?? $default; 217430ed1cbSGreg Roach } 218430ed1cbSGreg Roach 219430ed1cbSGreg Roach return $data; 220430ed1cbSGreg Roach } 221430ed1cbSGreg Roach 222430ed1cbSGreg Roach /** 223430ed1cbSGreg Roach * The server's memory limit 224430ed1cbSGreg Roach * 225430ed1cbSGreg Roach * @return int 226430ed1cbSGreg Roach */ 227430ed1cbSGreg Roach private function maxExecutionTime(): int 228430ed1cbSGreg Roach { 229430ed1cbSGreg Roach return (int) ini_get('max_execution_time'); 230430ed1cbSGreg Roach } 231430ed1cbSGreg Roach 232430ed1cbSGreg Roach /** 233430ed1cbSGreg Roach * The server's memory limit (in MB). 234430ed1cbSGreg Roach * 235430ed1cbSGreg Roach * @return int 236430ed1cbSGreg Roach */ 237430ed1cbSGreg Roach private function memoryLimit(): int 238430ed1cbSGreg Roach { 239430ed1cbSGreg Roach $memory_limit = ini_get('memory_limit'); 240430ed1cbSGreg Roach 241430ed1cbSGreg Roach $number = (int) $memory_limit; 242430ed1cbSGreg Roach 243430ed1cbSGreg Roach switch (substr($memory_limit, -1)) { 244430ed1cbSGreg Roach case 'g': 245430ed1cbSGreg Roach case 'G': 246430ed1cbSGreg Roach return $number * 1024; 247430ed1cbSGreg Roach case 'm': 248430ed1cbSGreg Roach case 'M': 249430ed1cbSGreg Roach return $number; 250430ed1cbSGreg Roach case 'k': 251430ed1cbSGreg Roach case 'K': 252430ed1cbSGreg Roach return (int) ($number / 1024); 253430ed1cbSGreg Roach default: 254430ed1cbSGreg Roach return (int) ($number / 1048576); 255430ed1cbSGreg Roach } 256430ed1cbSGreg Roach } 257430ed1cbSGreg Roach 258430ed1cbSGreg Roach /** 259430ed1cbSGreg Roach * Check we can write to the data folder. 260430ed1cbSGreg Roach * 261430ed1cbSGreg Roach * @param string $data_dir 262430ed1cbSGreg Roach * 263430ed1cbSGreg Roach * @return bool 264430ed1cbSGreg Roach */ 265430ed1cbSGreg Roach private function checkFolderIsWritable(string $data_dir): bool 266430ed1cbSGreg Roach { 267430ed1cbSGreg Roach $text1 = random_bytes(32); 268430ed1cbSGreg Roach 269430ed1cbSGreg Roach try { 270430ed1cbSGreg Roach file_put_contents($data_dir . 'test.txt', $text1); 271430ed1cbSGreg Roach $text2 = file_get_contents(Webtrees::DATA_DIR . 'test.txt'); 272430ed1cbSGreg Roach unlink(Webtrees::DATA_DIR . 'test.txt'); 273430ed1cbSGreg Roach } catch (Exception $ex) { 274430ed1cbSGreg Roach return false; 275430ed1cbSGreg Roach } 276430ed1cbSGreg Roach 277430ed1cbSGreg Roach return $text1 === $text2; 278430ed1cbSGreg Roach } 279430ed1cbSGreg Roach 280430ed1cbSGreg Roach /** 281430ed1cbSGreg Roach * @param array<string,mixed> $data 282430ed1cbSGreg Roach * 283430ed1cbSGreg Roach * @return ResponseInterface 284430ed1cbSGreg Roach */ 285430ed1cbSGreg Roach private function step1Language(array $data): ResponseInterface 286430ed1cbSGreg Roach { 287430ed1cbSGreg Roach return $this->viewResponse('setup/step-1-language', $data); 288430ed1cbSGreg Roach } 289430ed1cbSGreg Roach 290430ed1cbSGreg Roach /** 291430ed1cbSGreg Roach * @param array<string,mixed> $data 292430ed1cbSGreg Roach * 293430ed1cbSGreg Roach * @return ResponseInterface 294430ed1cbSGreg Roach */ 295430ed1cbSGreg Roach private function step2CheckServer(array $data): ResponseInterface 296430ed1cbSGreg Roach { 297430ed1cbSGreg Roach return $this->viewResponse('setup/step-2-server-checks', $data); 298430ed1cbSGreg Roach } 299430ed1cbSGreg Roach 300430ed1cbSGreg Roach /** 301430ed1cbSGreg Roach * @param array<string,mixed> $data 302430ed1cbSGreg Roach * 303430ed1cbSGreg Roach * @return ResponseInterface 304430ed1cbSGreg Roach */ 305430ed1cbSGreg Roach private function step3DatabaseType(array $data): ResponseInterface 306430ed1cbSGreg Roach { 307430ed1cbSGreg Roach if ($data['errors']->isNotEmpty()) { 308430ed1cbSGreg Roach return $this->viewResponse('setup/step-2-server-checks', $data); 309430ed1cbSGreg Roach } 310430ed1cbSGreg Roach 311430ed1cbSGreg Roach return $this->viewResponse('setup/step-3-database-type', $data); 312430ed1cbSGreg Roach } 313430ed1cbSGreg Roach 314430ed1cbSGreg Roach /** 315430ed1cbSGreg Roach * @param array<string,mixed> $data 316430ed1cbSGreg Roach * 317430ed1cbSGreg Roach * @return ResponseInterface 318430ed1cbSGreg Roach */ 319430ed1cbSGreg Roach private function step4DatabaseConnection(array $data): ResponseInterface 320430ed1cbSGreg Roach { 321430ed1cbSGreg Roach if ($data['errors']->isNotEmpty()) { 322430ed1cbSGreg Roach return $this->step3DatabaseType($data); 323430ed1cbSGreg Roach } 324430ed1cbSGreg Roach 325430ed1cbSGreg Roach return $this->viewResponse('setup/step-4-database-' . $data['dbtype'], $data); 326430ed1cbSGreg Roach } 327430ed1cbSGreg Roach 328430ed1cbSGreg Roach /** 329430ed1cbSGreg Roach * @param array<string,mixed> $data 330430ed1cbSGreg Roach * 331430ed1cbSGreg Roach * @return ResponseInterface 332430ed1cbSGreg Roach */ 333430ed1cbSGreg Roach private function step5Administrator(array $data): ResponseInterface 334430ed1cbSGreg Roach { 335354679afSGreg Roach // Use default port, if none specified. 336354679afSGreg Roach $data['dbport'] = $data['dbport'] ?: self::DEFAULT_PORTS[$data['dbtype']]; 337354679afSGreg Roach 338430ed1cbSGreg Roach try { 339430ed1cbSGreg Roach $this->connectToDatabase($data); 340430ed1cbSGreg Roach } catch (Throwable $ex) { 341430ed1cbSGreg Roach $data['errors']->push($ex->getMessage()); 342430ed1cbSGreg Roach 343430ed1cbSGreg Roach // Don't jump to step 4, as the error will make it jump to step 3. 344430ed1cbSGreg Roach return $this->viewResponse('setup/step-4-database-' . $data['dbtype'], $data); 345430ed1cbSGreg Roach } 346430ed1cbSGreg Roach 347430ed1cbSGreg Roach return $this->viewResponse('setup/step-5-administrator', $data); 348430ed1cbSGreg Roach } 349430ed1cbSGreg Roach 350430ed1cbSGreg Roach /** 351430ed1cbSGreg Roach * @param array<string,mixed> $data 352430ed1cbSGreg Roach * 353430ed1cbSGreg Roach * @return ResponseInterface 354430ed1cbSGreg Roach */ 355430ed1cbSGreg Roach private function step6Install(array $data): ResponseInterface 356430ed1cbSGreg Roach { 357430ed1cbSGreg Roach $error = $this->checkAdminUser($data['wtname'], $data['wtuser'], $data['wtpass'], $data['wtemail']); 358430ed1cbSGreg Roach 359430ed1cbSGreg Roach if ($error !== '') { 360430ed1cbSGreg Roach $data['errors']->push($error); 361430ed1cbSGreg Roach 362430ed1cbSGreg Roach return $this->step5Administrator($data); 363430ed1cbSGreg Roach } 364430ed1cbSGreg Roach 365430ed1cbSGreg Roach try { 366430ed1cbSGreg Roach $this->createConfigFile($data); 367430ed1cbSGreg Roach } catch (Throwable $exception) { 368430ed1cbSGreg Roach return $this->viewResponse('setup/step-6-failed', ['exception' => $exception]); 369430ed1cbSGreg Roach } 370430ed1cbSGreg Roach 371430ed1cbSGreg Roach // Done - start using webtrees! 372430ed1cbSGreg Roach return redirect($data['baseurl']); 373430ed1cbSGreg Roach } 374430ed1cbSGreg Roach 375430ed1cbSGreg Roach /** 376430ed1cbSGreg Roach * @param string $wtname 377430ed1cbSGreg Roach * @param string $wtuser 378430ed1cbSGreg Roach * @param string $wtpass 379430ed1cbSGreg Roach * @param string $wtemail 380430ed1cbSGreg Roach * 381430ed1cbSGreg Roach * @return string 382430ed1cbSGreg Roach */ 383430ed1cbSGreg Roach private function checkAdminUser($wtname, $wtuser, $wtpass, $wtemail): string 384430ed1cbSGreg Roach { 385430ed1cbSGreg Roach if ($wtname === '' || $wtuser === '' || $wtpass === '' || $wtemail === '') { 386430ed1cbSGreg Roach return I18N::translate('You must enter all the administrator account fields.'); 387430ed1cbSGreg Roach } 388430ed1cbSGreg Roach 389430ed1cbSGreg Roach if (mb_strlen($wtpass) < 6) { 390430ed1cbSGreg Roach return I18N::translate('The password needs to be at least six characters long.'); 391430ed1cbSGreg Roach } 392430ed1cbSGreg Roach 393430ed1cbSGreg Roach return ''; 394430ed1cbSGreg Roach } 395430ed1cbSGreg Roach 396430ed1cbSGreg Roach /** 397430ed1cbSGreg Roach * @param array<string,mixed> $data 398430ed1cbSGreg Roach * 399430ed1cbSGreg Roach * @return void 400430ed1cbSGreg Roach */ 401430ed1cbSGreg Roach private function createConfigFile(array $data): void 402430ed1cbSGreg Roach { 403430ed1cbSGreg Roach // Create/update the database tables. 404430ed1cbSGreg Roach $this->connectToDatabase($data); 405430ed1cbSGreg Roach $this->migration_service->updateSchema('\Fisharebest\Webtrees\Schema', 'WT_SCHEMA_VERSION', Webtrees::SCHEMA_VERSION); 406430ed1cbSGreg Roach 407430ed1cbSGreg Roach // Add some default/necessary configuration data. 408430ed1cbSGreg Roach $this->migration_service->seedDatabase(); 409430ed1cbSGreg Roach 410430ed1cbSGreg Roach // If we are re-installing, then this user may already exist. 411430ed1cbSGreg Roach $admin = $this->user_service->findByIdentifier($data['wtemail']); 412430ed1cbSGreg Roach if ($admin === null) { 413430ed1cbSGreg Roach $admin = $this->user_service->findByIdentifier($data['wtuser']); 414430ed1cbSGreg Roach } 415430ed1cbSGreg Roach // Create the user 416430ed1cbSGreg Roach if ($admin === null) { 417430ed1cbSGreg Roach $admin = $this->user_service->create($data['wtuser'], $data['wtname'], $data['wtemail'], $data['wtpass']); 4181fe542e9SGreg Roach $admin->setPreference(UserInterface::PREF_LANGUAGE, $data['lang']); 4191fe542e9SGreg Roach $admin->setPreference(UserInterface::PREF_IS_VISIBLE_ONLINE, '1'); 420430ed1cbSGreg Roach } else { 421430ed1cbSGreg Roach $admin->setPassword($_POST['wtpass']); 422430ed1cbSGreg Roach } 423430ed1cbSGreg Roach // Make the user an administrator 4241fe542e9SGreg Roach $admin->setPreference(UserInterface::PREF_IS_ADMINISTRATOR, '1'); 4251fe542e9SGreg Roach $admin->setPreference(UserInterface::PREF_IS_EMAIL_VERIFIED, '1'); 4261fe542e9SGreg Roach $admin->setPreference(UserInterface::PREF_IS_ACCOUNT_APPROVED, '1'); 427430ed1cbSGreg Roach 428430ed1cbSGreg Roach // Write the config file. We already checked that this would work. 429430ed1cbSGreg Roach $config_ini_php = view('setup/config.ini', $data); 430430ed1cbSGreg Roach 431430ed1cbSGreg Roach file_put_contents(Webtrees::CONFIG_FILE, $config_ini_php); 432430ed1cbSGreg Roach 433430ed1cbSGreg Roach // Login as the new user 434430ed1cbSGreg Roach $request = app(ServerRequestInterface::class) 435430ed1cbSGreg Roach ->withAttribute('base_url', $data['baseurl']); 436430ed1cbSGreg Roach 437430ed1cbSGreg Roach Session::start($request); 438430ed1cbSGreg Roach Auth::login($admin); 439430ed1cbSGreg Roach Session::put('language', $data['lang']); 440430ed1cbSGreg Roach } 441430ed1cbSGreg Roach 442430ed1cbSGreg Roach /** 443430ed1cbSGreg Roach * @param array<string,mixed> $data 444430ed1cbSGreg Roach * 445430ed1cbSGreg Roach * @return void 446430ed1cbSGreg Roach */ 447430ed1cbSGreg Roach private function connectToDatabase(array $data): void 448430ed1cbSGreg Roach { 449430ed1cbSGreg Roach $capsule = new DB(); 450430ed1cbSGreg Roach 451430ed1cbSGreg Roach // Try to create the database, if it does not already exist. 452430ed1cbSGreg Roach switch ($data['dbtype']) { 453430ed1cbSGreg Roach case 'sqlite': 454430ed1cbSGreg Roach $data['dbname'] = Webtrees::ROOT_DIR . 'data/' . $data['dbname'] . '.sqlite'; 455430ed1cbSGreg Roach touch($data['dbname']); 456430ed1cbSGreg Roach break; 457430ed1cbSGreg Roach 458430ed1cbSGreg Roach case 'mysql': 459430ed1cbSGreg Roach $capsule->addConnection([ 460430ed1cbSGreg Roach 'driver' => $data['dbtype'], 461430ed1cbSGreg Roach 'host' => $data['dbhost'], 462430ed1cbSGreg Roach 'port' => $data['dbport'], 463430ed1cbSGreg Roach 'database' => '', 464430ed1cbSGreg Roach 'username' => $data['dbuser'], 465430ed1cbSGreg Roach 'password' => $data['dbpass'], 466430ed1cbSGreg Roach ], 'temp'); 467430ed1cbSGreg Roach $capsule->getConnection('temp')->statement('CREATE DATABASE IF NOT EXISTS `' . $data['dbname'] . '` COLLATE utf8_unicode_ci'); 468430ed1cbSGreg Roach break; 469430ed1cbSGreg Roach } 470430ed1cbSGreg Roach 471430ed1cbSGreg Roach // Connect to the database. 472430ed1cbSGreg Roach $capsule->addConnection([ 473430ed1cbSGreg Roach 'driver' => $data['dbtype'], 474430ed1cbSGreg Roach 'host' => $data['dbhost'], 475430ed1cbSGreg Roach 'port' => $data['dbport'], 476430ed1cbSGreg Roach 'database' => $data['dbname'], 477430ed1cbSGreg Roach 'username' => $data['dbuser'], 478430ed1cbSGreg Roach 'password' => $data['dbpass'], 479430ed1cbSGreg Roach 'prefix' => $data['tblpfx'], 480430ed1cbSGreg Roach 'prefix_indexes' => true, 481430ed1cbSGreg Roach // For MySQL 482430ed1cbSGreg Roach 'charset' => 'utf8', 483430ed1cbSGreg Roach 'collation' => 'utf8_unicode_ci', 484430ed1cbSGreg Roach 'timezone' => '+00:00', 485430ed1cbSGreg Roach 'engine' => 'InnoDB', 486430ed1cbSGreg Roach 'modes' => [ 487430ed1cbSGreg Roach 'ANSI', 488430ed1cbSGreg Roach 'STRICT_TRANS_TABLES', 489430ed1cbSGreg Roach 'NO_ZERO_IN_DATE', 490430ed1cbSGreg Roach 'NO_ZERO_DATE', 491430ed1cbSGreg Roach 'ERROR_FOR_DIVISION_BY_ZERO', 492430ed1cbSGreg Roach ], 493430ed1cbSGreg Roach // For SQLite 494430ed1cbSGreg Roach 'foreign_key_constraints' => true, 495430ed1cbSGreg Roach ]); 496430ed1cbSGreg Roach 497430ed1cbSGreg Roach $capsule->setAsGlobal(); 498430ed1cbSGreg Roach } 499430ed1cbSGreg Roach} 500