. */ public static function acceptAttribute(): string { $parts = []; foreach (self::ALLOWED_EXTENSIONS as $ext) { $parts[] = '.' . $ext; } return implode(',', $parts); } /** * Deterministische, sichere MIME-Zuordnung je erlaubter Extension. Wird * sowohl beim Speichern als auch beim Ausliefern genutzt — der vom Client * gemeldete MIME-Typ wird bewusst NIE verwendet (sonst Stored-XSS, z. B. * als Bild getarntes SVG mit Skript). Nicht zuordenbare Endungen landen bei * application/octet-stream (Download statt Inline-Render). * * @var array */ public const EXTENSION_MIME_MAP = [ 'pdf' => 'application/pdf', 'png' => 'image/png', 'jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg', 'webp' => 'image/webp', 'doc' => 'application/msword', 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'xls' => 'application/vnd.ms-excel', 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'ppt' => 'application/vnd.ms-powerpoint', 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', ]; /** * MIME-Typen, die gefahrlos inline im Browser angezeigt werden dürfen. * Bewusst ohne image/svg+xml, text/*, application/xml o. Ä. * * @var string[] */ public const INLINE_SAFE_MIMES = [ 'image/png', 'image/jpeg', 'image/webp', 'application/pdf', ]; public static function mimeForFilename(string $filename): string { $dot = strrpos($filename, '.'); if ($dot !== false) { $ext = strtolower(substr($filename, $dot + 1)); if (isset(self::EXTENSION_MIME_MAP[$ext])) { return self::EXTENSION_MIME_MAP[$ext]; } } return 'application/octet-stream'; } public static function isInlineSafeMime(string $mime): bool { return in_array($mime, self::INLINE_SAFE_MIMES, true); } public static function isExtensionAllowed(string $filename): bool { $dot = strrpos($filename, '.'); if ($dot === false) { return false; } $ext = strtolower(substr($filename, $dot + 1)); return in_array($ext, self::ALLOWED_EXTENSIONS, true); } public static function isMimeAllowedIfDetected(?string $mime): bool { if ($mime === null || $mime === '') { return true; } foreach (self::ALLOWED_MIME_PREFIXES as $prefix) { if (strpos($mime, $prefix) === 0) { return true; } } return false; } public static function formatBytes(int $bytes): string { if ($bytes < 1024) { return $bytes . ' B'; } if ($bytes < 1024 * 1024) { return number_format($bytes / 1024, 1, ',', '.') . ' KB'; } return number_format($bytes / (1024 * 1024), 1, ',', '.') . ' MB'; } }