assure/Contestation/Demandereconnaissancefaciale.php
2026-02-23 23:41:24 +00:00

822 lines
26 KiB
PHP
Executable File
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
session_start();
session_unset();
if (!isset($_GET['lg'])) {
afficherMessage("Paramètre langue absent de la requête!");
}
$lg = $_GET['lg'];
$codeLangue = base64_decode($lg);
$tab_code_langue = ["fr_FR", "en_US"];
if (!in_array($codeLangue, $tab_code_langue)) {
afficherMessage("Langue inconnue!");
}
if (!isset($_GET['codeEntite'])) {
$msg = $codeLangue == 'en_US' ? "Entity parameter missing from query!" : "Paramètre entité absent de la requête!";
afficherMessage($msg);
}
if (!isset($_GET['codePrestataire'])) {
$msg = $codeLangue == 'en_US' ? "Provider parameter missing from query!" : "Paramètre prestataire absent de la requête!";
afficherMessage($msg);
}
if (!isset($_GET['idBeneficiaire'])) {
$msg = $codeLangue == 'en_US' ? "Insured ID missing from query!" : "ID assuré absent de la requête!";
afficherMessage($msg);
}
if (!isset($_GET['idDemande'])) {
$msg = $codeLangue == 'en_US' ? "Reqest ID missing from query!" : "ID demande absent de la requête!";
afficherMessage($msg);
}
$_SESSION['codeLangue'] = $lg;
$_SESSION['codeEntite'] = base64_decode($_GET['codeEntite']);
$_SESSION['codePrestataire'] = base64_decode($_GET['codePrestataire']);
$_SESSION['idBeneficiaire'] = base64_decode($_GET['idBeneficiaire']);
$_SESSION['idDemande'] = base64_decode($_GET['idDemande']);
$codeSociete = $_SESSION['codeEntite'];
$idBeneficiaire = $_SESSION['idBeneficiaire'];
$idDemande = $_SESSION['idDemande'];
$codePrestataire = $_SESSION['codePrestataire'];
$codeBdd = $codeSociete;
require_once "Assure.php";
$assure = new Assure();
$_SESSION['assure'] = $assure;
$_SESSION['codeBdd'] = $codeBdd;
$bdd = $assure->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("<strong>$message</strong>");
}
$_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("<strong>$message</strong>");
}
$demande = $assure->checkdemandereconnaissancefaciale_id();
if(!$demande) {
$message = $codeLangue == 'en_US' ? "No requests found!" : "Aucune demande trouvée!";
afficherMessage("<strong>$message</strong>");
}
$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"];
$lienPhoto = $demande["lienPhoto"];
// 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("<strong>$message</strong>");
}
if($codeEtat=="1") {
$message = $codeLangue == 'en_US' ? "Verification already completed!" : "Vérification déjà exffectuée!";
afficherMessage("<strong>$message</strong>");
}
if($codeEtat=="2") {
$message = $codeLangue == 'en_US' ? "Failure, please try again!" : "Echec, veuilez réessayer!";
afficherMessage("<strong>$message</strong>");
}
if($codeEtat=="4") {
$message = $codeLangue == 'en_US' ? "Error, please try again!" : "Erreur, veuilez réessayer!";
afficherMessage("<strong>$message</strong>");
}
/*
$message = $codeLangue == 'en_US'
? "Parameters successfully verified!"
: "Paramètres vérifiés avec succès!";
afficherMessage("<strong>$message</strong>", false);
*/
$param_societe = $assure->get_parametres_societe($codeSociete);
$_SESSION['dureeToken'] = $param_societe["dureeTokenReconnaissanceFaciale"];
$_SESSION['dossierPhoto'] = $param_societe["dossierPhoto"];
$_SESSION['nbTentative'] = $param_societe["nbTentativeBiometrie"];
$_SESSION['lienPhotoFace'] = $param_societe["lienPhotoFace"];
// vérifier que la photo du bénéficiaire existe
if ($_SESSION['lienPhoto']>" ")
{
$photo = $_SESSION['lienPhotoFace'].$_SESSION['lienPhoto'];
if(!file_exists($photo))
{
$_SESSION['lienPhoto'] = "";
}
else
{
$_SESSION['photoAssureCrypte'] = decryptImage($photo);
}
}
}
function afficherMessage($message) {
echo "<!DOCTYPE html>
<html lang='fr'>
<head>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<title>Erreur</title>
<link href='https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css' rel='stylesheet'>
<link href='https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css' rel='stylesheet'>
<style>
.error-container {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}
.error-card {
background: white;
border-radius: 12px;
box-shadow: 0 8px 30px rgba(0,0,0,0.12);
padding: 2rem;
max-width: 500px;
width: 100%;
border-left: 4px solid #dc3545;
}
</style>
</head>
<body class='bg-light'>
<div class='error-container'>
<div class='error-card'>
<div class='text-center mb-3'>
<i class='bi bi-exclamation-triangle-fill text-danger' style='font-size: 3rem;'></i>
</div>
<h4 class='text-center text-danger mb-3'>Erreur</h4>
<p class='text-center text-muted'>{$message}</p>
</div>
</div>
</body>
</html>";
exit();
// echo $message;
}
// Chiffrer limage au moment de lupload (PHP)
function encryptImage($sourcePath, $destPath)
{
$key = base64_decode(trim(file_get_contents('/var/www/keys/inter-sante-photo.key')));
$plaintext = file_get_contents($sourcePath);
$iv = openssl_random_pseudo_bytes(16);
$cipher = openssl_encrypt($plaintext, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
file_put_contents($destPath, $iv . $cipher); // concat IV + données
}
// Déchiffrer pour afficher la photo dans INTER-SANTE
function decryptImage($path)
{
$key = base64_decode(trim(file_get_contents('/var/www/keys/inter-sante-photo.key')));
$data = file_get_contents($path);
$iv = substr($data, 0, 16);
$ciphertext = substr($data, 16);
// return openssl_decrypt($ciphertext, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
return base64_encode(openssl_decrypt($ciphertext, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv));
}
?>
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>INTER-SANTÉ - Vérification d'identité</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}
.container {
background: white;
border-radius: 20px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
max-width: 600px;
width: 100%;
overflow: hidden;
}
.header {
background: linear-gradient(135deg, #2c3e50 0%, #34495e 100%);
color: white;
padding: 30px;
text-align: center;
}
.header h1 {
font-size: 28px;
margin-bottom: 10px;
}
.header p {
opacity: 0.9;
}
.content {
padding: 40px 30px;
}
.step {
display: none;
}
.step.active {
display: block;
}
.video-container {
position: relative;
background: #000;
border-radius: 15px;
overflow: hidden;
margin: 20px 0;
}
#video, #canvas {
width: 100%;
display: block;
border-radius: 15px;
}
#canvas {
display: none;
}
.face-overlay {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 250px;
height: 300px;
border: 3px dashed rgba(255, 255, 255, 0.7);
border-radius: 50%;
pointer-events: none;
}
.instructions {
background: #f8f9fa;
padding: 20px;
border-radius: 10px;
margin: 20px 0;
}
.instructions h3 {
color: #2c3e50;
margin-bottom: 15px;
display: flex;
align-items: center;
}
.instructions h3::before {
content: "";
margin-right: 10px;
}
.instructions ul {
list-style: none;
padding-left: 0;
}
.instructions li {
padding: 8px 0;
padding-left: 25px;
position: relative;
}
.instructions li::before {
content: "✓";
position: absolute;
left: 0;
color: #27ae60;
font-weight: bold;
}
.button {
background: linear-gradient(135deg, #3498db 0%, #2980b9 100%);
color: white;
border: none;
padding: 15px 30px;
font-size: 16px;
border-radius: 10px;
cursor: pointer;
width: 100%;
margin: 10px 0;
transition: transform 0.2s, box-shadow 0.2s;
font-weight: 600;
}
.button:hover {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(52, 152, 219, 0.4);
}
.button:disabled {
opacity: 0.5;
cursor: not-allowed;
transform: none;
}
.button.capture {
background: linear-gradient(135deg, #e74c3c 0%, #c0392b 100%);
}
.button.retry {
background: linear-gradient(135deg, #95a5a6 0%, #7f8c8d 100%);
}
.status {
padding: 15px;
border-radius: 10px;
margin: 20px 0;
text-align: center;
font-weight: 500;
}
.status.info {
background: #d1ecf1;
color: #0c5460;
border: 1px solid #bee5eb;
}
.status.success {
background: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.status.error {
background: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
.status.warning {
background: #fff3cd;
color: #856404;
border: 1px solid #ffeeba;
}
.loader {
border: 4px solid #f3f3f3;
border-top: 4px solid #3498db;
border-radius: 50%;
width: 50px;
height: 50px;
animation: spin 1s linear infinite;
margin: 20px auto;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.preview-image {
max-width: 100%;
border-radius: 15px;
margin: 20px 0;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
}
.match-result {
text-align: center;
padding: 30px;
}
.match-result .icon {
font-size: 80px;
margin-bottom: 20px;
}
.match-result h2 {
color: #2c3e50;
margin-bottom: 15px;
}
.countdown {
font-size: 14px;
color: #7f8c8d;
text-align: center;
margin-top: 20px;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🏥 INTER-SANTÉ</h1>
<p>Vérification d'identité sécurisée</p>
</div>
<div class="content">
<!-- Étape 1: Chargement -->
<div id="step-loading" class="step active">
<div class="loader"></div>
<p style="text-align: center; color: #7f8c8d;">Demande Vérification du lien...</p>
</div>
<!-- Étape 2: Instructions -->
<div id="step-instructions" class="step">
<div class="instructions">
<h3>Instructions pour la vérification</h3>
<ul>
<li>Positionnez votre visage dans l'ovale</li>
<li>Assurez-vous d'être dans un endroit bien éclairé</li>
<li>Regardez directement la caméra</li>
<li>Restez immobile lors de la capture</li>
<li>Retirez lunettes de soleil, casquette ou masque</li>
</ul>
</div>
<button class="button" onclick="startCamera()">📸 Démarrer la caméra</button>
</div>
<!-- Étape 3: Capture -->
<div id="step-capture" class="step">
<div class="video-container">
<video id="video" autoplay playsinline></video>
<canvas id="canvas"></canvas>
<div class="face-overlay"></div>
</div>
<div id="camera-status" class="status info">
Positionnez votre visage dans l'ovale
</div>
<button class="button capture" onclick="capturePhoto()">📷 Prendre la photo</button>
</div>
<!-- Étape 4: Confirmation -->
<div id="step-confirm" class="step">
<h3 style="color: #2c3e50; margin-bottom: 15px;">Confirmez votre photo</h3>
<img id="preview" class="preview-image" alt="Votre photo">
<button class="button" onclick="verifyPhoto()">✓ Confirmer et vérifier</button>
<button class="button retry" onclick="retakePhoto()">↻ Reprendre la photo</button>
</div>
<!-- Étape 5: Vérification en cours -->
<div id="step-verifying" class="step">
<div class="loader"></div>
<p style="text-align: center; color: #7f8c8d; margin-top: 20px;">
Vérification de votre identité en cours...<br>
<small>Merci de patienter</small>
</p>
</div>
<!-- Étape 6: Résultat -->
<div id="step-result" class="step">
<div class="match-result">
<div class="icon" id="result-icon"></div>
<h2 id="result-title"></h2>
<p id="result-message"></p>
</div>
<div id="countdown" class="countdown"></div>
</div>
<!-- Étape 7: Erreur -->
<div id="step-error" class="step">
<div class="status error">
<h3>❌ Erreur</h3>
<p id="error-message"></p>
</div>
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script>
let video = document.getElementById('video');
let canvas = document.getElementById('canvas');
let context = canvas.getContext('2d');
let stream = null;
let verificationToken = null;
let capturedImage = null;
// Récupérer le token depuis l'URL
const urlParams = new URLSearchParams(window.location.search);
// verificationToken = urlParams.get('token');
verificationToken = <?= $_SESSION['idDemande'] ?> ;
// alert("verificationToken = "+verificationToken);
// Initialisation
window.onload = function() {
if (!verificationToken) {
showError('Lien de vérification invalide');
return;
}
// Vérifier la validité du token
validateToken();
};
function validateToken() {
$.ajax({
url: '/Contestation/verify_facial_api.php',
method: 'POST',
contentType: 'application/json',
data: JSON.stringify({
action: 'validate_token',
token: verificationToken
}),
dataType: 'json',
success: function(data) {
if (data.success) {
showStep('step-instructions');
} else {
showError(data.message || 'Lien expiré ou invalide');
}
},
error: function(xhr, status, err) {
showError('Erreur de connexion au serveur');
// showError(xhr.responseText);
}
});
}
function showStep(stepId) {
document.querySelectorAll('.step').forEach(step => {
step.classList.remove('active');
});
document.getElementById(stepId).classList.add('active');
}
function showError(message) {
document.getElementById('error-message').textContent = message;
showStep('step-error');
}
async function startCamera() {
try {
stream = await navigator.mediaDevices.getUserMedia({
video: {
facingMode: 'user',
width: { ideal: 1280 },
height: { ideal: 720 }
}
});
video.srcObject = stream;
showStep('step-capture');
} catch (error) {
console.error('Erreur caméra:', error);
showError('Impossible d\'accéder à la caméra. Veuillez autoriser l\'accès.');
}
}
function capturePhoto() {
// Configurer le canvas
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
// Capturer l'image
context.drawImage(video, 0, 0, canvas.width, canvas.height);
// Convertir en base64
capturedImage = canvas.toDataURL('image/jpeg', 0.9);
// Afficher l'aperçu
document.getElementById('preview').src = capturedImage;
// Arrêter la caméra
stopCamera();
// Passer à l'étape de confirmation
showStep('step-confirm');
}
function retakePhoto() {
capturedImage = null;
startCamera();
}
function stopCamera() {
if (stream) {
stream.getTracks().forEach(track => track.stop());
stream = null;
}
}
/*
function verifyPhoto() {
showStep('step-verifying');
fetch('verify_facial_api.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
action: 'verify_face',
token: verificationToken,
image: capturedImage
})
})
.then(response => response.json())
.then(data => {
if (data.success && data.match) {
showSuccess(data);
} else {
showFailure(data);
}
})
.catch(error => {
showError('Erreur lors de la vérification: ' + error.message);
});
}
*/
function verifyPhoto() {
showStep('step-verifying');
$.ajax({
url: '/Contestation/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 !';
document.getElementById('result-title').style.color = '#27ae60';
document.getElementById('result-message').innerHTML =
`Votre identité a été confirmée avec succès.<br>
Confiance: ${data.confidence}%<br><br>
<strong>Vous pouvez maintenant accéder à vos prestations.</strong>`;
showStep('step-result');
// Redirection automatique après 5 secondes
startCountdown(5, () => {
window.location.href = data.redirect_url || 'dashboard.php';
});
}
function showFailure(data) {
document.getElementById('result-icon').textContent = '❌';
document.getElementById('result-title').textContent = 'Vérification échouée';
document.getElementById('result-title').style.color = '#e74c3c';
document.getElementById('result-message').innerHTML =
`${data.message || 'Votre visage ne correspond pas à notre base de données.'}<br><br>
Si vous pensez qu'il s'agit d'une erreur, veuillez contacter notre service client.<br>
<strong>Tentatives restantes: ${data.attempts_remaining || 0}</strong>`;
showStep('step-result');
// Permettre une nouvelle tentative si disponible
if (data.attempts_remaining > 0) {
setTimeout(() => {
location.reload();
}, 5000);
}
}
function startCountdown(seconds, callback) {
let remaining = seconds;
const countdownEl = document.getElementById('countdown');
const interval = setInterval(() => {
countdownEl.textContent = `Redirection dans ${remaining} secondes...`;
remaining--;
if (remaining < 0) {
clearInterval(interval);
callback();
}
}, 1000);
}
// Nettoyer la caméra quand on quitte la page
window.onbeforeunload = function() {
stopCamera();
};
</script>
</body>
</html>