Files
dasposchi-de/install.php
Claude 3c97192386 Initiales CMS: Deutschsprachiges Blog-System mit Admin-Bereich
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
2026-04-05 20:59:52 +00:00

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 &rarr;</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>";