cbzExists($filePath)) { throw new CbzFileNotFoundException($filePath); } $response = new BinaryFileResponse($filePath); $response->setContentDisposition( ResponseHeaderBag::DISPOSITION_ATTACHMENT, $filename ); $response->headers->set('Content-Type', 'application/x-cbz'); return $response; } public function createVolumeCbz(array $cbzPaths, string $volumeName): Response { $tempCbzPath = sys_get_temp_dir() . '/' . $volumeName . '.cbz'; $cbz = new \ZipArchive(); if ($cbz->open($tempCbzPath, \ZipArchive::CREATE) !== true) { throw new \RuntimeException('Cannot create CBZ file'); } $imageCounter = 1; foreach ($cbzPaths as $cbzPath) { if (!$this->cbzExists($cbzPath)) { continue; } $sourceCbz = new \ZipArchive(); if ($sourceCbz->open($cbzPath) !== true) { continue; // Skip if we can't open the CBZ } // Extract all images from the current CBZ for ($i = 0; $i < $sourceCbz->numFiles; $i++) { $fileName = $sourceCbz->getNameIndex($i); $fileInfo = $sourceCbz->statIndex($i); // Skip directories and non-image files if ($fileInfo['size'] === 0 || !$this->isImageFile($fileName)) { continue; } // Get the file content $imageContent = $sourceCbz->getFromIndex($i); if ($imageContent === false) { continue; } // Get file extension $extension = pathinfo($fileName, PATHINFO_EXTENSION); // Create a new filename with proper ordering $newFileName = sprintf('%04d.%s', $imageCounter, $extension); // Add the image to the volume CBZ $cbz->addFromString($newFileName, $imageContent); $imageCounter++; } $sourceCbz->close(); } $cbz->close(); $response = new BinaryFileResponse($tempCbzPath); $response->setContentDisposition( ResponseHeaderBag::DISPOSITION_ATTACHMENT, $volumeName . '.cbz' ); $response->headers->set('Content-Type', 'application/x-cbz'); // Clean up temp file after sending $response->deleteFileAfterSend(); return $response; } private function isImageFile(string $fileName): bool { $imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']; $extension = strtolower(pathinfo($fileName, PATHINFO_EXTENSION)); return in_array($extension, $imageExtensions); } public function deleteCbzFile(string $filePath): bool { if (!$this->cbzExists($filePath)) { return false; } return unlink($filePath); } public function cbzExists(string $filePath): bool { return file_exists($filePath) && is_readable($filePath); } }