#!/usr/bin/env php $destination"); if (!$dryRun) { if (is_dir($source)) { // Pour un dossier, utiliser rename return rename($source, $destination); } else { // Pour un fichier return rename($source, $destination); } } return true; } // Fonction pour copier récursivement un dossier function copyDirectory(string $source, string $dest): bool { global $dryRun; if (!is_dir($source)) { return false; } if (!$dryRun) { if (!is_dir($dest)) { mkdir($dest, 0775, true); chown($dest, 'nginx'); chgrp($dest, 'nobody'); } } $dir = opendir($source); while (($file = readdir($dir)) !== false) { if ($file === '.' || $file === '..') { continue; } $srcPath = "$source/$file"; $destPath = "$dest/$file"; if (is_dir($srcPath)) { copyDirectory($srcPath, $destPath); } else { logMessage("Copie: $srcPath -> $destPath"); if (!$dryRun) { copy($srcPath, $destPath); chmod($destPath, 0664); chown($destPath, 'nginx'); chgrp($destPath, 'nobody'); } } } closedir($dir); return true; } // Fonction principale de migration function migrateUploads(): void { global $dryRun; logMessage("=== Début de la migration des uploads ==="); logMessage($dryRun ? "MODE DRY-RUN (simulation)" : "MODE RÉEL (modifications effectives)"); // 1. Migrer uploads/entites/* vers uploads/* $entitesPath = BASE_PATH . '/entites'; if (is_dir($entitesPath)) { logMessage("Traitement du dossier entites/"); $entites = scandir($entitesPath); foreach ($entites as $entiteId) { if ($entiteId === '.' || $entiteId === '..') continue; $oldPath = "$entitesPath/$entiteId"; $newPath = BASE_PATH . "/$entiteId"; if (!is_dir($oldPath)) continue; logMessage("Migration entité $entiteId"); // Si le dossier destination existe déjà, fusionner if (is_dir($newPath)) { logMessage("Le dossier $entiteId existe déjà à la racine, fusion nécessaire", 'INFO'); // Migrer les sous-dossiers $subDirs = scandir($oldPath); foreach ($subDirs as $subDir) { if ($subDir === '.' || $subDir === '..') continue; $oldSubPath = "$oldPath/$subDir"; $newSubPath = "$newPath/$subDir"; if ($subDir === 'operations') { // Traiter spécialement le dossier operations migrateOperations($oldSubPath, $newSubPath); } else { // Pour logo et recus, déplacer directement if (!is_dir($newSubPath)) { moveItem($oldSubPath, $newSubPath); } else { logMessage("Le dossier $newSubPath existe déjà, fusion du contenu"); copyDirectory($oldSubPath, $newSubPath); if (!$dryRun) { // Supprimer l'ancien après copie exec("rm -rf " . escapeshellarg($oldSubPath)); } } } } } else { // Déplacer simplement le dossier entier moveItem($oldPath, $newPath); } } // Supprimer le dossier entites vide if (!$dryRun) { if (count(scandir($entitesPath)) === 2) { // Seulement . et .. rmdir($entitesPath); logMessage("Suppression du dossier entites/ vide"); } } } // 2. Nettoyer la structure des dossiers operations logMessage("Nettoyage de la structure des dossiers operations"); cleanupOperationsStructure(); logMessage("=== Migration terminée ==="); if (!$dryRun) { logMessage("Logs sauvegardés dans: " . LOG_FILE); } } // Fonction pour migrer le dossier operations avec simplification function migrateOperations(string $oldPath, string $newPath): void { global $dryRun; if (!is_dir($oldPath)) return; logMessage("Migration du dossier operations: $oldPath"); if (!$dryRun && !is_dir($newPath)) { mkdir($newPath, 0775, true); chown($newPath, 'nginx'); chgrp($newPath, 'nobody'); } $operations = scandir($oldPath); foreach ($operations as $opId) { if ($opId === '.' || $opId === '..') continue; $oldOpPath = "$oldPath/$opId"; $newOpPath = "$newPath/$opId"; // Simplifier la structure: déplacer les xlsx directement dans operations/{id}/ if (is_dir("$oldOpPath/documents/exports/excel")) { $excelPath = "$oldOpPath/documents/exports/excel"; $files = scandir($excelPath); foreach ($files as $file) { if ($file === '.' || $file === '..' || !str_ends_with($file, '.xlsx')) continue; $oldFilePath = "$excelPath/$file"; $newFilePath = "$newOpPath/$file"; logMessage("Déplacement Excel: $oldFilePath -> $newFilePath"); if (!$dryRun) { if (!is_dir($newOpPath)) { mkdir($newOpPath, 0775, true); chown($newOpPath, 'nginx'); chgrp($newOpPath, 'nobody'); } rename($oldFilePath, $newFilePath); chmod($newFilePath, 0664); chown($newFilePath, 'nginx'); chgrp($newFilePath, 'nobody'); } } } } } // Fonction pour nettoyer la structure après migration function cleanupOperationsStructure(): void { global $dryRun; $uploadsDir = BASE_PATH; $entites = scandir($uploadsDir); foreach ($entites as $entiteId) { if ($entiteId === '.' || $entiteId === '..' || $entiteId === 'entites') continue; $operationsPath = "$uploadsDir/$entiteId/operations"; if (!is_dir($operationsPath)) continue; $operations = scandir($operationsPath); foreach ($operations as $opId) { if ($opId === '.' || $opId === '..') continue; $opPath = "$operationsPath/$opId"; // Supprimer l'ancienne structure documents/exports/excel si elle est vide $oldStructure = "$opPath/documents"; if (is_dir($oldStructure)) { logMessage("Suppression de l'ancienne structure: $oldStructure"); if (!$dryRun) { exec("rm -rf " . escapeshellarg($oldStructure)); } } } } } // Vérifier les permissions if (!is_dir(BASE_PATH)) { die("ERREUR: Le dossier " . BASE_PATH . " n'existe pas\n"); } if (!is_writable(BASE_PATH) && !$dryRun) { die("ERREUR: Le dossier " . BASE_PATH . " n'est pas accessible en écriture\n"); } // Lancer la migration try { migrateUploads(); if ($dryRun) { echo "\n"; echo "========================================\n"; echo "SIMULATION TERMINÉE\n"; echo "Pour exécuter réellement la migration:\n"; echo "php " . $argv[0] . "\n"; echo "========================================\n"; } else { echo "\n"; echo "========================================\n"; echo "MIGRATION TERMINÉE AVEC SUCCÈS\n"; echo "Vérifiez les logs: " . LOG_FILE . "\n"; echo "========================================\n"; } } catch (Exception $e) { logMessage("ERREUR FATALE: " . $e->getMessage(), 'ERROR'); exit(1); }