Files
2026-10-16 19:12:15 +00:00

88 lines
2.7 KiB
PHP

<?php
require_once __DIR__ . '/includes/bootstrap.php';
$pdo = get_db();
$id = (int) ($_GET['id'] ?? 0);
$stmt = $pdo->prepare(
'SELECT a.*, tt.ticket_id, t.ticket_number, t.user_id, t.department_id
FROM ticket_attachments a
JOIN ticket_threads tt ON tt.id = a.thread_id
JOIN tickets t ON t.id = tt.ticket_id
WHERE a.id = ?'
);
$stmt->execute([$id]);
$att = $stmt->fetch();
if (!$att) {
http_response_code(404);
die('Datei nicht gefunden.');
}
$user = current_user();
$staff = current_staff();
$allowed = ($staff !== null && staff_can_access_department($staff, (int) $att['department_id']))
|| ($user && $att['user_id'] == $user['id'])
|| !empty($_SESSION['guest_ticket_access'][$att['ticket_number']]);
if (!$allowed) {
http_response_code(403);
die('Kein Zugriff auf diese Datei.');
}
$uploadsDir = realpath(rtrim(config()['uploads']['path'], '/'));
$path = $uploadsDir . '/' . basename($att['stored_name']); // basename verhindert Path-Traversal
// Sicherstellen dass Datei im Upload-Verzeichnis liegt
if (!$uploadsDir || strpos(realpath($path) ?: '', $uploadsDir) !== 0) {
http_response_code(403);
die('Ungültiger Dateipfad.');
}
if (!is_file($path)) {
http_response_code(404);
die('Datei nicht gefunden.');
}
$safeName = preg_replace('/[^a-zA-Z0-9._\-]/', '_', basename($att['original_name']));
$ext = strtolower(pathinfo($att['original_name'], PATHINFO_EXTENSION));
$preview = !empty($_GET['preview']);
// Inline-fähige Typen für Vorschau
$inlineMime = [
'jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg',
'png' => 'image/png', 'gif' => 'image/gif',
'webp' => 'image/webp', 'svg' => 'image/svg+xml',
'pdf' => 'application/pdf',
];
if ($preview && isset($inlineMime[$ext])) {
// Vorschau: Datei inline im Browser anzeigen
$mime = $inlineMime[$ext];
// SVG extra absichern
if ($ext === 'svg') {
header("Content-Security-Policy: default-src 'none'; style-src 'unsafe-inline'");
} else {
header("Content-Security-Policy: default-src 'none'");
}
header('Content-Type: ' . $mime);
header('X-Content-Type-Options: nosniff');
header('Content-Disposition: inline; filename="' . $safeName . '"');
header('Content-Length: ' . filesize($path));
header('Cache-Control: private, max-age=3600');
readfile($path);
exit;
}
// Standard: Datei herunterladen
header('Content-Type: application/octet-stream');
header('X-Content-Type-Options: nosniff');
header('Content-Disposition: attachment; filename="' . $safeName . '"');
header('Content-Length: ' . filesize($path));
header('Cache-Control: private, no-store, no-cache');
header("Content-Security-Policy: default-src 'none'");
header('X-Frame-Options: DENY');
readfile($path);
exit;