exists($path)) { abort(404, 'File tidak ditemukan'); } // Dapatkan path fisik file $filePath = Storage::disk('public')->path($path); // Set tipe konten berdasarkan ekstensi file $contentType = $this->getContentType($filePath); // Pastikan file bisa dibaca if (!File::isReadable($filePath)) { abort(403, 'Tidak dapat membaca file'); } // Return file response dengan header yang tepat return response()->file($filePath, [ 'Content-Type' => $contentType, 'Cache-Control' => 'public, max-age=86400', 'Access-Control-Allow-Origin' => '*', 'X-Content-Type-Options' => 'nosniff' ]); } /** * Menampilkan file dari subdirektori tertentu * * @param string $directory * @param string $filename * @return BinaryFileResponse */ public function serveDirectoryFile($directory, $filename) { return $this->serveFile("$directory/$filename"); } /** * Mendapatkan tipe konten berdasarkan ekstensi file * * @param string $filePath * @return string */ private function getContentType($filePath) { $extension = pathinfo($filePath, PATHINFO_EXTENSION); $contentTypes = [ 'png' => 'image/png', 'jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg', 'gif' => 'image/gif', 'svg' => 'image/svg+xml', 'pdf' => 'application/pdf', 'doc' => 'application/msword', 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'xls' => 'application/vnd.ms-excel', 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'zip' => 'application/zip', 'mp4' => 'video/mp4', 'mp3' => 'audio/mpeg', ]; return $contentTypes[strtolower($extension)] ?? 'application/octet-stream'; } }