From 35c4b740491c8fa8a4c4385b44f4bf6aa208be9a Mon Sep 17 00:00:00 2001 From: KANE LAZENI Date: Mon, 23 Feb 2026 09:11:13 +0000 Subject: [PATCH] a --- Contestation/Demandereconnaissancefaciale.php | 40 +- ...dereconnaissancefaciale_2026_02_23_08h.php | 751 ++++++++++++++++++ Contestation/verify_facial_api.php | 11 +- .../verify_facial_api_2026_02_23_08h.php | 433 ++++++++++ 4 files changed, 1222 insertions(+), 13 deletions(-) create mode 100755 Contestation/Demandereconnaissancefaciale_2026_02_23_08h.php create mode 100644 Contestation/verify_facial_api_2026_02_23_08h.php 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é + + + +
+
+

🏥 INTER-SANTÉ

+

Vérification d'identité sécurisée

+
+ +
+ +
+
+

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 +

+
+ + +
+
+
+

+

+
+
+
+ + +
+
+

❌ Erreur

+

+
+
+
+
+ + + + + + 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