storagePath . '/pages/' . $targetId; if (!is_dir($targetDir)) { mkdir($targetDir, 0755, true); } sort($localImagePaths); foreach ($localImagePaths as $index => $localPath) { $extension = pathinfo($localPath, PATHINFO_EXTENSION) ?: 'jpg'; $targetFile = sprintf('%s/%03d.%s', $targetDir, $index + 1, $extension); copy($localPath, $targetFile); } return $targetDir; } public function extractFromCbz(string $targetId, string $cbzBinary): string { $targetDir = $this->storagePath . '/pages/' . $targetId; if (!is_dir($targetDir)) { mkdir($targetDir, 0755, true); } $tmpFile = tempnam(sys_get_temp_dir(), 'cbz_'); file_put_contents($tmpFile, $cbzBinary); $zip = new ZipArchive(); if ($zip->open($tmpFile) !== true) { unlink($tmpFile); throw new \RuntimeException('Failed to open CBZ file as ZIP archive'); } $imageEntries = []; for ($i = 0; $i < $zip->numFiles; $i++) { $name = $zip->getNameIndex($i); if (preg_match('/\.(jpg|jpeg|png|webp|gif)$/i', $name)) { $imageEntries[] = ['index' => $i, 'name' => $name]; } } usort($imageEntries, fn ($a, $b) => strcmp($a['name'], $b['name'])); foreach ($imageEntries as $seq => $entry) { $extension = strtolower(pathinfo($entry['name'], PATHINFO_EXTENSION)) ?: 'jpg'; $targetFile = sprintf('%s/%03d.%s', $targetDir, $seq + 1, $extension); $content = $zip->getFromIndex($entry['index']); file_put_contents($targetFile, $content); } $zip->close(); unlink($tmpFile); return $targetDir; } public function countCbzImages(string $cbzBinary): int { $tmpFile = tempnam(sys_get_temp_dir(), 'cbz_'); file_put_contents($tmpFile, $cbzBinary); $zip = new ZipArchive(); if ($zip->open($tmpFile) !== true) { unlink($tmpFile); throw new \RuntimeException('Failed to open CBZ file as ZIP archive'); } $count = 0; for ($i = 0; $i < $zip->numFiles; $i++) { $name = $zip->getNameIndex($i); if (preg_match('/\.(jpg|jpeg|png|webp|gif)$/i', $name)) { $count++; } } $zip->close(); unlink($tmpFile); return $count; } }