upload v1

This commit is contained in:
2026-01-11 15:40:15 +00:00
parent 136a098425
commit 5d80bf4c40
57 changed files with 2430 additions and 0 deletions
+344
View File
@@ -0,0 +1,344 @@
<?php
// admin.php
declare(strict_types=1);
session_start();
require_once __DIR__ . '/functions.php';
$loggedIn = isset($_SESSION['admin']) && $_SESSION['admin'] === true;
// Login
if (isset($_POST['action']) && $_POST['action'] === 'login') {
if (($_POST['password'] ?? '') === ADMIN_PASSWORD_PLAIN) {
$_SESSION['admin'] = true;
header('Location: admin.php');
exit;
} else {
$error = 'Falsches Passwort.';
}
}
// Logout
if (isset($_GET['logout'])) {
$_SESSION = [];
session_destroy();
header('Location: admin.php');
exit;
}
if ($loggedIn) {
// CREATE/UPDATE
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['save_event'])) {
$events = load_events();
$id = $_POST['id'] ?: 'evt_' . bin2hex(random_bytes(6));
$title = sanitize_text($_POST['title'] ?? '');
$speaker = sanitize_text($_POST['speaker'] ?? '');
$date = sanitize_text($_POST['date'] ?? '');
$time = sanitize_text($_POST['time'] ?? '19:30');
$venue_name = sanitize_text($_POST['venue_name'] ?? '');
$venue_address = sanitize_text($_POST['venue_address'] ?? '');
$price = sanitize_text($_POST['price'] ?? '');
$doors_open = sanitize_text($_POST['doors_open'] ?? '');
$tickets_info = sanitize_text($_POST['tickets_info'] ?? '');
$catering = sanitize_text($_POST['catering'] ?? '');
$tags = sanitize_text($_POST['tags'] ?? '');
$description = trim($_POST['description'] ?? '');
$existing_image = sanitize_text($_POST['existing_image'] ?? '');
if ($title === '' || $date === '') {
$error = 'Titel und Datum sind Pflichtfelder.';
} else {
try {
$imagePath = $existing_image;
if (!empty($_FILES['image']['name'])) {
$imagePath = handle_image_upload($_FILES['image']);
}
$slug = make_slug($title, $date);
// Update falls vorhanden
$events = load_events();
$idx = null;
foreach ($events as $k => $ev) {
if ($ev['id'] === $id) { $idx = $k; break; }
}
$record = [
'id' => $id,
'title' => $title,
'speaker' => $speaker,
'date' => $date,
'time' => $time,
'venue_name' => $venue_name,
'venue_address' => $venue_address,
'price' => $price,
'doors_open' => $doors_open,
'tickets_info' => $tickets_info,
'catering' => $catering,
'tags' => $tags,
'description' => $description,
'image' => $imagePath,
'slug' => $slug,
'updated_at' => now_iso()
];
if ($idx !== null) {
$events[$idx] = $record;
} else {
$record['created_at'] = now_iso();
$events[] = $record;
}
save_events($events);
header('Location: admin.php?ok=1');
exit;
} catch (Throwable $e) {
$error = 'Fehler: ' . $e->getMessage();
}
}
}
// DELETE
if (isset($_GET['delete'])) {
$events = load_events();
$id = $_GET['delete'];
$events = array_values(array_filter($events, fn($e) => $e['id'] !== $id));
save_events($events);
header('Location: admin.php?deleted=1');
exit;
}
// EDIT load
$editEvent = null;
if (isset($_GET['edit'])) {
$id = $_GET['edit'];
foreach (load_events() as $e) {
if ($e['id'] === $id) { $editEvent = $e; break; }
}
}
}
?>
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Admin | <?= h(SITE_NAME) ?></title>
<meta name="robots" content="noindex,nofollow">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="/assets/styles.css">
<link rel="icon" href="/assets/logo.png" sizes="32x32" type="image/png">
</head>
<body>
<nav class="navbar navbar-expand-lg bg-body-tertiary border-bottom sticky-top">
<div class="container">
<a class="navbar-brand brand-logo" href="index.html">
<img src="/assets/logo.png" alt="Walschleber KulTour Logo" height="34" width="34">
<span><?= h(SITE_NAME) ?></span>
</a>
<div class="ms-auto">
<?php if ($loggedIn): ?>
<a class="btn btn-outline-secondary btn-sm" href="admin.php?logout=1">Logout</a>
<?php endif; ?>
</div>
</div>
</nav>
<?php if (!$loggedIn): ?>
<header class="py-5 bg-light border-bottom">
<div class="container">
<div class="akzent-line mb-3"></div>
<h1 class="display-6 mb-2">Admin-Login</h1>
</div>
</header>
<main class="container my-5">
<div class="row justify-content-center">
<div class="col-md-6 col-lg-5">
<div class="p-4 border rounded-3 bg-white">
<?php if (!empty($error)): ?><div class="alert alert-danger"><?= h($error) ?></div><?php endif; ?>
<form method="post" autocomplete="off">
<input type="hidden" name="action" value="login">
<div class="mb-3">
<label class="form-label">Passwort</label>
<input type="password" class="form-control form-control-lg" name="password" required>
</div>
<button class="btn btn-brand btn-lg w-100">Einloggen</button>
</form>
</div>
</div>
</div>
</main>
<?php else: ?>
<header class="py-5 bg-light border-bottom">
<div class="container">
<div class="akzent-line mb-3"></div>
<h1 class="display-6 mb-2">Vorträge verwalten</h1>
<p class="text-muted mb-0">Anlegen, bearbeiten, Bilder hochladen.</p>
</div>
</header>
<main class="container my-4">
<div class="d-flex align-items-center gap-2 mb-3">
<?php if (isset($_GET['ok'])): ?><span class="badge text-bg-success">Gespeichert</span><?php endif; ?>
<?php if (isset($_GET['deleted'])): ?><span class="badge text-bg-warning">Gelöscht</span><?php endif; ?>
</div>
<div class="row g-4">
<div class="col-lg-5">
<div class="card shadow-sm">
<div class="card-body">
<h2 class="h5 mb-3"><?= $editEvent ? 'Vortrag bearbeiten' : 'Neuen Vortrag anlegen' ?></h2>
<?php if (!empty($error)): ?><div class="alert alert-danger"><?= h($error) ?></div><?php endif; ?>
<form method="post" enctype="multipart/form-data">
<input type="hidden" name="id" value="<?= h($editEvent['id'] ?? '') ?>">
<div class="mb-3">
<label class="form-label">Titel*</label>
<input type="text" class="form-control" name="title" required value="<?= h($editEvent['title'] ?? '') ?>">
</div>
<div class="mb-3">
<label class="form-label">Referent/Autor</label>
<input type="text" class="form-control" name="speaker" value="<?= h($editEvent['speaker'] ?? '') ?>">
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label class="form-label">Datum*</label>
<input type="date" class="form-control" name="date" required value="<?= h($editEvent['date'] ?? '') ?>">
</div>
<div class="col-md-6 mb-3">
<label class="form-label">Uhrzeit</label>
<input type="time" class="form-control" name="time" value="<?= h($editEvent['time'] ?? '19:30') ?>">
</div>
</div>
<div class="mb-3">
<label class="form-label">Veranstaltungsort (Name)</label>
<input type="text" class="form-control" name="venue_name" value="<?= h($editEvent['venue_name'] ?? '') ?>">
</div>
<div class="mb-3">
<label class="form-label">Adresse (Straße, PLZ Ort)</label>
<input type="text" class="form-control" name="venue_address" value="<?= h($editEvent['venue_address'] ?? '') ?>">
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label class="form-label">Eintritt (z.B. 12 €)</label>
<input type="text" class="form-control" name="price" value="<?= h($editEvent['price'] ?? '') ?>">
</div>
<div class="col-md-6 mb-3">
<label class="form-label">Einlass (z.B. 18:30)</label>
<input type="text" class="form-control" name="doors_open" value="<?= h($editEvent['doors_open'] ?? '') ?>">
</div>
</div>
<div class="mb-3">
<label class="form-label">Ticket/VVK-Info</label>
<input type="text" class="form-control" name="tickets_info" value="<?= h($editEvent['tickets_info'] ?? '') ?>">
</div>
<div class="mb-3">
<label class="form-label">Verpflegung/Service</label>
<input type="text" class="form-control" name="catering" value="<?= h($editEvent['catering'] ?? '') ?>">
</div>
<div class="mb-3">
<label class="form-label">Tags (Kommagetrennt)</label>
<input type="text" class="form-control" name="tags" value="<?= h($editEvent['tags'] ?? '') ?>">
</div>
<div class="mb-3">
<label class="form-label">Beschreibung</label>
<textarea class="form-control" name="description" rows="6"><?= h($editEvent['description'] ?? '') ?></textarea>
</div>
<?php if (!empty($editEvent['image'])): ?>
<div class="mb-2">
<img src="<?= h($editEvent['image']) ?>" alt="aktuelles Bild" class="img-fluid rounded">
</div>
<input type="hidden" name="existing_image" value="<?= h($editEvent['image']) ?>">
<?php endif; ?>
<div class="mb-3">
<label class="form-label">Bild (JPG/PNG/WEBP)</label>
<input type="file" class="form-control" name="image" accept=".jpg,.jpeg,.png,.webp">
</div>
<button class="btn btn-brand" name="save_event" value="1">Speichern</button>
<?php if ($editEvent): ?>
<a href="admin.php" class="btn btn-outline-secondary ms-2">Abbrechen</a>
<?php endif; ?>
</form>
</div>
</div>
</div>
<div class="col-lg-7">
<div class="card shadow-sm">
<div class="card-body">
<h2 class="h5 mb-3">Alle Vorträge</h2>
<?php
$events = load_events();
usort($events, 'by_datetime_desc');
?>
<?php if (!$events): ?>
<p class="text-muted">Noch keine Einträge.</p>
<?php else: ?>
<div class="table-responsive">
<table class="table align-middle">
<thead>
<tr>
<th>Datum</th>
<th>Titel</th>
<th>Ort</th>
<th class="text-end"></th>
</tr>
</thead>
<tbody>
<?php foreach ($events as $e): ?>
<tr>
<td><?= h($e['date']) ?> <?= h($e['time']) ?></td>
<td>
<div class="fw-semibold"><?= h($e['title']) ?></div>
<div class="text-muted small"><?= h($e['speaker']) ?></div>
</td>
<td><?= h($e['venue_name']) ?></td>
<td class="text-end">
<a class="btn btn-sm btn-outline-primary" href="admin.php?edit=<?= h($e['id']) ?>">Bearbeiten</a>
<a class="btn btn-sm btn-outline-danger" href="admin.php?delete=<?= h($e['id']) ?>" onclick="return confirm('Wirklich löschen?')">Löschen</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</div>
</div>
<section class="my-4">
<div class="cta-band p-4 d-md-flex justify-content-between align-items-center rounded-4">
<div class="mb-3 mb-md-0">
<p class="section-kicker mb-1">Tipp</p>
<div class="h6 mb-0">Wenn „Ticket/VVK-Info“ eine URL enthält, zeigt die Programmseite automatisch den Button <em>„Tickets sichern“</em>.</div>
</div>
<a class="btn btn-accent" href="programm.php" target="_blank" rel="noopener">Programm ansehen</a>
</div>
</section>
</div>
</div>
</main>
<?php endif; ?>
<footer class="py-4 border-top mt-5">
<div class="container small d-flex gap-3 flex-wrap">
<span>&copy; <?= date('Y') ?> <?= h(SITE_NAME) ?></span>
<a href="impressum.html">Impressum</a>
<a href="datenschutz.html">Datenschutz</a>
</div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>