Files
dasposchi-de/admin/media.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

143 lines
5.1 KiB
PHP

<?php
require_once __DIR__ . '/../core/auth.php';
require_once __DIR__ . '/../core/upload.php';
auth_start_session();
auth_require_login();
// Bild hochladen
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
csrf_verify();
if (isset($_POST['delete_file'])) {
$file = $_POST['delete_file'];
// Sicherstellen, dass der Pfad im Upload-Verzeichnis liegt
$realUploadDir = realpath(UPLOAD_DIR);
$realFile = realpath(UPLOAD_DIR . $file);
if ($realFile && str_starts_with($realFile, $realUploadDir) && is_file($realFile)) {
unlink($realFile);
flash('success', 'Datei gelöscht.');
} else {
flash('error', 'Datei nicht gefunden.');
}
redirect('/admin/media.php');
}
if (!empty($_FILES['images'])) {
$files = $_FILES['images'];
$uploaded = 0;
$count = is_array($files['name']) ? count($files['name']) : 1;
for ($i = 0; $i < $count; $i++) {
$file = [
'name' => is_array($files['name']) ? $files['name'][$i] : $files['name'],
'type' => is_array($files['type']) ? $files['type'][$i] : $files['type'],
'tmp_name' => is_array($files['tmp_name']) ? $files['tmp_name'][$i] : $files['tmp_name'],
'error' => is_array($files['error']) ? $files['error'][$i] : $files['error'],
'size' => is_array($files['size']) ? $files['size'][$i] : $files['size'],
];
if ($file['error'] === UPLOAD_ERR_OK && handle_upload($file)) {
$uploaded++;
}
}
if ($uploaded > 0) {
flash('success', $uploaded . ' Datei(en) hochgeladen.');
} else {
flash('error', 'Upload fehlgeschlagen.');
}
redirect('/admin/media.php');
}
}
// Alle Bilder sammeln
function scan_uploads(string $dir, string $prefix = ''): array
{
$files = [];
if (!is_dir($dir)) return $files;
$items = scandir($dir);
foreach ($items as $item) {
if ($item === '.' || $item === '..' || $item === '.htaccess' || $item === '.gitkeep') continue;
$path = $dir . '/' . $item;
if (is_dir($path)) {
$files = array_merge($files, scan_uploads($path, $prefix . $item . '/'));
} elseif (preg_match('/\.(jpg|jpeg|png|gif|webp)$/i', $item)) {
$files[] = [
'path' => $prefix . $item,
'url' => UPLOAD_URL . $prefix . $item,
'size' => filesize($path),
'time' => filemtime($path),
];
}
}
return $files;
}
$images = scan_uploads(rtrim(UPLOAD_DIR, '/'));
usort($images, fn($a, $b) => $b['time'] - $a['time']);
$pageTitle = 'Medien';
$currentPage = 'media';
ob_start();
?>
<div class="card">
<h3>Bilder hochladen</h3>
<form method="post" enctype="multipart/form-data" class="upload-form">
<?= csrf_field() ?>
<div class="upload-zone" id="uploadZone">
<p>Bilder hierher ziehen oder klicken</p>
<input type="file" name="images[]" multiple accept="image/*" id="fileInput">
</div>
<button type="submit" class="btn btn-primary" style="margin-top:10px">Hochladen</button>
</form>
</div>
<div class="card">
<h3>Medienbibliothek (<?= count($images) ?>)</h3>
<?php if (empty($images)): ?>
<p class="empty-state">Noch keine Bilder vorhanden.</p>
<?php else: ?>
<div class="media-grid">
<?php foreach ($images as $img): ?>
<div class="media-item">
<img src="<?= e($img['url']) ?>" alt="" loading="lazy">
<div class="media-actions">
<button class="btn btn-sm" onclick="copyUrl('<?= e($img['url']) ?>')">URL kopieren</button>
<form method="post" class="inline-form" onsubmit="return confirm('Bild wirklich löschen?')">
<?= csrf_field() ?>
<input type="hidden" name="delete_file" value="<?= e($img['path']) ?>">
<button type="submit" class="btn btn-sm btn-danger">Löschen</button>
</form>
</div>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
<?php
$content = ob_get_clean();
$extraScripts = '
<script>
function copyUrl(url) {
var fullUrl = window.location.origin + url;
navigator.clipboard.writeText(fullUrl).then(function() {
alert("URL kopiert: " + fullUrl);
});
}
document.addEventListener("DOMContentLoaded", function() {
var zone = document.getElementById("uploadZone");
var input = document.getElementById("fileInput");
zone.addEventListener("click", function() { input.click(); });
zone.addEventListener("dragover", function(e) { e.preventDefault(); zone.classList.add("dragover"); });
zone.addEventListener("dragleave", function() { zone.classList.remove("dragover"); });
zone.addEventListener("drop", function(e) {
e.preventDefault(); zone.classList.remove("dragover");
input.files = e.dataTransfer.files;
});
});
</script>
';
include __DIR__ . '/templates/layout.php';