88 lines
2.7 KiB
PHP
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;
|