diff --git a/Contestation/Demandereconnaissancefaciale.php b/Contestation/Demandereconnaissancefaciale.php
index a119db8..ea38fb1 100755
--- a/Contestation/Demandereconnaissancefaciale.php
+++ b/Contestation/Demandereconnaissancefaciale.php
@@ -573,7 +573,6 @@
function validateToken() {
$.ajax({
- // url: 'verify_facial_api.php',
url: '/Contestation/verify_facial_api.php',
method: 'POST',
contentType: 'application/json',
@@ -583,8 +582,6 @@
}),
dataType: 'json',
success: function(data) {
- // alert("succes => " + data);
- // console.log('Réponse JSON :', data);
if (data.success) {
showStep('step-instructions');
} else {
@@ -592,8 +589,7 @@
}
},
error: function(xhr, status, err) {
- //console.log("Demande :", xhr.responseText); // ✅ voir le HTML retourné
- showError('Demande : Erreur de connexion au serveur');
+ showError('Erreur de connexion au serveur');
// showError(xhr.responseText);
}
});
@@ -664,6 +660,7 @@
}
}
+ /*
function verifyPhoto() {
showStep('step-verifying');
@@ -690,7 +687,38 @@
showError('Erreur lors de la vérification: ' + error.message);
});
}
-
+ */
+
+ function verifyPhoto() {
+ showStep('step-verifying');
+ $.ajax({
+ url: 'verify_facial_api.php',
+ method: 'POST',
+ contentType: 'application/json',
+ data: JSON.stringify({
+ action: 'verify_face',
+ token: verificationToken,
+ image: capturedImage
+ }),
+ dataType: 'json',
+ success: function(data) {
+ alert(data);
+ console.log(data);
+ if (data.success && data.match) {
+ showSuccess(data);
+ } else {
+ showFailure(data);
+ }
+ },
+ error: function(xhr, status, error) {
+ showError('Erreur lors de la vérification: ' + error);
+ // showError(xhr.responseText);
+ console.log(error);
+ console.log(xhr.responseText);
+ }
+ });
+ }
+
function showSuccess(data) {
document.getElementById('result-icon').textContent = '✅';
document.getElementById('result-title').textContent = 'Identité vérifiée !';
diff --git a/Contestation/Demandereconnaissancefaciale_2026_02_23_08h.php b/Contestation/Demandereconnaissancefaciale_2026_02_23_08h.php
new file mode 100755
index 0000000..a119db8
--- /dev/null
+++ b/Contestation/Demandereconnaissancefaciale_2026_02_23_08h.php
@@ -0,0 +1,751 @@
+geUneBd($codeBdd);
+
+ /*
+ var_dump(
+ array(
+ // "bdd" => $bdd,
+ "codeSociete" => $codeSociete,
+ "codePrestataire" => $codePrestataire,
+ "idBeneficiaire" => $idBeneficiaire,
+ )
+
+ );
+ */
+
+ if(!$bdd) {
+ $message = $codeLangue == 'en_US' ? "Entity not found!" : "Entité introuvable!";
+ afficherMessage("$message");
+ }
+
+ $_SESSION['BdName'] = $bdd['BdName'];
+ $_SESSION['BdLogin'] = $bdd['BdLogin'];
+ $_SESSION['BdMdp'] = $bdd['BdMdp'];
+
+ if($assure->existeligne($codeSociete)) {
+ $fassureExiste = $assure->assureExiste($codeSociete, $idBeneficiaire);
+
+ if(!$fassureExiste) {
+ $message = $codeLangue == 'en_US' ? "Insured not found!" : "Assuré introuvable!";
+ afficherMessage("$message");
+ }
+
+ $demande = $assure->checkdemandereconnaissancefaciale_id();
+
+ if(!$demande) {
+ $message = $codeLangue == 'en_US' ? "No requests found!" : "Aucune demande trouvée!";
+ afficherMessage("$message");
+ }
+
+ $idDemande = $demande["idDemande"];
+ $codeEtat = $demande["codeEtat"];
+ $demandeExpiree = $demande["demandeExpiree"];
+ $dateExpirationFr = $demande["dateExpirationFr"];
+ $dateExpirationEng = $demande["dateExpirationEng"];
+ $etatDemande = $demande["etatDemande"];
+ $etatDemandeEng = $demande["etatDemandeEng"];
+
+ $beneficiaire = $demande["beneficiaire"];
+ $prestataire = $demande["prestataire"];
+
+ // var_dump($demande);
+ /*
+ idDemande
+ codePrestataire
+ idBeneficiaire
+ codeEtat
+ nbTentative
+ lienPhotoWebcam
+ dateExpiration
+ dateExpirationFr
+ dateExpirationEng
+ demandeExpiree
+ beneficiaire
+ prestataire
+ */
+
+ /*
+ var_dump(
+ array(
+ // "bdd" => $bdd,
+ "idDemande" => $idDemande,
+ "codeEtat" => $codeEtat,
+ "demandeExpiree" => $demandeExpiree,
+ "etatDemande" => $etatDemande,
+ "etatDemandeEng" => $etatDemandeEng,
+
+ "beneficiaire" => $beneficiaire,
+ "prestataire" => $prestataire,
+ )
+
+ );
+ */
+
+ /*
+ codeEtat libelle
+ 3 Expiré
+ 1 Vérifié
+ 2 Echec
+ 4 Erreur
+ 0 En attente
+ */
+
+ if($codeEtat=="3" || $demandeExpiree=="1") {
+ $message = $codeLangue == 'en_US' ? "Request expired since $dateExpirationEng !" : "Demande expirée depuis $dateExpirationFr !";
+ afficherMessage("$message");
+ }
+
+ if($codeEtat=="1") {
+ $message = $codeLangue == 'en_US' ? "Verification already completed!" : "Vérification déjà exffectuée!";
+ afficherMessage("$message");
+ }
+
+ if($codeEtat=="2") {
+ $message = $codeLangue == 'en_US' ? "Failure, please try again!" : "Echec, veuilez réessayer!";
+ afficherMessage("$message");
+ }
+
+ if($codeEtat=="4") {
+ $message = $codeLangue == 'en_US' ? "Error, please try again!" : "Erreur, veuilez réessayer!";
+ afficherMessage("$message");
+ }
+
+ /*
+ $message = $codeLangue == 'en_US'
+ ? "Parameters successfully verified!"
+ : "Paramètres vérifiés avec succès!";
+ afficherMessage("$message", false);
+ */
+
+ $param_societe = $assure->get_parametres_societe($codeSociete);
+
+ $_SESSION['dureeToken'] = $param_societe["dureeTokenReconnaissanceFaciale"];
+ $_SESSION['dossierPhoto'] = $param_societe["dossierPhoto"];
+ $_SESSION['nbTentative'] = $param_societe["nbTentativeBiometrie"];
+ }
+
+ function afficherMessage($message) {
+ echo "
+
+
+
+
+ Erreur
+
+
+
+
+
+
+
+
+
+
+
Erreur
+
{$message}
+
+
+
+ ";
+ exit();
+
+ // echo $message;
+ }
+
+?>
+
+
+
+
+
+
+ INTER-SANTÉ - Vérification d'identité
+
+
+
+
+
+
+
+
+
+
+
Demande Vérification du lien...
+
+
+
+
+
+
Instructions pour la vérification
+
+ - Positionnez votre visage dans l'ovale
+ - Assurez-vous d'être dans un endroit bien éclairé
+ - Regardez directement la caméra
+ - Restez immobile lors de la capture
+ - Retirez lunettes de soleil, casquette ou masque
+
+
+
+
+
+
+
+
+
+ Positionnez votre visage dans l'ovale
+
+
+
+
+
+
+
Confirmez votre photo
+
![Votre photo]()
+
+
+
+
+
+
+
+
+ Vérification de votre identité en cours...
+ Merci de patienter
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Contestation/verify_facial_api.php b/Contestation/verify_facial_api.php
index 29ee12c..55449fc 100644
--- a/Contestation/verify_facial_api.php
+++ b/Contestation/verify_facial_api.php
@@ -25,13 +25,6 @@ class FacialVerificationAPI {
* Valide un token de vérification
*/
public function validateToken($token) {
-
- /*
- $request = $this->assure_api->valider_token();
- var_dump($request);
- exit;
- */
-
try {
$request = $this->assure_api->valider_token();
@@ -294,6 +287,10 @@ class FacialVerificationAPI {
* Vérifie le visage capturé
*/
public function verifyFace($token, $capturedImageBase64) {
+ $request = $this->assure_api->valider_token();
+ var_dump($request);
+ exit;
+
try {
// 1. Récupérer les infos de la demande
$sql = "SELECT vr.*, a.photo_reference_path, a.id as assure_id
diff --git a/Contestation/verify_facial_api_2026_02_23_08h.php b/Contestation/verify_facial_api_2026_02_23_08h.php
new file mode 100644
index 0000000..29ee12c
--- /dev/null
+++ b/Contestation/verify_facial_api_2026_02_23_08h.php
@@ -0,0 +1,433 @@
+ false, 'message' => 'Méthode non autorisée']);
+ exit;
+}
+
+class FacialVerificationAPI {
+ private $assure_api;
+ private $maxAttempts = 3;
+
+ public function __construct() {
+ $this->assure_api = $_SESSION['assure'];
+ $this->maxAttempts = $this->assure_api
+ ? $this->assure_api->get_nbTentativeBiometrie($_SESSION['codeEntite'])
+ : 3;
+ }
+
+ /**
+ * Valide un token de vérification
+ */
+ public function validateToken($token) {
+
+ /*
+ $request = $this->assure_api->valider_token();
+ var_dump($request);
+ exit;
+ */
+
+ try {
+ $request = $this->assure_api->valider_token();
+
+ if (!$request) {
+ return [
+ 'success' => false,
+ 'message' => 'Lien expiré ou invalide'
+ ];
+ }
+
+ return [
+ 'success' => true,
+ 'message' => 'Token valide',
+ 'assure' => [
+ 'nom' => $request['nom'],
+ 'prenoms' => $request['prenoms']
+ ]
+ ];
+
+ } catch (Exception $e) {
+ error_log("Erreur validateToken: " . $e->getMessage());
+ return [
+ 'success' => false,
+ 'message' => 'Erreur serveur'
+ ];
+ }
+ }
+
+ /**
+ * Compare deux visages avec l'API de reconnaissance faciale
+ * Utilisez Azure Face API, AWS Rekognition, ou une solution locale
+ */
+ private function compareFaces($referenceImagePath, $capturedImageBase64) {
+ // Option 1: Azure Face API (Recommandé)
+ return $this->compareWithAzureFaceAPI($referenceImagePath, $capturedImageBase64);
+
+ // Option 2: AWS Rekognition
+ // return $this->compareWithAWSRekognition($referenceImagePath, $capturedImageBase64);
+
+ // Option 3: Solution locale avec OpenCV/dlib (avancé)
+ // return $this->compareWithLocalFaceRecognition($referenceImagePath, $capturedImageBase64);
+ }
+
+ /**
+ * Comparaison avec Azure Face API
+ */
+ private function compareWithAzureFaceAPI($referenceImagePath, $capturedImageBase64) {
+ $endpoint = AZURE_FACE_ENDPOINT;
+ $apiKey = AZURE_FACE_API_KEY;
+
+ try {
+ // 1. Détecter le visage dans l'image de référence
+ $referenceImageData = base64_encode(file_get_contents($referenceImagePath));
+ $referenceFaceId = $this->detectFaceAzure($referenceImageData, $endpoint, $apiKey);
+
+ if (!$referenceFaceId) {
+ return [
+ 'match' => false,
+ 'confidence' => 0,
+ 'error' => 'Aucun visage détecté dans la photo de référence'
+ ];
+ }
+
+ // 2. Détecter le visage dans l'image capturée
+ $capturedImageData = explode(',', $capturedImageBase64)[1];
+ $capturedFaceId = $this->detectFaceAzure($capturedImageData, $endpoint, $apiKey);
+
+ if (!$capturedFaceId) {
+ return [
+ 'match' => false,
+ 'confidence' => 0,
+ 'error' => 'Aucun visage détecté dans votre photo'
+ ];
+ }
+
+ // 3. Comparer les deux visages
+ $verifyUrl = $endpoint . '/face/v1.0/verify';
+
+ $data = [
+ 'faceId1' => $referenceFaceId,
+ 'faceId2' => $capturedFaceId
+ ];
+
+ $ch = curl_init($verifyUrl);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch, CURLOPT_POST, true);
+ curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
+ curl_setopt($ch, CURLOPT_HTTPHEADER, [
+ 'Content-Type: application/json',
+ 'Ocp-Apim-Subscription-Key: ' . $apiKey
+ ]);
+
+ $response = curl_exec($ch);
+ $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+ curl_close($ch);
+
+ if ($httpCode !== 200) {
+ throw new Exception("Azure API error: " . $response);
+ }
+
+ $result = json_decode($response, true);
+
+ return [
+ 'match' => $result['isIdentical'],
+ 'confidence' => round($result['confidence'] * 100, 2),
+ 'error' => null
+ ];
+
+ } catch (Exception $e) {
+ error_log("Erreur Azure Face API: " . $e->getMessage());
+ return [
+ 'match' => false,
+ 'confidence' => 0,
+ 'error' => 'Erreur lors de la vérification faciale'
+ ];
+ }
+ }
+
+ /**
+ * Détecte un visage avec Azure Face API et retourne le faceId
+ */
+ private function detectFaceAzure($imageBase64, $endpoint, $apiKey) {
+ $detectUrl = $endpoint . '/face/v1.0/detect?returnFaceId=true';
+
+ $ch = curl_init($detectUrl);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch, CURLOPT_POST, true);
+ curl_setopt($ch, CURLOPT_POSTFIELDS, base64_decode($imageBase64));
+ curl_setopt($ch, CURLOPT_HTTPHEADER, [
+ 'Content-Type: application/octet-stream',
+ 'Ocp-Apim-Subscription-Key: ' . $apiKey
+ ]);
+
+ $response = curl_exec($ch);
+ $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+ curl_close($ch);
+
+ if ($httpCode !== 200) {
+ return null;
+ }
+
+ $faces = json_decode($response, true);
+
+ if (empty($faces)) {
+ return null;
+ }
+
+ return $faces[0]['faceId'];
+ }
+
+ /**
+ * Comparaison avec AWS Rekognition (Alternative)
+ */
+ private function compareWithAWSRekognition($referenceImagePath, $capturedImageBase64) {
+ require_once 'vendor/autoload.php';
+
+ try {
+ $rekognitionClient = new Aws\Rekognition\RekognitionClient([
+ 'version' => 'latest',
+ 'region' => AWS_REGION,
+ 'credentials' => [
+ 'key' => AWS_ACCESS_KEY_ID,
+ 'secret' => AWS_SECRET_ACCESS_KEY
+ ]
+ ]);
+
+ $referenceImageData = file_get_contents($referenceImagePath);
+ $capturedImageData = base64_decode(explode(',', $capturedImageBase64)[1]);
+
+ $result = $rekognitionClient->compareFaces([
+ 'SourceImage' => ['Bytes' => $referenceImageData],
+ 'TargetImage' => ['Bytes' => $capturedImageData],
+ 'SimilarityThreshold' => 80
+ ]);
+
+ if (empty($result['FaceMatches'])) {
+ return [
+ 'match' => false,
+ 'confidence' => 0,
+ 'error' => 'Les visages ne correspondent pas'
+ ];
+ }
+
+ $similarity = $result['FaceMatches'][0]['Similarity'];
+
+ return [
+ 'match' => $similarity >= 80,
+ 'confidence' => round($similarity, 2),
+ 'error' => null
+ ];
+
+ } catch (Exception $e) {
+ error_log("Erreur AWS Rekognition: " . $e->getMessage());
+ return [
+ 'match' => false,
+ 'confidence' => 0,
+ 'error' => 'Erreur lors de la vérification faciale'
+ ];
+ }
+ }
+
+ /**
+ * Enregistre la photo capturée
+ */
+ private function saveCapturedImage($assureId, $imageBase64) {
+ $uploadDir = 'uploads/facial_verification/';
+
+ if (!file_exists($uploadDir)) {
+ mkdir($uploadDir, 0755, true);
+ }
+
+ $imageData = explode(',', $imageBase64)[1];
+ $imageData = base64_decode($imageData);
+
+ $filename = $uploadDir . $assureId . '_' . time() . '.jpg';
+ file_put_contents($filename, $imageData);
+
+ return $filename;
+ }
+
+ /**
+ * Met à jour le statut de la vérification
+ */
+ private function updateVerificationStatus($token, $status, $matchResult = null, $capturedPhotoPath = null) {
+ $sql = "UPDATE facial_verification_requests
+ SET status = ?,
+ verified_at = NOW(),
+ match_confidence = ?,
+ captured_photo_path = ?,
+ attempts = attempts + 1
+ WHERE verification_token = ?";
+
+ $stmt = $this->db->prepare($sql);
+ $stmt->execute([
+ $status,
+ $matchResult ? $matchResult['confidence'] : null,
+ $capturedPhotoPath,
+ $token
+ ]);
+ }
+
+ /**
+ * Crée une session d'autorisation pour l'accès aux prestations
+ */
+ private function createAuthorizationSession($assureId, $verificationRequestId) {
+ $sessionToken = bin2hex(random_bytes(32));
+ $expiresAt = date('Y-m-d H:i:s', time() + 3600);
+
+ $sql = "INSERT INTO prestation_authorization_sessions
+ (assure_id, verification_request_id, session_token, expires_at, status)
+ VALUES (?, ?, ?, ?, 'active')";
+
+ $stmt = $this->db->prepare($sql);
+ $stmt->execute([$assureId, $verificationRequestId, $sessionToken, $expiresAt]);
+
+ return $sessionToken;
+ }
+
+ /**
+ * Vérifie le visage capturé
+ */
+ public function verifyFace($token, $capturedImageBase64) {
+ try {
+ // 1. Récupérer les infos de la demande
+ $sql = "SELECT vr.*, a.photo_reference_path, a.id as assure_id
+ FROM facial_verification_requests vr
+ JOIN assures a ON vr.assure_id = a.id
+ WHERE vr.verification_token = ?
+ AND vr.status = 'pending'
+ AND vr.expires_at > NOW()";
+
+ $stmt = $this->db->prepare($sql);
+ $stmt->execute([$token]);
+ $request = $stmt->fetch(PDO::FETCH_ASSOC);
+
+ if (!$request) {
+ return [
+ 'success' => false,
+ 'match' => false,
+ 'message' => 'Demande expirée ou invalide'
+ ];
+ }
+
+ // 2. Vérifier le nombre de tentatives
+ if ($request['attempts'] >= $this->maxAttempts) {
+ $this->updateVerificationStatus($token, 'failed');
+ return [
+ 'success' => false,
+ 'match' => false,
+ 'message' => 'Nombre maximum de tentatives atteint'
+ ];
+ }
+
+ // 3. Enregistrer la photo capturée
+ $capturedPhotoPath = $this->saveCapturedImage($request['assure_id'], $capturedImageBase64);
+
+ // 4. Comparer les visages
+ $comparisonResult = $this->compareFaces(
+ $request['photo_reference_path'],
+ $capturedImageBase64
+ );
+
+ if ($comparisonResult['error']) {
+ $this->updateVerificationStatus($token, 'error', $comparisonResult, $capturedPhotoPath);
+ return [
+ 'success' => false,
+ 'match' => false,
+ 'message' => $comparisonResult['error'],
+ 'attempts_remaining'=> $this->maxAttempts - ($request['attempts'] + 1)
+ ];
+ }
+
+ // 5. Seuil de confiance minimum (80%)
+ $confidenceThreshold = 80;
+ $isMatch = $comparisonResult['match'] && $comparisonResult['confidence'] >= $confidenceThreshold;
+
+ if ($isMatch) {
+ $this->updateVerificationStatus($token, 'verified', $comparisonResult, $capturedPhotoPath);
+ $sessionToken = $this->createAuthorizationSession($request['assure_id'], $request['id']);
+
+ return [
+ 'success' => true,
+ 'match' => true,
+ 'confidence' => $comparisonResult['confidence'],
+ 'message' => 'Identité vérifiée avec succès',
+ 'session_token' => $sessionToken,
+ 'redirect_url' => 'saisie_prestations.php?token=' . $sessionToken
+ ];
+ } else {
+ $attemptsRemaining = $this->maxAttempts - ($request['attempts'] + 1);
+
+ if ($attemptsRemaining > 0) {
+ $this->updateVerificationStatus($token, 'pending', $comparisonResult, $capturedPhotoPath);
+ return [
+ 'success' => false,
+ 'match' => false,
+ 'confidence' => $comparisonResult['confidence'],
+ 'message' => 'Votre visage ne correspond pas',
+ 'attempts_remaining' => $attemptsRemaining
+ ];
+ } else {
+ $this->updateVerificationStatus($token, 'failed', $comparisonResult, $capturedPhotoPath);
+ return [
+ 'success' => false,
+ 'match' => false,
+ 'confidence' => $comparisonResult['confidence'],
+ 'message' => 'Vérification échouée. Nombre maximum de tentatives atteint.',
+ 'attempts_remaining' => 0
+ ];
+ }
+ }
+
+ } catch (Exception $e) {
+ error_log("Erreur verifyFace: " . $e->getMessage());
+ return [
+ 'success' => false,
+ 'match' => false,
+ 'message' => 'Erreur lors de la vérification: ' . $e->getMessage()
+ ];
+ }
+ }
+}
+
+// Traiter la requête
+if ($_SERVER['REQUEST_METHOD'] === 'POST') {
+ $input = json_decode(file_get_contents('php://input'), true);
+ $action = $input['action'] ?? null;
+
+ $api = new FacialVerificationAPI();
+
+ switch ($action) {
+ case 'validate_token':
+ $token = $input['token'] ?? null;
+ if (!$token) {
+ echo json_encode(['success' => false, 'message' => 'Token requis']);
+ exit;
+ }
+ echo json_encode($api->validateToken($token));
+ break;
+
+ case 'verify_face':
+ $token = $input['token'] ?? null;
+ $image = $input['image'] ?? null;
+
+ if (!$token || !$image) {
+ echo json_encode(['success' => false, 'message' => 'Token et image requis']);
+ exit;
+ }
+ echo json_encode($api->verifyFace($token, $image));
+ break;
+
+ default:
+ echo json_encode(['success' => false, 'message' => 'Action invalide']);
+ }
+} else {
+ // echo json_encode(['success' => false, 'message' => 'Méthode non autorisée']);
+ ob_end_clean(); // ✅ vide le buffer avant d'envoyer le JSON
+ echo json_encode(['success' => false, 'message' => 'Méthode non autorisée']);
+}
\ No newline at end of file