192 lines
5.8 KiB
PHP
192 lines
5.8 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
require_once __DIR__ . '/env.php';
|
|
|
|
/**
|
|
* App-Login (schöne Login-Seite) für /adminer.
|
|
* Nutzer werden in einer MySQL-Tabelle gespeichert.
|
|
*
|
|
* Alles liegt in der DB "FabianWebsite".
|
|
*/
|
|
|
|
function adminer_app_session_start()
|
|
{
|
|
// CLI: keine Sessions/Headers
|
|
if (PHP_SAPI === 'cli') {
|
|
return;
|
|
}
|
|
|
|
if (session_status() === PHP_SESSION_NONE) {
|
|
ini_set('session.cookie_httponly', '1');
|
|
if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') {
|
|
ini_set('session.cookie_secure', '1');
|
|
}
|
|
session_start();
|
|
}
|
|
}
|
|
|
|
function adminer_app_config()
|
|
{
|
|
$vars = env_load(dirname(__DIR__) . '/.env');
|
|
|
|
// DB fest auf FabianWebsite, wie gewünscht.
|
|
$cfg = [
|
|
'host' => (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', $cfg['host'], (int)$cfg['port'], $cfg['db']);
|
|
|
|
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();
|
|
|
|
$pdo->exec(
|
|
'CREATE TABLE IF NOT EXISTS adminer_users ('
|
|
. 'id INT AUTO_INCREMENT PRIMARY KEY,'
|
|
. 'username VARCHAR(190) NOT NULL UNIQUE,'
|
|
. 'password_hash VARCHAR(255) NOT NULL,'
|
|
. 'created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP'
|
|
. ') ENGINE=InnoDB DEFAULT CHARSET=utf8mb4'
|
|
);
|
|
|
|
// Optional: auto-seed from .env ADMINER_APP_SEED_USER/PASS
|
|
$vars = env_load(dirname(__DIR__) . '/.env');
|
|
$seedUser = env_get($vars, 'ADMINER_APP_SEED_USER', '');
|
|
$seedPass = env_get($vars, 'ADMINER_APP_SEED_PASS', '');
|
|
|
|
if ($seedUser !== '' && $seedPass !== '') {
|
|
$stmt = $pdo->prepare('SELECT id FROM adminer_users WHERE username = ?');
|
|
$stmt->execute([(string)$seedUser]);
|
|
$exists = (bool)$stmt->fetchColumn();
|
|
if (!$exists) {
|
|
$hash = password_hash((string)$seedPass, PASSWORD_DEFAULT);
|
|
$ins = $pdo->prepare('INSERT INTO adminer_users (username, password_hash) VALUES (?, ?)');
|
|
$ins->execute([(string)$seedUser, $hash]);
|
|
}
|
|
}
|
|
}
|
|
|
|
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']);
|
|
}
|
|
|
|
function adminer_app_try_login($username, $password)
|
|
{
|
|
$username = trim((string)$username);
|
|
$password = (string)$password;
|
|
|
|
if ($username === '' || $password === '') {
|
|
return ['ok' => false, 'error' => 'Bitte Benutzername und Passwort eingeben.'];
|
|
}
|
|
|
|
$pdo = adminer_app_pdo();
|
|
$stmt = $pdo->prepare('SELECT id, password_hash FROM adminer_users WHERE username = ?');
|
|
$stmt->execute([$username]);
|
|
$row = $stmt->fetch();
|
|
|
|
if (!$row || empty($row['password_hash']) || !password_verify($password, (string)$row['password_hash'])) {
|
|
return ['ok' => false, 'error' => 'Login fehlgeschlagen.'];
|
|
}
|
|
|
|
adminer_app_session_start();
|
|
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];
|
|
}
|
|
|