diff --git a/.env b/.env
index 011aeee..aaa2e34 100644
--- a/.env
+++ b/.env
@@ -3,7 +3,7 @@ DB_SERVERNAME=localhost
DB_PORT=3306
DB_USERNAME=FSST
DB_PASSWORD=L9wUNZZ9Qkbt
-DB_DATABASE=FSS_T
+DB_DATABASE=FabianWebsite
# Optional: Basis-URL (wenn du was dynamisch bauen willst)
APP_URL=https://fabianschieder.com
diff --git a/.env.example b/.env.example
index 011aeee..7e9faa2 100644
--- a/.env.example
+++ b/.env.example
@@ -2,12 +2,20 @@
DB_SERVERNAME=localhost
DB_PORT=3306
DB_USERNAME=FSST
-DB_PASSWORD=L9wUNZZ9Qkbt
-DB_DATABASE=FSS_T
+DB_PASSWORD=
+DB_DATABASE=FabianWebsite
# Optional: Basis-URL (wenn du was dynamisch bauen willst)
APP_URL=https://fabianschieder.com
-# Basic Auth für /adminer (zusätzlicher Schutz)
-ADMINER_BASIC_USER=admin
-ADMINER_BASIC_PASS=L9wUNZZ9Qkbt
+# (Deprecated) Basic Auth für /adminer – wird nicht mehr verwendet
+ADMINER_BASIC_USER=
+ADMINER_BASIC_PASS=
+
+# App-Login für /adminer
+# Registrierung erlauben? 1=ja, 0=nein
+ADMINER_ALLOW_REGISTER=1
+
+# Optional: initialen User automatisch anlegen (einmalig)
+ADMINER_APP_SEED_USER=
+ADMINER_APP_SEED_PASS=
diff --git a/adminer/_smoke_register.php b/adminer/_smoke_register.php
new file mode 100644
index 0000000..4411441
--- /dev/null
+++ b/adminer/_smoke_register.php
@@ -0,0 +1,32 @@
+getMessage() . "\n";
+ exit(1);
+}
+
diff --git a/adminer/index.php b/adminer/index.php
index 91336c8..25c86bf 100644
--- a/adminer/index.php
+++ b/adminer/index.php
@@ -14,6 +14,7 @@ try {
exit;
}
+$appPage = (string)($_GET['page'] ?? 'login'); // login|register
$appAction = (string)($_GET['auth'] ?? '');
if ($appAction === 'logout') {
adminer_app_logout();
@@ -32,27 +33,81 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && (string)($_POST['action'] ?? '') ==
exit;
}
$appError = (string)($res['error'] ?? 'Login fehlgeschlagen.');
+ $appPage = 'login';
+}
+
+// Handle registration
+$appRegError = null;
+$appRegOk = null;
+if ($_SERVER['REQUEST_METHOD'] === 'POST' && (string)($_POST['action'] ?? '') === 'app_register') {
+ $u = (string)($_POST['username'] ?? '');
+ $p1 = (string)($_POST['password'] ?? '');
+ $p2 = (string)($_POST['password2'] ?? '');
+
+ $res = adminer_app_try_register($u, $p1, $p2);
+ if (!empty($res['ok'])) {
+ // Auto-login after register
+ $loginRes = adminer_app_try_login($u, $p1);
+ if (!empty($loginRes['ok'])) {
+ header('Location: /adminer', true, 302);
+ exit;
+ }
+ $appRegOk = 'Registrierung erfolgreich. Bitte einloggen.';
+ $appPage = 'login';
+ } else {
+ $appRegError = (string)($res['error'] ?? 'Registrierung fehlgeschlagen.');
+ $appPage = 'register';
+ }
}
if (!adminer_app_is_logged_in()) {
+ $canRegister = adminer_app_allow_register();
+
$body = '
DB-Verwaltung
Login';
$body .= '';
- $body .= '
Bitte melde dich an, um die DB-Verwaltung zu öffnen.
';
- if ($appError) {
- $body .= '
' . h($appError) . '
';
+ // Tabs
+ $body .= '
';
+
+ if ($appRegOk) {
+ $body .= '
' . h($appRegOk) . '
';
}
- $body .= '
';
+ if ($appPage === 'register') {
+ if (!$canRegister) {
+ $body .= '
Registrierung ist deaktiviert.
';
+ } else {
+ if ($appRegError) $body .= '
' . h($appRegError) . '
';
- $body .= '
';
- $body .= '
Admin-Hinweis: Du kannst initial einen User per .env seeden: '
- . 'ADMINER_APP_SEED_USER + ADMINER_APP_SEED_PASS (einmalig; wird nicht überschrieben).
';
+ $body .= '
Registrieren
';
+ $body .= '
';
+
+ $body .= '
Dein Account wird in FabianWebsite.adminer_users gespeichert.
';
+ }
+ } else {
+ if ($appError) $body .= '
' . h($appError) . '
';
+
+ $body .= '
Login
';
+ $body .= '
';
+
+ if ($canRegister) {
+ $body .= '
';
+ }
+ }
$body .= '
';
diff --git a/adminer/user_auth.php b/adminer/user_auth.php
index 300d3bb..ce0b099 100644
--- a/adminer/user_auth.php
+++ b/adminer/user_auth.php
@@ -1,18 +1,22 @@
(string)env_get($vars, 'DB_SERVERNAME', 'localhost'),
+ 'port' => (int)env_get($vars, 'DB_PORT', '3306'),
+ 'user' => (string)env_get($vars, 'DB_USERNAME', ''),
+ 'pass' => (string)env_get($vars, 'DB_PASSWORD', ''),
+ 'db' => 'FabianWebsite',
+ // Registrierung optional abschaltbar
+ 'allow_register' => ((string)env_get($vars, 'ADMINER_ALLOW_REGISTER', '1')) !== '0',
+ ];
+
+ return $cfg;
+}
+
+function adminer_app_pdo()
+{
+ $cfg = adminer_app_config();
+
+ if ($cfg['host'] === '' || (int)$cfg['port'] <= 0 || $cfg['user'] === '' || $cfg['db'] === '') {
throw new RuntimeException('DB_* ist in .env nicht vollständig gesetzt (für Admin-Login-User-Store).');
}
- $dsn = sprintf('mysql:host=%s;port=%d;dbname=%s;charset=utf8mb4', $host, $port, $db);
+ $dsn = sprintf('mysql:host=%s;port=%d;dbname=%s;charset=utf8mb4', $cfg['host'], (int)$cfg['port'], $cfg['db']);
- return new PDO($dsn, $user, $pass, [
+ return new PDO($dsn, $cfg['user'], $cfg['pass'], [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);
}
+function adminer_validate_username($u)
+{
+ $u = trim((string)$u);
+ if ($u === '') return [false, 'Benutzername darf nicht leer sein.'];
+ if (strlen($u) < 3) return [false, 'Benutzername ist zu kurz (min. 3 Zeichen).'];
+ if (strlen($u) > 50) return [false, 'Benutzername ist zu lang (max. 50 Zeichen).'];
+ if (!preg_match('/^[A-Za-z0-9_.-]+$/', $u)) return [false, 'Nur Buchstaben, Zahlen, Punkt, Unterstrich und Minus sind erlaubt.'];
+ return [true, null];
+}
+
function adminer_app_bootstrap()
{
$pdo = adminer_app_pdo();
- // Minimal users table
$pdo->exec(
'CREATE TABLE IF NOT EXISTS adminer_users ('
. 'id INT AUTO_INCREMENT PRIMARY KEY,'
@@ -64,12 +90,12 @@ function adminer_app_bootstrap()
if ($seedUser !== '' && $seedPass !== '') {
$stmt = $pdo->prepare('SELECT id FROM adminer_users WHERE username = ?');
- $stmt->execute([$seedUser]);
+ $stmt->execute([(string)$seedUser]);
$exists = (bool)$stmt->fetchColumn();
if (!$exists) {
- $hash = password_hash($seedPass, PASSWORD_DEFAULT);
+ $hash = password_hash((string)$seedPass, PASSWORD_DEFAULT);
$ins = $pdo->prepare('INSERT INTO adminer_users (username, password_hash) VALUES (?, ?)');
- $ins->execute([$seedUser, $hash]);
+ $ins->execute([(string)$seedUser, $hash]);
}
}
}
@@ -77,12 +103,18 @@ function adminer_app_bootstrap()
function adminer_app_is_logged_in()
{
adminer_app_session_start();
+ if (PHP_SAPI === 'cli') {
+ return false;
+ }
return !empty($_SESSION['adminer_app']['ok']);
}
function adminer_app_logout()
{
adminer_app_session_start();
+ if (PHP_SAPI === 'cli') {
+ return;
+ }
unset($_SESSION['adminer_app']);
}
@@ -105,11 +137,54 @@ function adminer_app_try_login($username, $password)
}
adminer_app_session_start();
- $_SESSION['adminer_app'] = [
- 'ok' => true,
- 'username' => $username,
- 'uid' => (int)$row['id'],
- ];
+ if (PHP_SAPI !== 'cli') {
+ $_SESSION['adminer_app'] = [
+ 'ok' => true,
+ 'username' => $username,
+ 'uid' => (int)$row['id'],
+ ];
+ }
+
+ return ['ok' => true, 'error' => null];
+}
+
+function adminer_app_allow_register()
+{
+ $cfg = adminer_app_config();
+ return !empty($cfg['allow_register']);
+}
+
+function adminer_app_try_register($username, $password, $password2)
+{
+ if (!adminer_app_allow_register()) {
+ return ['ok' => false, 'error' => 'Registrierung ist deaktiviert.'];
+ }
+
+ list($ok, $msg) = adminer_validate_username($username);
+ if (!$ok) return ['ok' => false, 'error' => $msg];
+
+ $password = (string)$password;
+ $password2 = (string)$password2;
+
+ if (strlen($password) < 8) {
+ return ['ok' => false, 'error' => 'Passwort ist zu kurz (min. 8 Zeichen).'];
+ }
+ if ($password !== $password2) {
+ return ['ok' => false, 'error' => 'Passwörter stimmen nicht überein.'];
+ }
+
+ $pdo = adminer_app_pdo();
+
+ // Unique check
+ $stmt = $pdo->prepare('SELECT id FROM adminer_users WHERE username = ?');
+ $stmt->execute([trim((string)$username)]);
+ if ($stmt->fetchColumn()) {
+ return ['ok' => false, 'error' => 'Benutzername ist bereits vergeben.'];
+ }
+
+ $hash = password_hash($password, PASSWORD_DEFAULT);
+ $ins = $pdo->prepare('INSERT INTO adminer_users (username, password_hash) VALUES (?, ?)');
+ $ins->execute([trim((string)$username), $hash]);
return ['ok' => true, 'error' => null];
}