- Exécute la migration pour une table spécifique * * Options: * --truncate Vide la table cible avant la migration * --create-table Crée la table cible si elle n'existe pas * --help Affiche l'aide */ require_once dirname(__DIR__) . '/config.php'; // Définition des mappages de colonnes pour chaque table $tableMappings = [ 'x_devises' => [ 'source_to_target' => [ 'rowid' => 'id', 'active' => 'chk_active' ], 'primary_key' => 'rowid', // Clé primaire dans la table source 'target_primary_key' => 'id' // Clé primaire dans la table cible ], 'users' => [ 'source_to_target' => [ 'id' => 'id', 'user_pass_hash' => 'password_hash', 'encrypted_user_name' => 'encrypted_last_name', 'lang' => 'preferred_language', 'chk_active' => 'is_active' ], 'primary_key' => 'id', 'target_primary_key' => 'id', 'encrypted_fields' => [ 'email' => ['field' => 'encrypted_email', 'searchable' => true], 'user_name' => ['field' => 'encrypted_last_name', 'searchable' => false], 'phone' => ['field' => 'encrypted_phone', 'searchable' => false], 'mobile' => ['field' => 'encrypted_mobile', 'searchable' => false] ] ], // Ajoutez d'autres tables selon les besoins ]; // Fonction pour afficher l'aide function showHelp() { echo "Usage: php migrate.php [--truncate] [--create-table]\n"; echo "\nOptions disponibles:\n"; echo " --truncate Vide la table cible avant la migration\n"; echo " --create-table Crée la table cible si elle n'existe pas\n"; echo " --help Affiche cette aide\n"; echo "\nTables disponibles:\n"; global $tableMappings; foreach (array_keys($tableMappings) as $table) { echo " - $table\n"; } exit(0); } // Définition des scripts de migration disponibles dans l'ordre d'exécution $migrationScripts = [ 'x_devises' => __DIR__ . '/migrate_x_devises.php', 'x_entites_types' => __DIR__ . '/migrate_x_entites_types.php', 'x_types_passages' => __DIR__ . '/migrate_x_types_passages.php', 'x_types_reglements' => __DIR__ . '/migrate_x_types_reglements.php', 'x_users_roles' => __DIR__ . '/migrate_x_users_roles.php', 'x_pays' => __DIR__ . '/migrate_x_pays.php', 'x_regions' => __DIR__ . '/migrate_x_regions.php', 'x_departements' => __DIR__ . '/migrate_x_departements.php', 'x_villes' => __DIR__ . '/migrate_x_villes.php', 'entites' => __DIR__ . '/migrate_entites.php', 'users' => __DIR__ . '/migrate_users.php', 'operations' => __DIR__ . '/migrate_operations.php', 'ope_sectors' => __DIR__ . '/migrate_ope_sectors.php', 'sectors_adresses' => __DIR__ . '/migrate_sectors_adresses.php', 'ope_users' => __DIR__ . '/migrate_ope_users.php', 'ope_users_sectors' => __DIR__ . '/migrate_ope_users_sectors.php', 'ope_pass' => __DIR__ . '/migrate_ope_pass.php', 'ope_pass_histo' => __DIR__ . '/migrate_ope_pass_histo.php', 'medias' => __DIR__ . '/migrate_medias.php' // Ajoutez d'autres scripts de migration au fur et à mesure ]; // Fonction pour exécuter un script de migration spécifique function executeMigrationScript($scriptPath) { echo "\nExécution du script: " . basename($scriptPath) . "\n"; echo "------------------------------------------------\n"; // Exécuter le script PHP include $scriptPath; echo "\n"; return true; } // Traitement des arguments de ligne de commande $tableName = null; $truncateTable = false; $createTable = false; $runAllScripts = true; for ($i = 1; $i < $_SERVER['argc']; $i++) { $arg = $_SERVER['argv'][$i]; if ($arg === '--help') { showHelp(); } elseif ($arg === '--truncate') { $truncateTable = true; } elseif ($arg === '--create-table') { $createTable = true; } elseif (substr($arg, 0, 2) !== '--') { $tableName = $arg; $runAllScripts = false; } } // Si aucune table n'est spécifiée, exécuter tous les scripts de migration dans l'ordre if ($runAllScripts) { echo "\nDémarrage de la migration complète de la base de données\n"; echo "=======================================================\n"; $startTime = microtime(true); $successCount = 0; $failCount = 0; foreach ($migrationScripts as $table => $scriptPath) { if (file_exists($scriptPath)) { try { executeMigrationScript($scriptPath); $successCount++; } catch (Exception $e) { echo "\nErreur lors de la migration de la table $table: " . $e->getMessage() . "\n"; $failCount++; } } else { echo "\nScript de migration introuvable pour la table $table: $scriptPath\n"; $failCount++; } } $endTime = microtime(true); $executionTime = round($endTime - $startTime, 2); echo "\n=======================================================\n"; echo "Migration terminée en $executionTime secondes\n"; echo "Tables migrées avec succès: $successCount\n"; echo "Tables en échec: $failCount\n"; exit(0); } // Si une table spécifique est demandée, vérifier si un script dédié existe if (isset($migrationScripts[$tableName])) { $scriptPath = $migrationScripts[$tableName]; if (file_exists($scriptPath)) { executeMigrationScript($scriptPath); exit(0); } } // Sinon, utiliser la méthode générique de migration (code existant) if (!isset($tableMappings[$tableName])) { echo "Erreur: La table '$tableName' n'est pas configurée pour la migration.\n"; echo "Tables disponibles: " . implode(', ', array_keys($tableMappings)) . "\n"; exit(1); } // Création du dossier de logs si nécessaire if (!is_dir(dirname(__DIR__) . '/logs')) { mkdir(dirname(__DIR__) . '/logs', 0755, true); } logOperation("Démarrage de la migration de la table $tableName"); try { // Connexion aux bases de données $sourceDb = getSourceConnection(); $targetDb = getTargetConnection(); // Obtenir le service API pour le chiffrement si nécessaire $apiService = null; if (isset($tableMappings[$tableName]['encrypted_fields'])) { $container = $GLOBALS['container']; $apiService = $container->get('ApiService'); } // Récupération des données de la source $stmt = $sourceDb->query("SELECT * FROM $tableName"); $records = $stmt->fetchAll(); logOperation("Nombre d'enregistrements à migrer: " . count($records)); // Vérifier si la table existe dans la cible try { $targetDb->query("SELECT 1 FROM $tableName LIMIT 1"); $tableExists = true; } catch (PDOException $e) { $tableExists = false; } // Créer la table si elle n'existe pas et si l'option est activée if (!$tableExists && $createTable) { logOperation("La table $tableName n'existe pas dans la base cible. Création de la table..."); // Récupérer la structure de la table source $stmt = $sourceDb->query("SHOW CREATE TABLE $tableName"); $tableStructure = $stmt->fetch(PDO::FETCH_ASSOC); if (isset($tableStructure['Create Table'])) { $createTableSql = $tableStructure['Create Table']; // Adapter les noms de colonnes selon le mapping $mapping = $tableMappings[$tableName]['source_to_target']; foreach ($mapping as $sourceCol => $targetCol) { $createTableSql = str_replace("`$sourceCol`", "`$targetCol`", $createTableSql); } // Remplacer le nom de la clé primaire si nécessaire $sourcePk = $tableMappings[$tableName]['primary_key']; $targetPk = $tableMappings[$tableName]['target_primary_key']; if ($sourcePk !== $targetPk) { $createTableSql = str_replace("PRIMARY KEY (`$sourcePk`)", "PRIMARY KEY (`$targetPk`)", $createTableSql); } // Créer la table $targetDb->exec($createTableSql); logOperation("Table $tableName créée avec succès"); } else { throw new Exception("Impossible de récupérer la structure de la table source"); } } // Vider la table cible si l'option est activée if ($truncateTable && $tableExists) { logOperation("Vidage de la table cible $tableName..."); $targetDb->exec("TRUNCATE TABLE $tableName"); } // Construire la requête d'insertion dynamiquement $mapping = $tableMappings[$tableName]['source_to_target']; // Récupérer les colonnes de la table cible $stmt = $targetDb->query("DESCRIBE $tableName"); $targetColumns = $stmt->fetchAll(PDO::FETCH_COLUMN); // Construire les listes de colonnes pour l'insertion $insertColumns = []; $insertPlaceholders = []; $updateClauses = []; foreach ($targetColumns as $column) { $insertColumns[] = "`$column`"; $insertPlaceholders[] = ":$column"; $updateClauses[] = "`$column` = VALUES(`$column`)"; } $insertColumnsSql = implode(", ", $insertColumns); $insertPlaceholdersSql = implode(", ", $insertPlaceholders); $updateClausesSql = implode(", ", $updateClauses); $insertQuery = "INSERT INTO $tableName ($insertColumnsSql) " . "VALUES ($insertPlaceholdersSql) " . "ON DUPLICATE KEY UPDATE $updateClausesSql"; $insertStmt = $targetDb->prepare($insertQuery); // Compteurs $successCount = 0; $errorCount = 0; // Traitement de chaque enregistrement foreach ($records as $record) { try { $data = []; // Mappage des colonnes selon la configuration foreach ($targetColumns as $targetCol) { // Trouver la colonne source correspondante $sourceCol = array_search($targetCol, $mapping); if ($sourceCol !== false) { // La colonne existe dans le mapping $data[$targetCol] = $record[$sourceCol]; } elseif (isset($record[$targetCol])) { // La colonne a le même nom dans les deux tables $data[$targetCol] = $record[$targetCol]; } else { // Colonne non trouvée, utiliser NULL ou une valeur par défaut $data[$targetCol] = null; } } // Traitement des champs chiffrés si nécessaire if (isset($tableMappings[$tableName]['encrypted_fields']) && $apiService) { foreach ($tableMappings[$tableName]['encrypted_fields'] as $sourceField => $config) { $targetField = $config['field']; $isSearchable = $config['searchable']; if (isset($record[$sourceField]) && !empty($record[$sourceField])) { // Vérifier si le champ est déjà chiffré if (isset($record["encrypted_$sourceField"])) { $data[$targetField] = $record["encrypted_$sourceField"]; } else { // Chiffrer la donnée selon qu'elle est recherchable ou non if ($isSearchable) { $data[$targetField] = $apiService->encryptSearchableData($record[$sourceField]); } else { $data[$targetField] = $apiService->encryptData($record[$sourceField]); } } } } } // Gestion spécifique pour certaines tables if ($tableName === 'users') { // Conversion de chk_active (0,1,2) vers is_active (booléen) if (isset($record['chk_active'])) { $data['is_active'] = ($record['chk_active'] > 0) ? 1 : 0; } } // Insertion dans la base cible $insertStmt->execute($data); $successCount++; // Identifiant pour le log $pkField = $tableMappings[$tableName]['primary_key']; $recordId = $record[$pkField] ?? 'inconnu'; logOperation("Enregistrement ID $recordId migré avec succès", "INFO"); } catch (Exception $e) { $errorCount++; $pkField = $tableMappings[$tableName]['primary_key']; $recordId = $record[$pkField] ?? 'inconnu'; logOperation("Erreur lors de la migration de l'enregistrement ID $recordId: " . $e->getMessage(), "ERROR"); } } logOperation("Migration terminée. Succès: $successCount, Erreurs: $errorCount"); // Fermer le tunnel SSH closeSshTunnel(); } catch (Exception $e) { logOperation("Erreur critique: " . $e->getMessage(), "ERROR"); // Fermer le tunnel SSH en cas d'erreur closeSshTunnel(); exit(1); }