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
This commit is contained in:
180
index.php
Normal file
180
index.php
Normal file
@@ -0,0 +1,180 @@
|
||||
<?php
|
||||
/**
|
||||
* Öffentlicher Front-Controller / Router
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/config/config.php';
|
||||
require_once __DIR__ . '/core/db.php';
|
||||
require_once __DIR__ . '/core/helpers.php';
|
||||
|
||||
date_default_timezone_set(TIMEZONE);
|
||||
|
||||
$route = trim($_GET['route'] ?? '', '/');
|
||||
$segments = $route === '' ? [] : explode('/', $route);
|
||||
|
||||
// Navigation für alle Seiten laden
|
||||
$navItems = db()->query('SELECT * FROM navigation ORDER BY sort_order')->fetchAll();
|
||||
|
||||
// Navigations-URLs auflösen
|
||||
foreach ($navItems as &$nav) {
|
||||
switch ($nav['type']) {
|
||||
case 'home':
|
||||
$nav['url'] = '/';
|
||||
break;
|
||||
case 'page':
|
||||
$stmt = db()->prepare('SELECT slug FROM pages WHERE id = ? AND status = "published"');
|
||||
$stmt->execute([$nav['target']]);
|
||||
$pg = $stmt->fetchColumn();
|
||||
$nav['url'] = $pg ? '/seite/' . $pg : '#';
|
||||
break;
|
||||
case 'category':
|
||||
$stmt = db()->prepare('SELECT slug FROM categories WHERE id = ?');
|
||||
$stmt->execute([$nav['target']]);
|
||||
$cat = $stmt->fetchColumn();
|
||||
$nav['url'] = $cat ? '/kategorie/' . $cat : '#';
|
||||
break;
|
||||
case 'url':
|
||||
$nav['url'] = $nav['target'];
|
||||
break;
|
||||
default:
|
||||
$nav['url'] = '#';
|
||||
}
|
||||
}
|
||||
unset($nav);
|
||||
|
||||
// Routing
|
||||
$action = $segments[0] ?? '';
|
||||
$param = $segments[1] ?? '';
|
||||
|
||||
switch ($action) {
|
||||
case '':
|
||||
// Startseite
|
||||
$page = max(1, (int) ($_GET['page'] ?? 1));
|
||||
$total = (int) db()->query("SELECT COUNT(*) FROM articles WHERE status='published'")->fetchColumn();
|
||||
$pag = paginate($total, $page, ITEMS_PER_PAGE);
|
||||
|
||||
$stmt = db()->prepare(
|
||||
"SELECT a.*, c.name as category_name, c.slug as category_slug
|
||||
FROM articles a LEFT JOIN categories c ON a.category_id = c.id
|
||||
WHERE a.status='published' ORDER BY a.published_at DESC LIMIT ? OFFSET ?"
|
||||
);
|
||||
$stmt->execute([$pag['limit'], $pag['offset']]);
|
||||
$articles = $stmt->fetchAll();
|
||||
|
||||
$categories = db()->query('SELECT * FROM categories ORDER BY sort_order, name')->fetchAll();
|
||||
|
||||
$pageTitle = SITE_TITLE . ' - ' . SITE_DESCRIPTION;
|
||||
$metaDescription = 'Blog über IT, Künstliche Intelligenz und Gaming.';
|
||||
ob_start();
|
||||
include __DIR__ . '/templates/home.php';
|
||||
$content = ob_get_clean();
|
||||
break;
|
||||
|
||||
case 'artikel':
|
||||
if ($param === '') { redirect('/'); }
|
||||
$stmt = db()->prepare(
|
||||
"SELECT a.*, c.name as category_name, c.slug as category_slug
|
||||
FROM articles a LEFT JOIN categories c ON a.category_id = c.id
|
||||
WHERE a.slug = ? AND a.status='published'"
|
||||
);
|
||||
$stmt->execute([$param]);
|
||||
$article = $stmt->fetch();
|
||||
if (!$article) {
|
||||
http_response_code(404);
|
||||
$pageTitle = 'Nicht gefunden';
|
||||
ob_start();
|
||||
include __DIR__ . '/templates/404.php';
|
||||
$content = ob_get_clean();
|
||||
break;
|
||||
}
|
||||
$pageTitle = $article['title'] . ' - ' . SITE_TITLE;
|
||||
$metaDescription = $article['excerpt'] ?: excerpt($article['body']);
|
||||
$ogImage = $article['cover_image'] ?? '';
|
||||
ob_start();
|
||||
include __DIR__ . '/templates/article.php';
|
||||
$content = ob_get_clean();
|
||||
break;
|
||||
|
||||
case 'seite':
|
||||
if ($param === '') { redirect('/'); }
|
||||
$stmt = db()->prepare("SELECT * FROM pages WHERE slug = ? AND status='published'");
|
||||
$stmt->execute([$param]);
|
||||
$staticPage = $stmt->fetch();
|
||||
if (!$staticPage) {
|
||||
http_response_code(404);
|
||||
$pageTitle = 'Nicht gefunden';
|
||||
ob_start();
|
||||
include __DIR__ . '/templates/404.php';
|
||||
$content = ob_get_clean();
|
||||
break;
|
||||
}
|
||||
$pageTitle = $staticPage['title'] . ' - ' . SITE_TITLE;
|
||||
ob_start();
|
||||
include __DIR__ . '/templates/page.php';
|
||||
$content = ob_get_clean();
|
||||
break;
|
||||
|
||||
case 'kategorie':
|
||||
if ($param === '') { redirect('/'); }
|
||||
$stmt = db()->prepare('SELECT * FROM categories WHERE slug = ?');
|
||||
$stmt->execute([$param]);
|
||||
$category = $stmt->fetch();
|
||||
if (!$category) {
|
||||
http_response_code(404);
|
||||
$pageTitle = 'Nicht gefunden';
|
||||
ob_start();
|
||||
include __DIR__ . '/templates/404.php';
|
||||
$content = ob_get_clean();
|
||||
break;
|
||||
}
|
||||
|
||||
$page = max(1, (int) ($_GET['page'] ?? 1));
|
||||
$totalStmt = db()->prepare("SELECT COUNT(*) FROM articles WHERE status='published' AND category_id=?");
|
||||
$totalStmt->execute([$category['id']]);
|
||||
$total = (int) $totalStmt->fetchColumn();
|
||||
$pag = paginate($total, $page, ITEMS_PER_PAGE);
|
||||
|
||||
$stmt = db()->prepare(
|
||||
"SELECT a.*, c.name as category_name, c.slug as category_slug
|
||||
FROM articles a LEFT JOIN categories c ON a.category_id = c.id
|
||||
WHERE a.status='published' AND a.category_id=?
|
||||
ORDER BY a.published_at DESC LIMIT ? OFFSET ?"
|
||||
);
|
||||
$stmt->execute([$category['id'], $pag['limit'], $pag['offset']]);
|
||||
$articles = $stmt->fetchAll();
|
||||
|
||||
$pageTitle = $category['name'] . ' - ' . SITE_TITLE;
|
||||
$metaDescription = $category['description'];
|
||||
ob_start();
|
||||
include __DIR__ . '/templates/category.php';
|
||||
$content = ob_get_clean();
|
||||
break;
|
||||
|
||||
case 'archiv':
|
||||
$page = max(1, (int) ($_GET['page'] ?? 1));
|
||||
$total = (int) db()->query("SELECT COUNT(*) FROM articles WHERE status='published'")->fetchColumn();
|
||||
$pag = paginate($total, $page, ITEMS_PER_PAGE);
|
||||
|
||||
$stmt = db()->prepare(
|
||||
"SELECT a.*, c.name as category_name, c.slug as category_slug
|
||||
FROM articles a LEFT JOIN categories c ON a.category_id = c.id
|
||||
WHERE a.status='published' ORDER BY a.published_at DESC LIMIT ? OFFSET ?"
|
||||
);
|
||||
$stmt->execute([$pag['limit'], $pag['offset']]);
|
||||
$articles = $stmt->fetchAll();
|
||||
|
||||
$pageTitle = 'Archiv - ' . SITE_TITLE;
|
||||
ob_start();
|
||||
include __DIR__ . '/templates/archive.php';
|
||||
$content = ob_get_clean();
|
||||
break;
|
||||
|
||||
default:
|
||||
http_response_code(404);
|
||||
$pageTitle = 'Nicht gefunden';
|
||||
ob_start();
|
||||
include __DIR__ . '/templates/404.php';
|
||||
$content = ob_get_clean();
|
||||
}
|
||||
|
||||
include __DIR__ . '/templates/layout.php';
|
||||
Reference in New Issue
Block a user