open($_FILES['importFile']['tmp_name']) !== true) { throw new Exception('Impossible d\'ouvrir l\'archive ZIP'); } $zip->extractTo($tempDir); $zip->close(); // Vérifier la présence du manifeste $manifestFile = $tempDir . '/manifest.json'; if (!file_exists($manifestFile)) { throw new Exception('Archive invalide : manifeste manquant'); } $manifest = json_decode(file_get_contents($manifestFile), true); if (!$manifest || !isset($manifest['stories'])) { throw new Exception('Manifeste invalide'); } $importedCount = 0; $skippedCount = 0; $errors = []; // Parcourir chaque roman dans le manifeste foreach ($manifest['stories'] as $storyInfo) { try { $storyId = $storyInfo['id']; $storyDir = $tempDir . '/' . $storyId; if (!file_exists($storyDir . '/story.json')) { throw new Exception("Fichier story.json manquant pour {$storyInfo['title']}"); } $story = json_decode(file_get_contents($storyDir . '/story.json'), true); if (!$story) { throw new Exception("Données JSON invalides pour {$storyInfo['title']}"); } // Vérifier si le roman existe déjà $existingStory = Stories::get($storyId); if ($existingStory && !$overwrite) { $skippedCount++; continue; } // Créer les dossiers nécessaires avec les permissions correctes $baseDir = __DIR__ . '/../../'; $coverDir = $baseDir . 'assets/images/covers'; $chaptersImgDir = $baseDir . 'assets/images/chapters/' . $storyId; $chaptersCoverDir = $baseDir . 'assets/images/chapters/' . $storyId . '/covers'; foreach ([$coverDir, $chaptersImgDir, $chaptersCoverDir] as $dir) { if (!file_exists($dir)) { if (!mkdir($dir, 0777, true)) { throw new Exception("Impossible de créer le dossier: $dir"); } chmod($dir, 0777); } } // Gérer l'image de couverture du roman if (!empty($story['cover'])) { $coverFile = $storyDir . '/' . $story['cover']; if (file_exists($coverFile)) { // Extraire l'extension correctement $originalName = basename($coverFile); if (preg_match('/\.([^.]+)$/', $originalName, $matches)) { $extension = $matches[1]; $newCoverPath = 'assets/images/covers/' . $storyId . '.' . $extension; $targetPath = $baseDir . $newCoverPath; if (!copy($coverFile, $targetPath)) { throw new Exception("Impossible de copier la couverture du roman"); } chmod($targetPath, 0777); $story['cover'] = $newCoverPath; } } } // Gérer les images des chapitres foreach ($story['chapters'] as &$chapter) { // Gérer les images de couverture des chapitres if (!empty($chapter['cover'])) { $chapterCoverFile = $storyDir . '/' . $chapter['cover']; if (file_exists($chapterCoverFile)) { // Extraire l'extension correctement $originalName = basename($chapterCoverFile); if (preg_match('/\.([^.]+)$/', $originalName, $matches)) { $extension = $matches[1]; $newChapterCoverName = $chapter['id'] . '-cover.' . $extension; $newChapterCoverPath = 'assets/images/chapters/' . $storyId . '/covers/' . $newChapterCoverName; $targetPath = $baseDir . $newChapterCoverPath; if (!copy($chapterCoverFile, $targetPath)) { throw new Exception("Impossible de copier la couverture du chapitre"); } chmod($targetPath, 0777); $chapter['cover'] = $newChapterCoverPath; } } } // Gérer le contenu et les images intégrées if (!empty($chapter['content'])) { $content = $chapter['content']; if (is_string($content) && isJson($content)) { $content = json_decode($content, true); } if (is_array($content) && isset($content['ops'])) { foreach ($content['ops'] as &$op) { if (is_array($op['insert']) && isset($op['insert']['image'])) { $imgPath = $storyDir . '/' . $op['insert']['image']; if (file_exists($imgPath)) { $originalName = basename($imgPath); if (preg_match('/\.([^.]+)$/', $originalName, $matches)) { $extension = $matches[1]; $newImgName = 'image_' . uniqid() . '.' . $extension; $targetPath = $chaptersImgDir . '/' . $newImgName; if (!copy($imgPath, $targetPath)) { throw new Exception("Impossible de copier l'image intégrée"); } chmod($targetPath, 0777); $op['insert']['image'] = 'assets/images/chapters/' . $storyId . '/' . $newImgName; } } } } $chapter['content'] = json_encode($content); } } } // Sauvegarder le roman if (!Stories::save($story)) { throw new Exception("Erreur lors de la sauvegarde de {$story['title']}"); } $importedCount++; } catch (Exception $e) { error_log("Erreur d'import pour {$storyInfo['title']}: " . $e->getMessage()); error_log("Trace complète: " . print_r($e->getTraceAsString(), true)); $errors[] = "Erreur pour {$storyInfo['title']}: " . $e->getMessage(); } } // Nettoyer deleteDir($tempDir); // Préparer le message de résultat $messages = []; if ($importedCount > 0) { $messages[] = "$importedCount roman(s) importé(s)"; } if ($skippedCount > 0) { $messages[] = "$skippedCount roman(s) ignoré(s) (déjà existants)"; } if (!empty($errors)) { $messages[] = "Erreurs : " . implode(", ", $errors); } $_SESSION['import_result'] = [ 'success' => implode(", ", $messages), 'error' => !empty($errors) ? implode("\n", $errors) : '' ]; header('Location: ../export-import.php'); exit; } catch (Exception $e) { error_log("Erreur générale d'import: " . $e->getMessage()); error_log("Trace complète: " . print_r($e->getTraceAsString(), true)); if (isset($tempDir) && file_exists($tempDir)) { deleteDir($tempDir); } $_SESSION['import_result'] = [ 'error' => 'Erreur lors de l\'import : ' . $e->getMessage() ]; header('Location: ../export-import.php'); exit; } // 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 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); }