+ addExtension(new DebugExtension());
$template = $twigWrapper->loadTemplate($pathToTwigFile);
$response->setContent($template->render($templateVars));
diff --git a/phpmyfaq/src/phpMyFAQ/Controller/Setup/SetupController.php b/phpmyfaq/src/phpMyFAQ/Controller/Api/SetupController.php
similarity index 98%
rename from phpmyfaq/src/phpMyFAQ/Controller/Setup/SetupController.php
rename to phpmyfaq/src/phpMyFAQ/Controller/Api/SetupController.php
index 8a482d21d7..1cc6e6aa08 100644
--- a/phpmyfaq/src/phpMyFAQ/Controller/Setup/SetupController.php
+++ b/phpmyfaq/src/phpMyFAQ/Controller/Api/SetupController.php
@@ -15,9 +15,8 @@
* @since 2023-10-17
*/
-namespace phpMyFAQ\Controller\Setup;
+namespace phpMyFAQ\Controller\Api;
-use phpMyFAQ\Configuration;
use phpMyFAQ\Controller\AbstractController;
use phpMyFAQ\Core\Exception;
use phpMyFAQ\Database;
diff --git a/phpmyfaq/src/phpMyFAQ/Controller/Frontend/SetupController.php b/phpmyfaq/src/phpMyFAQ/Controller/Frontend/SetupController.php
new file mode 100644
index 0000000000..85daa9410e
--- /dev/null
+++ b/phpmyfaq/src/phpMyFAQ/Controller/Frontend/SetupController.php
@@ -0,0 +1,119 @@
+
+ * @copyright 2024 phpMyFAQ Team
+ * @license https://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0
+ * @link https://www.phpmyfaq.de
+ * @since 2024-06-01
+ */
+
+namespace phpMyFAQ\Controller\Frontend;
+
+use Elastic\Elasticsearch\Exception\AuthenticationException;
+use phpMyFAQ\Controller\AbstractController;
+use phpMyFAQ\Core\Exception;
+use phpMyFAQ\Language\LanguageCodes;
+use phpMyFAQ\Setup\Installer;
+use phpMyFAQ\System;
+use phpMyFAQ\Template\TemplateException;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\Routing\Annotation\Route;
+
+class SetupController extends AbstractController
+{
+ /**
+ * @throws TemplateException
+ * @throws \Exception
+ */
+ #[Route('/setup', name: 'public.setup.update')]
+ public function index(): Response
+ {
+ $system = new System();
+ $installer = new Installer($system);
+
+ $checkBasicError = '';
+
+ try {
+ $installer->checkBasicStuff();
+ } catch (Exception $e) {
+ $checkBasicError = $e->getMessage();
+ }
+
+ return $this->render(
+ 'setup/index.twig',
+ [
+ 'newVersion' => System::getVersion(),
+ 'setupType' => 'Setup',
+ 'currentYear' => date('Y'),
+ 'currentLanguage' => 'en',
+ 'documentationUrl' => System::getDocumentationUrl(),
+ 'checkBasicError' => $checkBasicError,
+ 'nonCriticalSettings' => $installer->checkNoncriticalSettings(),
+ 'supportedDatabases' => $system->getSupportedSafeDatabases(),
+ 'currentPath' => dirname(__DIR__, 4),
+ 'isLdapEnabled' => $installer->hasLdapSupport(),
+ 'isElasticsearchEnabled' => $installer->hasElasticsearchSupport(),
+ 'supportedTranslations' => LanguageCodes::getAllSupported(),
+ ]
+ );
+ }
+
+ /**
+ * @throws TemplateException
+ * @throws \Exception
+ */
+ #[Route('/setup/install', name: 'public.setup.install')]
+ public function install(): Response
+ {
+ $system = new System();
+ $installer = new Installer($system);
+
+ $checkBasicError = $installationError = '';
+
+ try {
+ $installer->checkBasicStuff();
+ } catch (Exception $e) {
+ $checkBasicError = $e->getMessage();
+ }
+
+ try {
+ $installer->startInstall();
+ } catch (Exception | AuthenticationException $e) {
+ $installationError = $e->getMessage();
+ }
+
+ return $this->render(
+ 'setup/install.twig',
+ [
+ 'newVersion' => System::getVersion(),
+ 'setupType' => 'Setup',
+ 'currentYear' => date('Y'),
+ 'documentationUrl' => System::getDocumentationUrl(),
+ 'checkBasicError' => $checkBasicError,
+ 'installationError' => $installationError,
+ ]
+ );
+ }
+
+ /**
+ * @throws TemplateException
+ */
+ #[Route('/setup/update', name: 'public.setup.update')]
+ public function update(): Response
+ {
+ return $this->render(
+ 'setup/update.twig',
+ [
+ 'currentStep' => $step ?? 1,
+ ]
+ );
+ }
+}
diff --git a/phpmyfaq/src/phpMyFAQ/Language.php b/phpmyfaq/src/phpMyFAQ/Language.php
index 45421d32ac..4d4c4dd6e6 100644
--- a/phpmyfaq/src/phpMyFAQ/Language.php
+++ b/phpmyfaq/src/phpMyFAQ/Language.php
@@ -165,6 +165,24 @@ public function setLanguageByAcceptLanguage(): string
return self::$language = $this->acceptLanguage;
}
+ /**
+ * True if the language is supported by the current phpMyFAQ installation.
+ *
+ * @param string|null $langCode Language code
+ */
+ public static function isASupportedLanguage(?string $langCode): bool
+ {
+ return $langCode !== null && LanguageCodes::getSupported($langCode) !== null;
+ }
+
+ /**
+ * Returns the current language.
+ */
+ public function getLanguage(): string
+ {
+ return self::$language;
+ }
+
/**
* Gets the accepted language from the user agent.
*
@@ -193,22 +211,4 @@ private function getUserAgentLanguage(): void
}
}
}
-
- /**
- * True if the language is supported by the current phpMyFAQ installation.
- *
- * @param string|null $langCode Language code
- */
- public static function isASupportedLanguage(?string $langCode): bool
- {
- return $langCode !== null && LanguageCodes::getSupported($langCode) !== null;
- }
-
- /**
- * Returns the current language.
- */
- public function getLanguage(): string
- {
- return self::$language;
- }
}
diff --git a/phpmyfaq/src/phpMyFAQ/Setup/Installer.php b/phpmyfaq/src/phpMyFAQ/Setup/Installer.php
index 3117eca1f3..af1c6afdcd 100644
--- a/phpmyfaq/src/phpMyFAQ/Setup/Installer.php
+++ b/phpmyfaq/src/phpMyFAQ/Setup/Installer.php
@@ -619,7 +619,7 @@ public function checkBasicStuff(): void
if (!$this->system->checkInstallation()) {
throw new Exception(
- 'phpMyFAQ is already installed! Please use the update.'
+ 'phpMyFAQ is already installed! Please use the update.'
);
}
}
@@ -704,43 +704,47 @@ public function checkFilesystemPermissions(): void
/**
* Checks some non-critical settings and print some hints.
*
- * @todo We should return an array of messages
+ * @return string[]
*/
- public function checkNoncriticalSettings(): void
+ public function checkNoncriticalSettings(): array
{
+ $hints = [];
if (!$this->system->getHttpsStatus()) {
- echo '
phpMyFAQ could not find HTTPS support. For security reasons we ' .
- 'recommend activating HTTPS.
';
+ $hints[] = '
phpMyFAQ could not find HTTPS support. For security reasons ' .
+ 'we recommend activating HTTPS.
';
}
if (!extension_loaded('gd')) {
- echo '
You don\'t have GD support enabled in your PHP installation. Please ' .
- "enable GD support in your php.ini file otherwise you can't use Captchas for spam protection.
";
+ $hints[] = '
You don\'t have GD support enabled in your PHP installation. ' .
+ "Please enable GD support in your php.ini file otherwise you can't use Captchas for spam protection." .
+ "
";
}
if (!function_exists('imagettftext')) {
- echo '
You don\'t have Freetype support enabled in the GD extension of ' .
- 'your PHP installation. Please enable Freetype support in GD extension otherwise the Captchas ' .
+ $hints[] = '
You don\'t have Freetype support enabled in the GD extension ' .
+ ' ofyour PHP installation. Please enable Freetype support in GD extension otherwise the Captchas ' .
'for spam protection will be quite easy to break.
';
}
if (!extension_loaded('curl') || !extension_loaded('openssl')) {
- echo '
You don\'t have cURL and/or OpenSSL support enabled in your PHP ' .
- "installation. Please enable cURL and/or OpenSSL support in your php.ini file otherwise you can't " .
- 'use Elasticsearch.
';
+ $hints[] = '
You don\'t have cURL and/or OpenSSL support enabled in your ' .
+ "PHP installation. Please enable cURL and/or OpenSSL support in your php.ini file otherwise you " .
+ " can't use Elasticsearch.
";
}
if (!extension_loaded('fileinfo')) {
- echo '
You don\'t have Fileinfo support enabled in your PHP installation. ' .
- "Please enable Fileinfo support in your php.ini file otherwise you can't use our backup/restore " .
- 'functionality.
';
+ $hints[] = '
You don\'t have Fileinfo support enabled in your PHP ' .
+ "installation. Please enable Fileinfo support in your php.ini file otherwise you can't use our " .
+ 'backup/restore functionality.
';
}
if (!extension_loaded('sodium')) {
- echo '
You don\'t have Sodium support enabled in your PHP installation. ' .
- "Please enable Sodium support in your php.ini file otherwise you can't use our backup/restore " .
- 'functionality.
';
+ $hints[] = '
You don\'t have Sodium support enabled in your PHP ' .
+ "installation. Please enable Sodium support in your php.ini file otherwise you can't use our " .
+ 'backup/restore functionality.
';
}
+
+ return $hints;
}
/**
@@ -751,6 +755,7 @@ public function checkNoncriticalSettings(): void
*/
public function startInstall(array|null $setup = null): void
{
+ $feedbacks = [];
$ldapSetup = [];
$query = [];
$uninstall = [];
@@ -1231,4 +1236,14 @@ public function adjustRewriteBaseHtaccess(string $path): bool
return file_put_contents($htaccessPath, implode('', $newLines)) !== false;
}
+
+ public function hasLdapSupport(): bool
+ {
+ return extension_loaded('ldap');
+ }
+
+ public function hasElasticsearchSupport(): bool
+ {
+ return extension_loaded('curl') && extension_loaded('openssl');
+ }
}
diff --git a/phpmyfaq/src/phpMyFAQ/System.php b/phpmyfaq/src/phpMyFAQ/System.php
index 5bebde18a0..bb34f04d24 100644
--- a/phpmyfaq/src/phpMyFAQ/System.php
+++ b/phpmyfaq/src/phpMyFAQ/System.php
@@ -244,9 +244,9 @@ public function getAvailableTemplates(): array
*
* @return array
*/
- public function getSupportedSafeDatabases(bool $returnAsHtml = false): array
+ public function getSupportedSafeDatabases(): array
{
- $retVal = [];
+ $databases = [];
foreach ($this->getSupportedDatabases() as $extension => $database) {
if (!extension_loaded($extension)) {
continue;
@@ -254,14 +254,10 @@ public function getSupportedSafeDatabases(bool $returnAsHtml = false): array
if (version_compare(PHP_VERSION, $database[0]) < 0) {
continue;
}
- if ($returnAsHtml) {
- $retVal[] = sprintf('', $extension, $database[1]);
- } else {
- $retVal[$extension] = $database;
- }
+ $databases[$extension] = $database[1];
}
- return $retVal;
+ return $databases;
}
/**
diff --git a/phpmyfaq/src/phpMyFAQ/Template/TwigWrapper.php b/phpmyfaq/src/phpMyFAQ/Template/TwigWrapper.php
index c1296c1048..ac5ea98501 100644
--- a/phpmyfaq/src/phpMyFAQ/Template/TwigWrapper.php
+++ b/phpmyfaq/src/phpMyFAQ/Template/TwigWrapper.php
@@ -17,6 +17,7 @@
namespace phpMyFAQ\Template;
+use phpMyFAQ\Core\Exception;
use phpMyFAQ\System;
use Twig\Environment;
use Twig\Error\LoaderError;
@@ -44,14 +45,14 @@ public function __construct(string $templatePath)
}
/**
- * @throws TemplateException
+ * @throws Exception
*/
public function loadTemplate(string $templateFile): TemplateWrapper
{
try {
return $this->twigEnvironment->load($templateFile);
} catch (LoaderError | RuntimeError | SyntaxError $exception) {
- throw new TemplateException($exception->getMessage());
+ throw new Exception($exception->getMessage());
}
}
diff --git a/phpmyfaq/src/public-routes.php b/phpmyfaq/src/public-routes.php
new file mode 100644
index 0000000000..e9587c90a6
--- /dev/null
+++ b/phpmyfaq/src/public-routes.php
@@ -0,0 +1,35 @@
+
+ * @copyright 2024 phpMyFAQ Team
+ * @license https://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0
+ * @link https://www.phpmyfaq.de
+ * @since 2024-05-31
+ */
+
+use phpMyFAQ\Controller\Frontend\SetupController;
+use Symfony\Component\Routing\Route;
+use Symfony\Component\Routing\RouteCollection;
+
+$routes = new RouteCollection();
+
+$routeDefinitions = [
+ // Setup and update
+ 'public.setup.index' => ['/', SetupController::class, 'index'],
+ 'public.setup.install' => ['/install', SetupController::class, 'install'],
+ 'public.setup.update' => ['/update', SetupController::class, 'update'],
+];
+
+foreach ($routeDefinitions as $name => [$path, $controller, $action]) {
+ $routes->add($name, new Route($path, ['_controller' => [$controller, $action]]));
+}
+
+return $routes;