Vollständiges, schlankes PHP/SQLite-CMS für IT-, KI- und Gaming-Inhalte: - Core: DB-Singleton, Auth mit Passwort-Hashing, Session-Cookies, CSRF-Schutz, Login-Rate-Limit, Bild-Upload mit serverseitiger Validierung - Admin: Dashboard, Artikel/Seiten-Verwaltung mit Quill WYSIWYG-Editor, Kategorien, Navigation (Drag & Drop), Medienbibliothek, Profil - Frontend: Responsive Dark-Theme, Artikel-Grid, Kategorie-Filter, Archiv, Paginierung, SEO-Meta-Tags - Sicherheit: Prepared Statements, HTML-Sanitizer, .htaccess-Schutz für sensible Verzeichnisse, PHP-Ausführungsschutz im Upload-Ordner - Installation: install.php erstellt DB-Schema und Admin-Account https://claude.ai/code/session_01Xsg4j2t4S9goMuWVpF3ezG
195 lines
8.3 KiB
PHP
195 lines
8.3 KiB
PHP
<?php
|
|
/**
|
|
* Installations-Script: Erstellt die Datenbank und den Admin-Benutzer.
|
|
* Nach der Installation sollte diese Datei gelöscht werden.
|
|
*/
|
|
|
|
require_once __DIR__ . '/config/config.php';
|
|
|
|
date_default_timezone_set(TIMEZONE);
|
|
|
|
// Prüfen ob bereits installiert
|
|
if (file_exists(DB_PATH)) {
|
|
die('Die Datenbank existiert bereits. Lösche diese Datei aus Sicherheitsgründen.');
|
|
}
|
|
|
|
// Datenbank-Verzeichnis prüfen
|
|
$dataDir = dirname(DB_PATH);
|
|
if (!is_dir($dataDir)) {
|
|
mkdir($dataDir, 0755, true);
|
|
}
|
|
|
|
echo "<html><head><meta charset='UTF-8'><title>DasPoschi CMS - Installation</title>
|
|
<style>
|
|
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; max-width: 600px; margin: 50px auto; padding: 20px; background: #1a1a2e; color: #e0e0e0; }
|
|
h1 { color: #00d4ff; }
|
|
form { background: #16213e; padding: 30px; border-radius: 8px; }
|
|
label { display: block; margin: 15px 0 5px; font-weight: 600; }
|
|
input { width: 100%; padding: 10px; border: 1px solid #333; border-radius: 4px; background: #0f3460; color: #e0e0e0; box-sizing: border-box; }
|
|
button { margin-top: 20px; padding: 12px 30px; background: #00d4ff; color: #1a1a2e; border: none; border-radius: 4px; font-size: 16px; font-weight: 600; cursor: pointer; }
|
|
button:hover { background: #00b8d9; }
|
|
.success { background: #0a3d2a; border: 1px solid #00d474; padding: 20px; border-radius: 8px; margin-top: 20px; }
|
|
.error { background: #3d0a0a; border: 1px solid #d40000; padding: 20px; border-radius: 8px; margin-top: 20px; }
|
|
</style></head><body>";
|
|
|
|
echo "<h1>DasPoschi CMS - Installation</h1>";
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
$username = trim($_POST['username'] ?? '');
|
|
$displayName = trim($_POST['display_name'] ?? '');
|
|
$password = $_POST['password'] ?? '';
|
|
$passwordConfirm = $_POST['password_confirm'] ?? '';
|
|
|
|
$errors = [];
|
|
if (strlen($username) < 3) {
|
|
$errors[] = 'Benutzername muss mindestens 3 Zeichen lang sein.';
|
|
}
|
|
if (strlen($password) < 10) {
|
|
$errors[] = 'Passwort muss mindestens 10 Zeichen lang sein.';
|
|
}
|
|
if ($password !== $passwordConfirm) {
|
|
$errors[] = 'Passwörter stimmen nicht überein.';
|
|
}
|
|
if (empty($displayName)) {
|
|
$displayName = $username;
|
|
}
|
|
|
|
if (!empty($errors)) {
|
|
echo "<div class='error'><ul>";
|
|
foreach ($errors as $err) {
|
|
echo "<li>" . htmlspecialchars($err) . "</li>";
|
|
}
|
|
echo "</ul></div>";
|
|
} else {
|
|
try {
|
|
$pdo = new PDO('sqlite:' . DB_PATH, null, null, [
|
|
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
|
]);
|
|
$pdo->exec('PRAGMA journal_mode=WAL');
|
|
$pdo->exec('PRAGMA foreign_keys=ON');
|
|
|
|
// Tabellen erstellen
|
|
$pdo->exec("
|
|
CREATE TABLE users (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
username TEXT NOT NULL UNIQUE,
|
|
password_hash TEXT NOT NULL,
|
|
display_name TEXT NOT NULL DEFAULT '',
|
|
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
)
|
|
");
|
|
|
|
$pdo->exec("
|
|
CREATE TABLE categories (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
name TEXT NOT NULL UNIQUE,
|
|
slug TEXT NOT NULL UNIQUE,
|
|
description TEXT NOT NULL DEFAULT '',
|
|
sort_order INTEGER NOT NULL DEFAULT 0
|
|
)
|
|
");
|
|
|
|
$pdo->exec("
|
|
CREATE TABLE articles (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
title TEXT NOT NULL,
|
|
slug TEXT NOT NULL UNIQUE,
|
|
excerpt TEXT NOT NULL DEFAULT '',
|
|
body TEXT NOT NULL DEFAULT '',
|
|
cover_image TEXT DEFAULT NULL,
|
|
category_id INTEGER DEFAULT NULL,
|
|
status TEXT NOT NULL DEFAULT 'draft' CHECK(status IN ('draft','published')),
|
|
published_at TEXT DEFAULT NULL,
|
|
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
FOREIGN KEY (category_id) REFERENCES categories(id) ON DELETE SET NULL
|
|
)
|
|
");
|
|
|
|
$pdo->exec("
|
|
CREATE TABLE pages (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
title TEXT NOT NULL,
|
|
slug TEXT NOT NULL UNIQUE,
|
|
body TEXT NOT NULL DEFAULT '',
|
|
status TEXT NOT NULL DEFAULT 'draft' CHECK(status IN ('draft','published')),
|
|
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
)
|
|
");
|
|
|
|
$pdo->exec("
|
|
CREATE TABLE navigation (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
label TEXT NOT NULL,
|
|
type TEXT NOT NULL CHECK(type IN ('url','page','category','home')),
|
|
target TEXT NOT NULL DEFAULT '',
|
|
sort_order INTEGER NOT NULL DEFAULT 0,
|
|
parent_id INTEGER DEFAULT NULL,
|
|
FOREIGN KEY (parent_id) REFERENCES navigation(id) ON DELETE CASCADE
|
|
)
|
|
");
|
|
|
|
$pdo->exec("
|
|
CREATE TABLE login_attempts (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
ip_address TEXT NOT NULL,
|
|
attempted_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
)
|
|
");
|
|
$pdo->exec("CREATE INDEX idx_login_attempts_ip ON login_attempts(ip_address, attempted_at)");
|
|
|
|
// Admin-Benutzer anlegen
|
|
$hash = password_hash($password, PASSWORD_DEFAULT);
|
|
$stmt = $pdo->prepare('INSERT INTO users (username, password_hash, display_name) VALUES (?, ?, ?)');
|
|
$stmt->execute([$username, $hash, $displayName]);
|
|
|
|
// Standard-Navigation
|
|
$pdo->exec("INSERT INTO navigation (label, type, target, sort_order) VALUES ('Startseite', 'home', '', 0)");
|
|
|
|
// Standard-Kategorien
|
|
$pdo->exec("INSERT INTO categories (name, slug, description, sort_order) VALUES ('IT', 'it', 'Technik und Programmierung', 0)");
|
|
$pdo->exec("INSERT INTO categories (name, slug, description, sort_order) VALUES ('KI', 'ki', 'Künstliche Intelligenz', 1)");
|
|
$pdo->exec("INSERT INTO categories (name, slug, description, sort_order) VALUES ('Gaming', 'gaming', 'Spiele und Gaming-Kultur', 2)");
|
|
|
|
echo "<div class='success'>";
|
|
echo "<h2>Installation erfolgreich!</h2>";
|
|
echo "<p>Der Admin-Account wurde erstellt. Du kannst dich jetzt anmelden:</p>";
|
|
echo "<p><a href='/admin/login.php' style='color: #00d4ff;'>Zum Admin-Login →</a></p>";
|
|
echo "<p><strong>Wichtig:</strong> Lösche diese Datei (install.php) nach der Installation!</p>";
|
|
echo "</div>";
|
|
echo "</body></html>";
|
|
exit;
|
|
|
|
} catch (Exception $ex) {
|
|
// DB-Datei wieder löschen bei Fehler
|
|
if (file_exists(DB_PATH)) {
|
|
unlink(DB_PATH);
|
|
}
|
|
echo "<div class='error'>Fehler bei der Installation: " . htmlspecialchars($ex->getMessage()) . "</div>";
|
|
}
|
|
}
|
|
}
|
|
|
|
echo "
|
|
<form method='post'>
|
|
<label for='username'>Benutzername</label>
|
|
<input type='text' id='username' name='username' required minlength='3'
|
|
value='" . htmlspecialchars($_POST['username'] ?? '') . "'>
|
|
|
|
<label for='display_name'>Anzeigename (optional)</label>
|
|
<input type='text' id='display_name' name='display_name'
|
|
value='" . htmlspecialchars($_POST['display_name'] ?? '') . "'>
|
|
|
|
<label for='password'>Passwort (mind. 10 Zeichen)</label>
|
|
<input type='password' id='password' name='password' required minlength='10'>
|
|
|
|
<label for='password_confirm'>Passwort bestätigen</label>
|
|
<input type='password' id='password_confirm' name='password_confirm' required>
|
|
|
|
<button type='submit'>Installieren</button>
|
|
</form>";
|
|
|
|
echo "</body></html>";
|