date('Y-m-d H:i:s'), 'stories' => [] ]; foreach ($selectedIds as $storyId) { $story = Stories::get($storyId); if (!$story) continue; // Créer un dossier pour ce roman $storyDir = $tempDir . '/' . $storyId; mkdir($storyDir); mkdir($storyDir . '/images'); // Copier l'image de couverture si elle existe if (!empty($story['cover'])) { $coverPath = __DIR__ . '/../../' . $story['cover']; if (file_exists($coverPath)) { copy($coverPath, $storyDir . '/cover' . pathinfo($coverPath, PATHINFO_EXTENSION)); $story['cover'] = 'cover' . pathinfo($coverPath, PATHINFO_EXTENSION); } } // Extraire et copier les images des chapitres foreach ($story['chapters'] as &$chapter) { if (!empty($chapter['content'])) { $content = $chapter['content']; if (is_string($content) && isJson($content)) { $content = json_decode($content, true); } // Traiter le contenu pour les images if (is_array($content) && isset($content['ops'])) { foreach ($content['ops'] as &$op) { if (is_array($op['insert']) && isset($op['insert']['image'])) { $imgUrl = $op['insert']['image']; $imgPath = __DIR__ . '/../../' . preg_replace('/^(?:\.\.\/)+/', '', $imgUrl); if (file_exists($imgPath)) { $newImgName = 'image_' . uniqid() . pathinfo($imgPath, PATHINFO_EXTENSION); copy($imgPath, $storyDir . '/images/' . $newImgName); $op['insert']['image'] = 'images/' . $newImgName; } } } $chapter['content'] = json_encode($content); } } } // Sauvegarder les données du roman file_put_contents($storyDir . '/story.json', json_encode($story, JSON_PRETTY_PRINT)); // Ajouter au manifeste $manifest['stories'][] = [ 'id' => $story['id'], 'title' => $story['title'] ]; } // Sauvegarder le manifeste file_put_contents($tempDir . '/manifest.json', json_encode($manifest, JSON_PRETTY_PRINT)); // Créer l'archive ZIP $zipFile = sys_get_temp_dir() . '/romans_' . date('Y-m-d_His') . '.zip'; $zip = new ZipArchive(); if ($zip->open($zipFile, ZipArchive::CREATE | ZipArchive::OVERWRITE) === true) { addDirToZip($zip, $tempDir, ''); $zip->close(); // Nettoyer le dossier temporaire deleteDir($tempDir); // Envoyer l'archive header('Content-Type: application/zip'); header('Content-Disposition: attachment; filename="' . basename($zipFile) . '"'); header('Content-Length: ' . filesize($zipFile)); readfile($zipFile); unlink($zipFile); } else { throw new Exception('Impossible de créer l\'archive ZIP'); } } catch (Exception $e) { if (isset($tempDir) && file_exists($tempDir)) { deleteDir($tempDir); } if (isset($zipFile) && file_exists($zipFile)) { unlink($zipFile); } http_response_code(500); echo 'Erreur lors de l\'export : ' . $e->getMessage(); } // Fonction pour vérifier si une chaîne est du JSON valide function isJson($string) { json_decode($string); return json_last_error() === JSON_ERROR_NONE; } // Fonction récursive pour ajouter un dossier à une archive ZIP function addDirToZip($zip, $dir, $relativePath) { $files = new RecursiveIteratorIterator( new RecursiveDirectoryIterator($dir), RecursiveIteratorIterator::LEAVES_ONLY ); foreach ($files as $file) { if (!$file->isDir()) { $filePath = $file->getRealPath(); $zipPath = $relativePath . substr($filePath, strlen($dir)); // Normaliser les séparateurs de chemin pour Windows $zipPath = str_replace('\\', '/', $zipPath); $zip->addFile($filePath, $zipPath); } } } // Fonction récursive pour supprimer un dossier et son contenu function deleteDir($dir) { if (!file_exists($dir)) return; $files = new RecursiveIteratorIterator( new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS), RecursiveIteratorIterator::CHILD_FIRST ); foreach ($files as $file) { if ($file->isDir()) { rmdir($file->getRealPath()); } else { unlink($file->getRealPath()); } } rmdir($dir); }