load(); // Check if the created .env file is writable to continue install process if (is_really_writable(ROOTPATH . '.env')) { try { $dotenv->required(['app.baseURL', 'analytics.salt', 'admin.gateway', 'auth.gateway']); } catch (ValidationException) { // form to input instance configuration return $this->instanceConfig(); } try { $dotenv->required([ 'database.default.hostname', 'database.default.database', 'database.default.username', 'database.default.password', 'database.default.DBPrefix', ]); } catch (ValidationException) { return $this->databaseConfig(); } try { $dotenv->required('cache.handler'); } catch (ValidationException) { return $this->cacheConfig(); } } else { try { $dotenv->required([ 'app.baseURL', 'analytics.salt', 'admin.gateway', 'auth.gateway', 'database.default.hostname', 'database.default.database', 'database.default.username', 'database.default.password', 'database.default.DBPrefix', 'cache.handler', ]); } catch (ValidationException) { return view('manual_config'); } } try { $db = db_connect(); // Check if instance owner has been created, meaning install was completed if ($db->tableExists('users') && (new UserModel())->where('is_owner', true) ->first() !== null ) { // if so, show a 404 page throw PageNotFoundException::forPageNotFound(); } } catch (DatabaseException) { // Could not connect to the database // show database config view to fix value session() ->setFlashdata('error', lang('Install.messages.databaseConnectError')); return $this->databaseConfig(); } // migrate if no user has been created $this->migrate(); // Check if all seeds have succeeded $this->seed(); return $this->createSuperAdmin(); } public function instanceConfig(): string { return view('instance_config'); } public function attemptInstanceConfig(): RedirectResponse { $rules = [ 'hostname' => 'required|valid_url_strict', 'media_base_url' => 'permit_empty|valid_url_strict', 'admin_gateway' => 'required', 'auth_gateway' => 'required|differs[admin_gateway]', ]; if (! $this->validate($rules)) { return redirect() ->to((host_url() === null ? config('App') ->baseURL : host_url()) . config('Install')->gateway) ->withInput() ->with('errors', $this->validator->getErrors()); } $baseUrl = $this->request->getPost('hostname'); $mediaBaseUrl = $this->request->getPost('media_base_url'); self::writeEnv([ 'app.baseURL' => $baseUrl, 'media.baseURL' => $mediaBaseUrl === '' ? $baseUrl : $mediaBaseUrl, 'analytics.salt' => generate_random_salt(64), 'admin.gateway' => $this->request->getPost('admin_gateway'), 'auth.gateway' => $this->request->getPost('auth_gateway'), ]); helper('text'); // redirect to full install url with new baseUrl input return redirect()->to(reduce_double_slashes($baseUrl . '/' . config('Install')->gateway)); } public function databaseConfig(): string { return view('database_config'); } public function attemptDatabaseConfig(): RedirectResponse { $rules = [ 'db_hostname' => 'required', 'db_name' => 'required', 'db_username' => 'required', 'db_password' => 'required', ]; if (! $this->validate($rules)) { return redirect() ->back() ->withInput() ->with('errors', $this->validator->getErrors()); } self::writeEnv([ 'database.default.hostname' => $this->request->getPost('db_hostname'), 'database.default.database' => $this->request->getPost('db_name'), 'database.default.username' => $this->request->getPost('db_username'), 'database.default.password' => $this->request->getPost('db_password'), 'database.default.DBPrefix' => $this->request->getPost('db_prefix'), ]); return redirect()->back(); } public function cacheConfig(): string { return view('cache_config'); } public function attemptCacheConfig(): RedirectResponse { $rules = [ 'cache_handler' => 'required', ]; if (! $this->validate($rules)) { return redirect() ->back() ->withInput() ->with('errors', $this->validator->getErrors()); } self::writeEnv([ 'cache.handler' => $this->request->getPost('cache_handler'), ]); return redirect()->back(); } /** * Runs all database migrations required for instance. */ public function migrate(): void { $migrate = Services::migrations(); $migrate->setNamespace(null) ->latest(); } /** * Runs all database seeds required for instance. */ public function seed(): void { $seeder = Database::seeder(); // Seed database $seeder->call('AppSeeder'); } /** * Returns the form to create a the first superadmin user for the instance. */ public function createSuperAdmin(): string { return view('create_superadmin'); } /** * Creates the first superadmin user or redirects back to form if any error. * * After creation, user is redirected to login page to input its credentials. */ public function attemptCreateSuperAdmin(): RedirectResponse { // validate user password $rules = [ 'password' => 'required|strong_password', ]; $userModel = new UserModel(); if (! $this->validate($rules)) { return redirect() ->back() ->withInput() ->with('errors', $userModel->errors()); } // Save the user $user = new User([ 'username' => $this->request->getPost('username'), 'email' => $this->request->getPost('email'), 'password' => $this->request->getPost('password'), 'is_owner' => true, ]); try { $userModel->save($user); } catch (ValidationException) { return redirect()->back() ->withInput() ->with('errors', $userModel->errors()); } $user = $userModel->findById($userModel->getInsertID()); // set newly created user as most powerful instance group (superadmin) $user->addGroup(setting('AuthGroups.mostPowerfulGroup')); // Success! // set redirect_url session as admin area to go to after login session() ->set('redirect_url', route_to('admin')); return redirect() ->route('admin') ->with('message', lang('Install.messages.createSuperAdminSuccess')); } /** * writes config values in .env file overwrites any existing key and appends new ones * * @param array $configData key/value config pairs */ public static function writeEnv(array $configData): void { $envData = file(ROOTPATH . '.env'); // reads an array of lines foreach ($configData as $key => $value) { $replaced = false; $keyVal = $key . '="' . $value . '"' . PHP_EOL; $envData = array_map( static function ($line) use ($key, $keyVal, &$replaced) { if (str_starts_with($line, $key)) { $replaced = true; return $keyVal; } return $line; }, $envData ); if (! $replaced) { $envData[] = $keyVal; } } file_put_contents(ROOTPATH . '.env', implode('', $envData)); } }