#!/usr/bin/env php */ require_once __DIR__ . '/../lib/CryptoService.php'; require_once __DIR__ . '/../lib/DatabaseConnection.php'; require_once __DIR__ . '/../lib/helpers.php'; // Vérifier les arguments if ($argc < 3) { error("Usage: " . basename($argv[0]) . " "); error("Exemple: " . basename($argv[0]) . " dva dupont"); error(" " . basename($argv[0]) . " dva secteur_a"); error(" " . basename($argv[0]) . " dva j.dupont"); exit(1); } $environment = strtoupper($argv[1]); $searchString = strtolower(trim($argv[2])); if (strlen($searchString) < 2) { error("La recherche doit contenir au moins 2 caractères"); exit(1); } try { // Ouvrir le tunnel SSH si nécessaire $tunnelScript = __DIR__ . '/_ssh-tunnel.sh'; exec("$tunnelScript open $environment 2>&1", $output, $exitCode); if ($exitCode !== 0) { error("Impossible d'ouvrir le tunnel SSH"); exit(1); } // Connexion à la base de données $db = new DatabaseConnection($environment); $pdo = $db->connect(); info("Environnement: $environment"); info("Recherche de: '$searchString'"); info("Champs: username, nom, prénom, secteur\n"); // Récupérer les utilisateurs avec sect_name (en clair) et first_name (en clair) // On peut filtrer directement sur ces deux champs $stmt = $pdo->prepare(" SELECT u.id, u.encrypted_user_name, u.encrypted_email, u.encrypted_name, u.first_name, u.sect_name, u.fk_role, u.fk_entite, r.libelle as role_name, e.encrypted_name as entite_encrypted_name FROM users u LEFT JOIN x_users_roles r ON u.fk_role = r.id LEFT JOIN entites e ON u.fk_entite = e.id WHERE LOWER(u.first_name) LIKE :search1 OR LOWER(u.sect_name) LIKE :search2 ORDER BY u.id "); $searchPattern = '%' . $searchString . '%'; $stmt->execute([ 'search1' => $searchPattern, 'search2' => $searchPattern ]); $preFilteredUsers = $stmt->fetchAll(); // Récupérer TOUS les utilisateurs pour chercher dans les champs chiffrés $stmtAll = $pdo->query(" SELECT u.id, u.encrypted_user_name, u.encrypted_email, u.encrypted_name, u.first_name, u.sect_name, u.fk_role, u.fk_entite, r.libelle as role_name, e.encrypted_name as entite_encrypted_name FROM users u LEFT JOIN x_users_roles r ON u.fk_role = r.id LEFT JOIN entites e ON u.fk_entite = e.id ORDER BY u.id "); $allUsers = $stmtAll->fetchAll(); info("Analyse de " . count($allUsers) . " utilisateurs...\n"); // Déchiffrer et filtrer $config = DatabaseConfig::getInstance(); $crypto = new CryptoService($config->getEncryptionKey()); $matchedUsers = []; $seenIds = []; // Ajouter d'abord les résultats pré-filtrés (sect_name, first_name) foreach ($preFilteredUsers as $user) { $username = $crypto->decryptSearchable($user['encrypted_user_name']); $name = $crypto->decryptWithIV($user['encrypted_name']); // Vérifier aussi dans les champs chiffrés $matches = false; $matchedFields = []; if (stripos($user['first_name'], $searchString) !== false) { $matches = true; $matchedFields[] = 'prénom'; } if (stripos($user['sect_name'], $searchString) !== false) { $matches = true; $matchedFields[] = 'secteur'; } if ($username && stripos($username, $searchString) !== false) { $matches = true; $matchedFields[] = 'username'; } if ($name && stripos($name, $searchString) !== false) { $matches = true; $matchedFields[] = 'nom'; } if ($matches) { $matchedUsers[] = [ 'id' => $user['id'], 'username' => $username ?? '-', 'prenom' => $user['first_name'] ?? '-', 'nom' => $name ?? '-', 'secteur' => $user['sect_name'] ?? '-', 'role' => $user['role_name'] ?? '-', 'entite' => $crypto->decryptWithIV($user['entite_encrypted_name']) ?? '-', 'matched_in' => implode(', ', $matchedFields), ]; $seenIds[$user['id']] = true; } } // Chercher dans les utilisateurs restants (pour username et nom chiffrés) foreach ($allUsers as $user) { if (isset($seenIds[$user['id']])) { continue; // Déjà trouvé } $username = $crypto->decryptSearchable($user['encrypted_user_name']); $name = $crypto->decryptWithIV($user['encrypted_name']); $matches = false; $matchedFields = []; if ($username && stripos($username, $searchString) !== false) { $matches = true; $matchedFields[] = 'username'; } if ($name && stripos($name, $searchString) !== false) { $matches = true; $matchedFields[] = 'nom'; } if ($matches) { $matchedUsers[] = [ 'id' => $user['id'], 'username' => $username ?? '-', 'prenom' => $user['first_name'] ?? '-', 'nom' => $name ?? '-', 'secteur' => $user['sect_name'] ?? '-', 'role' => $user['role_name'] ?? '-', 'entite' => $crypto->decryptWithIV($user['entite_encrypted_name']) ?? '-', 'matched_in' => implode(', ', $matchedFields), ]; $seenIds[$user['id']] = true; } } if (empty($matchedUsers)) { warning("\nAucun utilisateur trouvé avec: '$searchString'"); exit(0); } // Affichage title("RÉSULTATS DE LA RCAHERCHE - " . count($matchedUsers) . " utilisateur(s) trouvé(s)"); // Préparer les données pour le tableau $tableData = []; foreach ($matchedUsers as $user) { $tableData[] = [ 'id' => $user['id'], 'username' => truncate($user['username'], 20), 'prenom' => truncate($user['prenom'], 15), 'nom' => truncate($user['nom'], 20), 'secteur' => truncate($user['secteur'], 15), 'role' => truncate($user['role'], 12), 'match' => $user['matched_in'], ]; } table( [ 'id' => 'ID', 'username' => 'Username', 'prenom' => 'Prénom', 'nom' => 'Nom', 'secteur' => 'Secteur', 'role' => 'Rôle', 'match' => 'Trouvé dans', ], $tableData, true ); success("Recherche terminée"); // Proposer d'afficher les détails complets if (count($matchedUsers) === 1) { echo "\n"; if (confirm("Afficher les détails complets de cet utilisateur ?")) { echo "\n"; $userId = $matchedUsers[0]['id']; $decryptUserScript = __DIR__ . '/decrypt-user'; passthru("$decryptUserScript $environment $userId"); } } elseif (count($matchedUsers) > 1 && count($matchedUsers) <= 10) { echo "\n"; if (confirm("Afficher les détails d'un utilisateur spécifique ?")) { echo color("\nEntrez l'ID de l'utilisateur: ", 'yellow'); $handle = fopen('php://stdin', 'r'); $userId = trim(fgets($handle)); fclose($handle); if (is_numeric($userId) && (int)$userId > 0) { echo "\n"; $decryptUserScript = __DIR__ . '/decrypt-user'; passthru("$decryptUserScript $environment $userId"); } } } } catch (Exception $e) { error("Erreur: " . $e->getMessage()); exit(1); }