#!/usr/bin/env php ['source' => 0, 'migrated' => 0], 'users' => ['source' => 0, 'migrated' => 0], 'operations' => ['source' => 0, 'migrated' => 0], 'ope_sectors' => ['source' => 0, 'migrated' => 0], 'sectors_adresses' => ['source' => 0, 'migrated' => 0], 'ope_users' => ['source' => 0, 'migrated' => 0], 'ope_users_sectors' => ['source' => 0, 'migrated' => 0], 'ope_pass' => ['source' => 0, 'migrated' => 0], 'ope_pass_histo' => ['source' => 0, 'migrated' => 0], 'medias' => ['source' => 0, 'migrated' => 0], ]; // Fonctions utilitaires function println($message, $color = C_RESET) { echo $color . $message . C_RESET . "\n"; } function printBox($title, $color = C_BLUE) { $width = 70; $titleLen = strlen($title); $padding = ($width - $titleLen - 2) / 2; println(str_repeat("═", $width), $color); println(str_repeat(" ", floor($padding)) . $title . str_repeat(" ", ceil($padding)), $color); println(str_repeat("═", $width), $color); } function printStep($step, $substep = null) { if ($substep) { println(" ├─ " . $substep, C_CYAN); } else { println("\n" . C_BOLD . "▶ " . $step . C_RESET); } } function printStat($label, $source, $migrated, $indent = " ") { $status = ($source === $migrated) ? C_GREEN . "✓" : C_YELLOW . "⚠"; println($indent . "📊 {$label}: {$source} source → {$migrated} migré(s) {$status}" . C_RESET); } function connectDatabases($sourceDbName, $targetDbName) { global $sourceDb, $targetDb; printStep("Connexion aux bases de données"); try { // Base source $dsn = sprintf('mysql:host=%s;port=%d;dbname=%s;charset=utf8mb4', DB_HOST, DB_PORT, $sourceDbName); $sourceDb = new PDO($dsn, DB_USER_ROOT, DB_PASS_ROOT, [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ]); printStep("Source connectée: {$sourceDbName}", true); // Base cible $dsn = sprintf('mysql:host=%s;port=%d;dbname=%s;charset=utf8mb4', DB_HOST, DB_PORT, $targetDbName); $targetDb = new PDO($dsn, DB_USER, DB_PASS, [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ]); printStep("Cible connectée: {$targetDbName}", true); return true; } catch (PDOException $e) { println("✗ Erreur connexion: " . $e->getMessage(), C_RED); return false; } } function getEntityInfo($entityId) { global $sourceDb; $stmt = $sourceDb->prepare(" SELECT rowid, libelle, cp, ville FROM users_entites WHERE rowid = ? "); $stmt->execute([$entityId]); return $stmt->fetch(); } function migrateReferenceTable($tableName) { global $sourceDb, $targetDb; printStep("Migration table: {$tableName}"); // Compter source $count = $sourceDb->query("SELECT COUNT(*) FROM {$tableName}")->fetchColumn(); printStep("Source: {$count} enregistrements", true); if ($count === 0) { printStep("Aucune donnée à migrer", true); return 0; } // Récupérer les données $rows = $sourceDb->query("SELECT * FROM {$tableName}")->fetchAll(); // Préparer l'insertion $columns = array_keys($rows[0]); $placeholders = array_map(fn($col) => ":{$col}", $columns); $sql = sprintf( "INSERT INTO %s (%s) VALUES (%s) ON DUPLICATE KEY UPDATE %s", $tableName, implode(', ', $columns), implode(', ', $placeholders), implode(', ', array_map(fn($col) => "{$col} = VALUES({$col})", $columns)) ); $stmt = $targetDb->prepare($sql); $success = 0; foreach ($rows as $row) { try { $stmt->execute($row); $success++; } catch (PDOException $e) { // Ignorer erreurs } } printStep("Migré: {$success}/{$count}", true); return $success; } function migrateEntite($entityId) { global $sourceDb, $targetDb, $stats; printStep("ÉTAPE 1: Migration de l'entité #{$entityId}"); // Récupérer l'entité source $stmt = $sourceDb->prepare(" SELECT * FROM users_entites WHERE rowid = ? "); $stmt->execute([$entityId]); $entity = $stmt->fetch(); if (!$entity) { println(" ✗ Entité introuvable", C_RED); return false; } $stats['entites']['source'] = 1; println(" 📋 Entité: " . $entity['libelle']); println(" 📍 Code postal: " . ($entity['cp'] ?? 'N/A')); println(" 🏙️ Ville: " . ($entity['ville'] ?? 'N/A')); // Chiffrer les données $encryptedName = ApiService::encryptSearchableData($entity['libelle']); $encryptedEmail = !empty($entity['email']) ? ApiService::encryptSearchableData($entity['email']) : ''; $encryptedPhone = !empty($entity['phone']) ? ApiService::encryptData($entity['phone']) : ''; $encryptedMobile = !empty($entity['mobile']) ? ApiService::encryptData($entity['mobile']) : ''; // Insérer dans la cible $sql = "INSERT INTO entites ( id, encrypted_name, code_postal, ville, encrypted_email, encrypted_phone, encrypted_mobile, fk_region, fk_type, chk_active, created_at, updated_at ) VALUES ( :id, :name, :cp, :ville, :email, :phone, :mobile, :region, :type, :active, :created, :updated ) ON DUPLICATE KEY UPDATE encrypted_name = VALUES(encrypted_name), code_postal = VALUES(code_postal), ville = VALUES(ville)"; $stmt = $targetDb->prepare($sql); $stmt->execute([ 'id' => $entity['rowid'], 'name' => $encryptedName, 'cp' => $entity['cp'] ?? '', 'ville' => $entity['ville'] ?? '', 'email' => $encryptedEmail, 'phone' => $encryptedPhone, 'mobile' => $encryptedMobile, 'region' => $entity['fk_region'] ?? 1, 'type' => $entity['fk_type'] ?? 1, 'active' => $entity['active'] ?? 1, 'created' => $entity['date_creat'], 'updated' => $entity['date_modif'] ]); $stats['entites']['migrated'] = 1; printStat("Entité", 1, 1); return true; } function migrateUsers($entityId) { global $sourceDb, $targetDb, $stats; printStep("ÉTAPE 2: Migration des utilisateurs"); // Compter source $count = $sourceDb->prepare("SELECT COUNT(*) FROM users WHERE fk_entite = ? AND active = 1"); $count->execute([$entityId]); $sourceCount = $count->fetchColumn(); $stats['users']['source'] = $sourceCount; println(" 📊 Source: {$sourceCount} utilisateurs actifs"); if ($sourceCount === 0) { println(" ⚠️ Aucun utilisateur à migrer", C_YELLOW); return 0; } // Récupérer les users $stmt = $sourceDb->prepare(" SELECT * FROM users WHERE fk_entite = ? AND active = 1 "); $stmt->execute([$entityId]); $users = $stmt->fetchAll(); $success = 0; foreach ($users as $user) { try { $encryptedName = ApiService::encryptSearchableData($user['nom']); $encryptedUsername = !empty($user['username']) ? ApiService::encryptSearchableData($user['username']) : ''; $encryptedEmail = !empty($user['email']) ? ApiService::encryptSearchableData($user['email']) : ''; $encryptedPhone = !empty($user['telephone']) ? ApiService::encryptData($user['telephone']) : ''; $encryptedMobile = !empty($user['mobile']) ? ApiService::encryptData($user['mobile']) : ''; $sql = "INSERT INTO users ( id, fk_entite, fk_role, encrypted_name, first_name, encrypted_user_name, user_pass_hash, encrypted_email, encrypted_phone, encrypted_mobile, chk_active, created_at, updated_at ) VALUES ( :id, :entity, :role, :name, :firstname, :username, :pass, :email, :phone, :mobile, :active, :created, :updated ) ON DUPLICATE KEY UPDATE encrypted_name = VALUES(encrypted_name), encrypted_email = VALUES(encrypted_email)"; $stmt = $targetDb->prepare($sql); $stmt->execute([ 'id' => $user['rowid'], 'entity' => $entityId, 'role' => $user['fk_role'] ?? 1, 'name' => $encryptedName, 'firstname' => $user['prenom'] ?? '', 'username' => $encryptedUsername, 'pass' => $user['password'] ?? '', 'email' => $encryptedEmail, 'phone' => $encryptedPhone, 'mobile' => $encryptedMobile, 'active' => 1, 'created' => $user['date_creat'], 'updated' => $user['date_modif'] ]); $success++; } catch (PDOException $e) { // Ignorer } } $stats['users']['migrated'] = $success; printStat("Utilisateurs", $sourceCount, $success); return $success; } function migrateOperations($entityId, $limit = 3) { global $sourceDb, $targetDb, $stats; printStep("ÉTAPE 3: Migration des opérations (limite: {$limit})"); // Compter toutes les opérations $count = $sourceDb->prepare("SELECT COUNT(*) FROM operations WHERE fk_entite = ? AND active = 1"); $count->execute([$entityId]); $totalCount = $count->fetchColumn(); println(" 📊 Total disponible: {$totalCount} opérations"); println(" 🎯 Limitation: {$limit} dernières opérations"); $stats['operations']['source'] = min($limit, $totalCount); // Récupérer les N dernières opérations $stmt = $sourceDb->prepare(" SELECT * FROM operations WHERE fk_entite = ? AND active = 1 ORDER BY date_creat DESC LIMIT ? "); $stmt->execute([$entityId, $limit]); $operations = $stmt->fetchAll(); if (empty($operations)) { println(" ⚠️ Aucune opération à migrer", C_YELLOW); return []; } $migratedOps = []; foreach ($operations as $op) { try { $sql = "INSERT INTO operations ( id, fk_entite, libelle, date_deb, date_fin, chk_distinct_sectors, chk_active, created_at, updated_at ) VALUES ( :id, :entity, :libelle, :datedeb, :datefin, :distinct, :active, :created, :updated ) ON DUPLICATE KEY UPDATE libelle = VALUES(libelle)"; $stmt = $targetDb->prepare($sql); $stmt->execute([ 'id' => $op['rowid'], 'entity' => $entityId, 'libelle' => $op['libelle'], 'datedeb' => $op['date_deb'], 'datefin' => $op['date_fin'], 'distinct' => $op['chk_distinct_sectors'] ?? 0, 'active' => 1, 'created' => $op['date_creat'], 'updated' => $op['date_modif'] ]); $migratedOps[] = $op['rowid']; $stats['operations']['migrated']++; println(" ├─ Opération #{$op['rowid']}: " . $op['libelle'], C_GREEN); } catch (PDOException $e) { println(" ├─ ✗ Erreur opération #{$op['rowid']}: " . $e->getMessage(), C_RED); } } printStat("Opérations", count($operations), count($migratedOps)); return $migratedOps; } function migrateOperationDetails($operationId, $entityId) { global $sourceDb, $targetDb, $stats; println("\n " . C_BOLD . "┌─ Détails opération #{$operationId}" . C_RESET); // 1. Compter les passages $passCount = $sourceDb->prepare("SELECT COUNT(*) FROM ope_pass WHERE fk_operation = ?"); $passCount->execute([$operationId]); $nbPassages = $passCount->fetchColumn(); println(" │ 📊 Passages disponibles: {$nbPassages}"); // 2. Compter les ope_users $opeUsersCount = $sourceDb->prepare("SELECT COUNT(*) FROM ope_users WHERE fk_operation = ?"); $opeUsersCount->execute([$operationId]); $nbOpeUsers = $opeUsersCount->fetchColumn(); $stats['ope_users']['source'] += $nbOpeUsers; println(" │ 👥 Associations users: {$nbOpeUsers}"); // 3. Compter les secteurs (via ope_users_sectors) $sectorsCount = $sourceDb->prepare(" SELECT COUNT(DISTINCT ous.fk_sector) FROM ope_users_sectors ous WHERE ous.fk_operation = ? "); $sectorsCount->execute([$operationId]); $nbSectors = $sectorsCount->fetchColumn(); println(" │ 🗺️ Secteurs distincts: {$nbSectors}"); println(" └─ " . C_CYAN . "Migration des données associées..." . C_RESET); // Migration ope_users (simplifié pour l'exemple) // ... (code de migration réel ici) $stats['ope_pass']['source'] += $nbPassages; } // === MAIN === function parseArguments($argv) { $args = [ 'source-db' => null, 'target-db' => 'pra_geo', 'entity-id' => null, 'limit-operations' => 3, 'help' => false ]; foreach ($argv as $arg) { if (strpos($arg, '--') === 0) { $parts = explode('=', substr($arg, 2), 2); $key = $parts[0]; $value = $parts[1] ?? true; if (array_key_exists($key, $args)) { $args[$key] = $value; } } } return $args; } // Vérifier CLI if (php_sapi_name() !== 'cli') { die("Ce script doit être exécuté en ligne de commande.\n"); } $args = parseArguments($argv); if ($args['help'] || !$args['source-db'] || !$args['entity-id']) { echo << $data) { if ($data['source'] > 0 || $data['migrated'] > 0) { printStat(ucfirst($table), $data['source'], $data['migrated'], " "); } } println("\n✅ Migration terminée avec succès!", C_GREEN); exit(0);