false, 'error' => 'Méthode non autorisée']); exit; } $data = json_decode(file_get_contents('php://input'), true); $identifiant = isset($data['identifiant']) ? trim((string) $data['identifiant']) : ''; $motdepasse = isset($data['motdepasse']) ? (string) $data['motdepasse'] : ''; if ($identifiant === '' || $motdepasse === '') { http_response_code(400); echo json_encode(['success' => false, 'error' => 'Identifiant et mot de passe sont obligatoires.']); exit; } try { $pdoRouter = getRouterConnection(); } catch (PDOException $e) { http_response_code(500); echo json_encode(['success' => false, 'error' => 'Connexion à MIRADOR impossible']); exit; } // Comparaison directe sur l'email : la collation utf8mb4_0900_ai_ci déjà en // place sur MIRADOR (comme sur les autres bases ASPIC) est nativement // insensible à la casse et aux accents, pas besoin d'UPPER() ici. $stmt = $pdoRouter->prepare( 'SELECT MIR_Code, MIR_MDPHash, MIR_ServeurHost, MIR_ServeurPort, MIR_BaseNom FROM MIR_Users WHERE MIR_Email = ? AND MIR_Actif = 1' ); $stmt->execute([$identifiant]); $routage = $stmt->fetch(); // Hash factice comparé même quand l'email est inconnu (password_verify() // tourne alors quand même) : évite qu'une différence de temps de réponse // laisse deviner qu'une adresse n'existe pas dans MIRADOR. Valeur sans // signification, générée une fois pour toutes, jamais utilisée comme vrai // mot de passe. const HASH_FACTICE = '$2y$12$wni9cLq0BKttPzU0xAPM9uX/HMzu9UJhlOMj32H6/wLmkjlNfZ1cm'; $hashAVerifier = $routage['MIR_MDPHash'] ?? HASH_FACTICE; if (!$routage || !password_verify($motdepasse, $hashAVerifier)) { // Message volontairement générique : ne pas révéler si c'est l'identifiant // ou le mot de passe qui est en cause. Le compteur d'essais / la sortie au // 3e échec sont gérés côté front, pas ici (voir en-tête de ce fichier). echo json_encode(['success' => false]); exit; } // Coordonnées de la base de travail propre à cet utilisateur : posées en // session pour que getDbConnection() (db.php) route tous les prochains // appels de CETTE session vers la bonne base, sans qu'il faille les // repasser en paramètre à chaque endpoint. $_SESSION['USR_Code'] = $routage['MIR_Code']; $_SESSION['ASPIC_DB_HOST'] = $routage['MIR_ServeurHost']; $_SESSION['ASPIC_DB_PORT'] = (int) $routage['MIR_ServeurPort']; $_SESSION['ASPIC_DB_NAME'] = $routage['MIR_BaseNom']; // Nom affiché : toujours porté par ASP_Users de la base cible (MIRADOR ne // connaît que l'email/code/mot de passe/routage, pas le nom complet). Un // échec de connexion à cette base cible est remonté explicitement — plutôt // que de laisser entrer un utilisateur dans une base injoignable, ce qui // ferait échouer silencieusement tous les écrans suivants. try { $pdoCible = getDbConnection(); } catch (PDOException $e) { session_unset(); http_response_code(500); echo json_encode(['success' => false, 'error' => 'Connexion à la base de travail impossible']); exit; } // USR_Prenom récupéré ici en même temps que USR_Nom (7 septembre 2026, nuit) // et posé en session : sert désormais de "nom affiché" pour les réalisations // créées par cet utilisateur (voir REA_NomAffiche, realisations.php) sans // jamais toucher à USR_Code lui-même — Jean-Marc a explicitement écarté un // renommage de USR_Code (trop structurant) et une jointure ASP_Users refaite // à chaque affichage/écriture (source de complication inutile, et // potentiellement impossible si utilisateurs et agents IA finissent un jour // dans des bases séparées) : un seul aller-retour ici, à la connexion, // suffit pour tout le reste de la session. $stmtNom = $pdoCible->prepare('SELECT USR_Nom, USR_Prenom FROM ASP_Users WHERE USR_Code = ?'); $stmtNom->execute([$routage['MIR_Code']]); $ligneUsr = $stmtNom->fetch(); $nom = $ligneUsr['USR_Nom'] ?? null; $prenom = $ligneUsr['USR_Prenom'] ?? null; $_SESSION['USR_Prenom'] = $prenom; echo json_encode([ 'success' => true, 'user' => [ 'USR_Code' => $routage['MIR_Code'], 'USR_Nom' => $nom, 'USR_Prenom' => $prenom, ], ]);