update installer class and ui
This commit is contained in:
@@ -25,30 +25,118 @@
|
||||
|
||||
namespace Froxlor\Install;
|
||||
|
||||
use Exception;
|
||||
use Froxlor\UI\Panel\UI;
|
||||
use Froxlor\UI\Request;
|
||||
|
||||
class Install
|
||||
{
|
||||
public $step = 0;
|
||||
public $currentStep;
|
||||
public $maxSteps;
|
||||
public $phpVersion;
|
||||
public $formfield;
|
||||
public string $requiredVersion = '7.4.0';
|
||||
public array $requiredExtensions = ['libxml', 'zip'];
|
||||
public array $suggestedExtensions = ['curl'];
|
||||
public array $suggestions = [];
|
||||
public array $criticals = [];
|
||||
public array $loadedExtensions;
|
||||
public array $supportedOS = [
|
||||
'focal' => 'Ubuntu 20.04 LTS (Focal Fossa)'
|
||||
];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->step = Request::get('step');
|
||||
// set formfield, so we can get the fields and steps etc.
|
||||
$this->formfield = require dirname(__DIR__, 3) . '/lib/formfields/install/formfield.install.php';
|
||||
|
||||
// set actual step
|
||||
$this->currentStep = Request::get('step', 0);
|
||||
$this->maxSteps = count($this->formfield['install']['sections']);
|
||||
|
||||
// set actual php version and extensions
|
||||
$this->phpVersion = phpversion();
|
||||
$this->loadedExtensions = get_loaded_extensions();
|
||||
|
||||
$this->checkExtensions();
|
||||
// init twig
|
||||
UI::initTwig(true);
|
||||
UI::sendHeaders();
|
||||
|
||||
// set global variables
|
||||
UI::twig()->addGlobal('install_mode', true);
|
||||
UI::twig()->addGlobal('basehref', '../');
|
||||
|
||||
// unset session if user goes back to step 0
|
||||
if (isset($_SESSION['installation']) && $this->currentStep == 0) {
|
||||
unset($_SESSION['installation']);
|
||||
}
|
||||
}
|
||||
|
||||
public function checkExtensions()
|
||||
/**
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
// handle form data
|
||||
if (!is_null(Request::get('submit')) && $this->currentStep) {
|
||||
try {
|
||||
$this->handleFormData($this->formfield['install']);
|
||||
} catch (Exception $e) {
|
||||
$error = $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
// load template
|
||||
UI::twigBuffer('/install/index.html.twig', [
|
||||
'setup' => [
|
||||
'step' => $this->currentStep,
|
||||
],
|
||||
'preflight' => $this->checkExtensions(),
|
||||
'page' => [
|
||||
'title' => 'Database',
|
||||
'description' => 'Test',
|
||||
],
|
||||
'section' => $this->formfield['install']['sections']['step' . $this->currentStep] ?? [],
|
||||
'error' => $error ?? null,
|
||||
]);
|
||||
|
||||
// output view
|
||||
UI::twigOutputBuffer();
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
private function handleFormData(array $formfield): void
|
||||
{
|
||||
// Validate user data
|
||||
$validatedData = $this->validateRequest($formfield['sections']['step' . $this->currentStep]['fields']);
|
||||
|
||||
// handle current step
|
||||
if ($this->currentStep <= $this->maxSteps) {
|
||||
// Check database connection (
|
||||
if ($this->currentStep == 1) {
|
||||
$this->checkDatabase($validatedData);
|
||||
}
|
||||
// Store validated data for later use
|
||||
$_SESSION['installation'] = array_merge($_SESSION['installation'] ?? [], $validatedData);
|
||||
}
|
||||
|
||||
// also handle completion of installation if it's the last step
|
||||
if ($this->currentStep == $this->maxSteps) {
|
||||
$this->startInstallation($validatedData);
|
||||
header('Location: ../');
|
||||
return;
|
||||
}
|
||||
|
||||
header('Location: ?step=' . ($this->currentStep + 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function checkExtensions(): array
|
||||
{
|
||||
// check for required extensions
|
||||
foreach ($this->requiredExtensions as $requiredExtension) {
|
||||
@@ -65,42 +153,18 @@ class Install
|
||||
}
|
||||
$this->suggestions['missing_extensions'][] = $suggestedExtension;
|
||||
}
|
||||
|
||||
return [
|
||||
'text' => $this->getInformationText(),
|
||||
'suggestions' => $this->suggestions,
|
||||
'criticals' => $this->criticals,
|
||||
];
|
||||
}
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$formfield = require dirname(__DIR__, 3) . '/lib/formfields/install/formfield.install.php';
|
||||
|
||||
// init twig
|
||||
UI::initTwig(true);
|
||||
UI::sendHeaders();
|
||||
|
||||
// set global variables
|
||||
UI::twig()->addGlobal('install_mode', true);
|
||||
UI::twig()->addGlobal('basehref', '../');
|
||||
|
||||
// load template
|
||||
UI::twigBuffer('/install/index.html.twig', [
|
||||
'setup' => [
|
||||
'step' => $this->step,
|
||||
],
|
||||
'preflight' => [
|
||||
'text' => $this->getPreflightText(),
|
||||
'suggestions' => $this->suggestions,
|
||||
'criticals' => $this->criticals,
|
||||
],
|
||||
'page' => [
|
||||
'title' => 'Database',
|
||||
'description' => 'Test',
|
||||
],
|
||||
'section' => $formfield['install']['sections'][sprintf('step%s', $this->step)] ?? [],
|
||||
]);
|
||||
|
||||
// output view
|
||||
UI::twigOutputBuffer();
|
||||
}
|
||||
|
||||
public function getPreflightText(): string
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
private function getInformationText(): string
|
||||
{
|
||||
if (version_compare($this->requiredVersion, PHP_VERSION, "<")) {
|
||||
$text = 'Your system is running with PHP ' . $this->phpVersion;
|
||||
@@ -108,7 +172,93 @@ class Install
|
||||
$text = 'Your system is running a lower version than PHP ' . $this->requiredVersion;
|
||||
$this->criticals[] = 'Update your current PHP Version from ' . $this->phpVersion . ' to ' . $this->requiredVersion . ' or higher';
|
||||
}
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
private function validateRequest(array $fields): array
|
||||
{
|
||||
$attributes = [];
|
||||
foreach ($fields as $name => $field) {
|
||||
$attributes[$name] = $this->validateAttribute(Request::get($name), $field);
|
||||
if (isset($field['next_to'])) {
|
||||
$attributes = array_merge($attributes, $this->validateRequest($field['next_to']));
|
||||
}
|
||||
}
|
||||
return $attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
private function validateAttribute($attribute, array $field)
|
||||
{
|
||||
// TODO: do validations
|
||||
if (isset($field['mandatory']) && $field['mandatory'] && empty($attribute)) {
|
||||
throw new Exception('Mandatory field is not set!');
|
||||
}
|
||||
return $attribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
private function checkDatabase(array $validatedData): void
|
||||
{
|
||||
$dsn = sprintf('mysql:host=%s;charset=utf8mb4', $validatedData['sql_hostname']);
|
||||
$pdo = new \PDO($dsn, $validatedData['sql_root_username'], $validatedData['sql_root_password']);
|
||||
|
||||
// check if the database already exist
|
||||
$stmt = $pdo->prepare('SHOW DATABASES LIKE ?');
|
||||
$stmt->execute([
|
||||
$validatedData['sql_database']
|
||||
]);
|
||||
$hasDatabase = $stmt->fetch();
|
||||
if ($hasDatabase && !$validatedData['sql_override_database']) {
|
||||
throw new Exception('Database already exist, please set override option to rebuild!');
|
||||
}
|
||||
|
||||
// check if we can create a new database
|
||||
$testDatabase = uniqid('froxlor_tmp_');
|
||||
if ($pdo->exec('CREATE DATABASE IF NOT EXISTS ' . $testDatabase . ';') === false) {
|
||||
throw new Exception('cant create test db');
|
||||
}
|
||||
if ($pdo->exec('DROP DATABASE IF EXISTS ' . $testDatabase . ';') === false) {
|
||||
throw new Exception('Cant drop test db');
|
||||
}
|
||||
|
||||
// FIXME: seems not to work
|
||||
// check if the user already exist
|
||||
$stmt = $pdo->prepare("SELECT `user` FROM `mysql.user` WHERE `user` = '?'");
|
||||
if ($stmt->rowCount()) {
|
||||
throw new Exception('Username already exist, please use another username!');
|
||||
}
|
||||
|
||||
// check if we can create a new user
|
||||
$testUser = uniqid('froxlor_tmp_');
|
||||
$stmt = $pdo->prepare('CREATE USER ?@? IDENTIFIED BY ?');
|
||||
if ($stmt->execute([$testUser, $validatedData['sql_hostname'], uniqid()]) === false) {
|
||||
throw new Exception('cant create test user');
|
||||
}
|
||||
$stmt = $pdo->prepare('DROP USER ?@?');
|
||||
if ($stmt->execute([$testUser, $validatedData['sql_hostname']]) === false) {
|
||||
throw new Exception('cant create test user');
|
||||
}
|
||||
if ($pdo->prepare('FLUSH PRIVILEGES')->execute() === false) {
|
||||
throw new Exception('Cant flush privileges');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $validatedData
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
private function startInstallation(array $validatedData): void
|
||||
{
|
||||
// TODO: do the installation (maybe in an own class?)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,153 +30,111 @@ return [
|
||||
'self_overview' => ['section' => 'admins', 'page' => 'admins'],
|
||||
'sections' => [
|
||||
'step1' => [
|
||||
'title' => lng('install.dabatase'),
|
||||
'title' => lng('install.database.title'),
|
||||
'fields' => [
|
||||
'sql_hostname' => [
|
||||
'label' => lng('sql_hostname'),
|
||||
'type' => 'text',
|
||||
'mandatory' => true,
|
||||
'value' => 'localhost'
|
||||
'value' => old('sql_hostname', 'localhost', 'installation')
|
||||
],
|
||||
'sql_root_username' => [
|
||||
'label' => lng('sql_root_username'),
|
||||
'type' => 'password',
|
||||
'type' => 'text',
|
||||
'mandatory' => true,
|
||||
'value' => old('sql_root_username', 'froxroot', 'installation'),
|
||||
'next_to' => [
|
||||
'sql_root_password' => [
|
||||
'label' => lng('sql_root_password'),
|
||||
'type' => 'password',
|
||||
'mandatory' => true
|
||||
'mandatory' => true,
|
||||
'value' => old('sql_root_password', null, 'installation'),
|
||||
],
|
||||
]
|
||||
],
|
||||
'sql_username' => [
|
||||
'label' => lng('sql_username'),
|
||||
'type' => 'password',
|
||||
'type' => 'text',
|
||||
'mandatory' => true,
|
||||
'value' => old('sql_username', 'froxlor', 'installation'),
|
||||
'next_to' => [
|
||||
'sql_password' => [
|
||||
'label' => lng('sql_password'),
|
||||
'type' => 'password',
|
||||
'mandatory' => true
|
||||
'mandatory' => true,
|
||||
'value' => old('sql_password', null, 'installation'),
|
||||
],
|
||||
]
|
||||
],
|
||||
'sql_database' => [
|
||||
'label' => lng('sql_database'),
|
||||
'type' => 'text',
|
||||
'mandatory' => true,
|
||||
'value' => old('sql_database', 'froxlor', 'installation'),
|
||||
],
|
||||
'sql_override_database' => [
|
||||
'label' => lng('sql_override_database'),
|
||||
'type' => 'checkbox',
|
||||
'value' => '1',
|
||||
'checked' => old('sql_override_database', '0', 'installation')
|
||||
],
|
||||
]
|
||||
],
|
||||
'step2' => [
|
||||
'title' => lng('admin.contactdata'),
|
||||
'image' => 'icons/user_add.png',
|
||||
'title' => lng('install.admin.title'),
|
||||
'fields' => [
|
||||
'name' => [
|
||||
'label' => lng('name'),
|
||||
'type' => 'text',
|
||||
'mandatory' => true
|
||||
'mandatory' => true,
|
||||
'value' => old('name', 'Administrator', 'installation'),
|
||||
],
|
||||
'username' => [
|
||||
'label' => lng('username'),
|
||||
'type' => 'text',
|
||||
'mandatory' => true
|
||||
'mandatory' => true,
|
||||
'value' => old('username', 'admin', 'installation'),
|
||||
],
|
||||
'password' => [
|
||||
'label' => lng('password'),
|
||||
'type' => 'password',
|
||||
'mandatory' => true
|
||||
'mandatory' => true,
|
||||
'value' => old('password', null, 'installation'),
|
||||
],
|
||||
'email' => [
|
||||
'label' => lng('email'),
|
||||
'type' => 'text',
|
||||
'mandatory' => true
|
||||
'mandatory' => true,
|
||||
'value' => old('email', null, 'installation'),
|
||||
],
|
||||
]
|
||||
],
|
||||
'step3' => [
|
||||
'title' => lng('admin.servicedata'),
|
||||
'image' => 'icons/user_add.png',
|
||||
'title' => lng('install.system.title'),
|
||||
'fields' => [
|
||||
'ipaddress' => [
|
||||
'label' => lng('serversettings.ipaddress.title'),
|
||||
'type' => 'select'
|
||||
'system' => [
|
||||
'label' => lng('install.system.system'),
|
||||
'type' => 'select',
|
||||
'select_var' => $this->supportedOS,
|
||||
],
|
||||
'change_serversettings' => [
|
||||
'label' => lng('admin.change_serversettings'),
|
||||
'test' => [
|
||||
'label' => lng('install.system.test'),
|
||||
'type' => 'checkbox',
|
||||
'value' => '1',
|
||||
'checked' => false
|
||||
],
|
||||
'customers' => [
|
||||
'label' => lng('admin.customers'),
|
||||
'type' => 'textul',
|
||||
'value' => 0,
|
||||
'maxlength' => 9,
|
||||
'mandatory' => true
|
||||
]
|
||||
],
|
||||
'step4' => [
|
||||
'title' => lng('install.system.title'),
|
||||
'fields' => [
|
||||
'system' => [
|
||||
'label' => lng('install.system.system'),
|
||||
'type' => 'textarea',
|
||||
'value' => '/var/www/html/froxlor/bin/froxlor-cli cron --force',
|
||||
'readonly' => true,
|
||||
'rows' => 1
|
||||
],
|
||||
'customers_see_all' => [
|
||||
'label' => lng('admin.customers_see_all'),
|
||||
'type' => 'checkbox',
|
||||
'value' => '1',
|
||||
'checked' => false
|
||||
],
|
||||
'domains' => [
|
||||
'label' => lng('admin.domains'),
|
||||
'type' => 'textul',
|
||||
'value' => 0,
|
||||
'maxlength' => 9,
|
||||
'mandatory' => true
|
||||
],
|
||||
'domains_see_all' => [
|
||||
'label' => lng('admin.domains_see_all'),
|
||||
'type' => 'checkbox',
|
||||
'value' => '1',
|
||||
'checked' => false
|
||||
],
|
||||
'caneditphpsettings' => [
|
||||
'label' => lng('admin.caneditphpsettings'),
|
||||
'type' => 'checkbox',
|
||||
'value' => '1',
|
||||
'checked' => false
|
||||
],
|
||||
'subdomains' => [
|
||||
'label' => lng('customer.subdomains'),
|
||||
'type' => 'textul',
|
||||
'value' => 0,
|
||||
'maxlength' => 9,
|
||||
'mandatory' => true
|
||||
],
|
||||
'emails' => [
|
||||
'label' => lng('customer.emails'),
|
||||
'type' => 'textul',
|
||||
'value' => 0,
|
||||
'maxlength' => 9,
|
||||
'mandatory' => true
|
||||
],
|
||||
'email_accounts' => [
|
||||
'label' => lng('customer.accounts'),
|
||||
'type' => 'textul',
|
||||
'value' => 0,
|
||||
'maxlength' => 9,
|
||||
'mandatory' => true
|
||||
],
|
||||
'email_forwarders' => [
|
||||
'label' => lng('customer.forwarders'),
|
||||
'type' => 'textul',
|
||||
'value' => 0,
|
||||
'maxlength' => 9,
|
||||
'mandatory' => true
|
||||
],
|
||||
'ftps' => [
|
||||
'label' => lng('customer.ftps'),
|
||||
'type' => 'textul',
|
||||
'value' => 0,
|
||||
'maxlength' => 9
|
||||
],
|
||||
'mysqls' => [
|
||||
'label' => lng('customer.mysqls'),
|
||||
'type' => 'textul',
|
||||
'value' => 0,
|
||||
'maxlength' => 9,
|
||||
'mandatory' => true
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
*/
|
||||
|
||||
use Froxlor\Language;
|
||||
use Froxlor\UI\Request;
|
||||
|
||||
function view($template, $attributes)
|
||||
{
|
||||
@@ -36,3 +37,11 @@ function lng(string $identifier, array $arguments = [])
|
||||
{
|
||||
return Language::getTranslation($identifier, $arguments);
|
||||
}
|
||||
|
||||
function old(string $identifier, string $default = null, string $session = null)
|
||||
{
|
||||
if ($session && isset($_SESSION[$session])) {
|
||||
return $_SESSION[$session][$identifier] ?? $default;
|
||||
}
|
||||
return Request::get($identifier, $default);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user