This commit is contained in:
KONE SOREL 2026-03-04 01:46:25 +00:00
commit fb2bedd0e7
21 changed files with 803 additions and 1148 deletions

15
.gitignore vendored
View File

@ -1,5 +1,10 @@
Config/
Config
Config/dev.ini
vendor/
vendor
Config/
Config
Config/dev.ini
vendor/
vendor
logs/
logs
Cron/prod.ini
Temp/
Temp

View File

@ -0,0 +1,24 @@
<?php
require_once 'Framework/Controleur.php';
require_once 'Modele/Beneficiaire.php';
class ControleurAjaxdemandereconnaissancefaciale extends Controleur {
private $beneficiaire;
public function __construct() {
$this->beneficiaire = new Beneficiaire();
}
public function index() {
$this->beneficiaire->demandereconnaissancefaciale();
$this->genererVueAjax();
}
public function checkdemandereconnaissancefaciale()
{
$demandereconnaissancefaciale = $this->beneficiaire->checkdemandereconnaissancefaciale();
$codeEtat = $demandereconnaissancefaciale["codeEtat"];
$this->genererVueAjax(array('demandereconnaissancefaciale' => $demandereconnaissancefaciale, 'codeEtat' => $codeEtat));
}
}

View File

@ -17,7 +17,7 @@ class ControleurConnexion extends Controleur
private $garantie;
private $societeusercentral;
private $menuvue;
private $menuvue;
public function __construct()
{
$this->utilisateur = new Utilisateur();
@ -770,7 +770,15 @@ class ControleurConnexion extends Controleur
$this->rediriger("Kine");
break;
default:
$this->rediriger("Recherche");
$carteAvecDonnees = $utilisateur['carteAvecDonnees'];
if($carteAvecDonnees=="1")
{
$this->rediriger("Rechercheparcarte");
}
else
{
$this->rediriger("Recherche");
}
}
}
}

View File

@ -11,7 +11,7 @@ require_once 'Modele/Bonpec.php';
require_once 'Modele/Medecin.php';
require_once 'Modele/Garantiesbaremepriseencharge.php';
class ControleurFichebeneficiaire extends Controleur {
class ControleurFichebeneficiaire extends Controleur {
private $menuvue;
private $beneficiaire;
@ -209,6 +209,13 @@ class ControleurFichebeneficiaire extends Controleur {
$sexe = $beneficiaire['sexe'];
$raison = $this->raison->getraisonconsultation($sexe);
// KANE => 24/02/205 => réponse demande reconnaissance faciale
$etatDemanderecFac = $this->beneficiaire->fn_etat_demandereconnaissancefaciale();
$libelleEtatDemanderecFac = $this->beneficiaire->fn_libelle_etat_demandereconnaissancefaciale();
$messagePrestataireRecFac = $this->beneficiaire->fn_message_demandereconnaissancefaciale();
// if (in_array($etatDemanderecFac, ["-1", "3", "4", "5"] , true)){}
$this->genererVue(array(
'beneficiaire' => $beneficiaire,
@ -235,7 +242,10 @@ class ControleurFichebeneficiaire extends Controleur {
'bonNonLivrePha' => $bonNonLivrePha,
'nuit' => $nuit,
'acte' => $acte,
'specialite' => $specialite
'specialite' => $specialite,
'etatDemanderecFac' => $etatDemanderecFac,
'libelleEtatDemanderecFac' => $libelleEtatDemanderecFac,
'messagePrestataireRecFac' => $messagePrestataireRecFac
));
}
@ -439,4 +449,11 @@ class ControleurFichebeneficiaire extends Controleur {
$this->beneficiaire->envoyer_otp($otpValue);
$this->rediriger("Fichebeneficiaire");
}
public function demandereconnaissancefaciale() {
$telephoneAutre = $this->requete->getParametreFormulaire("telephoneAutre");
$this->beneficiaire->demandereconnaissancefaciale($telephoneAutre);
$this->rediriger("Fichebeneficiaire");
}
}

View File

@ -35,15 +35,6 @@ class ControleurRechercheparcarte extends Controleur {
$msgErreur="";
}
/*
var_dump(
array(
"msgErreur" => $msgErreur,
)
);
exit();
*/
$this->beneficiaire->getModeBiometrie();
$_SESSION['p_okId'] = "-1";
@ -62,43 +53,29 @@ class ControleurRechercheparcarte extends Controleur {
if(isset($_POST['donneesCarte']))
{
// IS1 => Inter-Sante V1
$donneesCarte = $_POST['donneesCarte']; // ex: "IS1|ebene|ESI6936000602"
$versionTagCarteEncours = $this->beneficiaire->getVersionTagCarteEncours();
$donneesCarte = $_POST['donneesCarte'];
$parts = explode('|', $donneesCarte);
// var_dump($parts);
// exit();
$versionTagCarte = base64_decode($parts[0]);
$codeEntite = base64_decode($parts[1]);
if (count($parts) !== 3 || $parts[0] !== 'IS1') {
if (count($parts) !== 5 || $versionTagCarte !== $versionTagCarteEncours || $codeEntite != $_SESSION['p_codeSociete']) {
$msgErreur = 'Carte invalide / Invalid card';
}
else{
$codeEntite = $parts[1];
$numeroBeneficiaireCarte = $parts[2];
$numeroBeneficiaireCarte = base64_decode($parts[2]);
$tagUuid = $parts[3];
$donneesCarte=trim($_POST['donneesCarte']);
/*
var_dump(
array(
"codeEntite" => $codeEntite,
"numeroBeneficiaireCarte" => $numeroBeneficiaireCarte,
)
);
exit();
*/
if($codeEntite<=" " || $numeroBeneficiaireCarte<=" ")
if($codeEntite<=" " || $numeroBeneficiaireCarte<=" " || $tagUuid<=" ")
{
$msgErreur = 'Carte invalide / Invalid card';
}
else
{
// faire le traitement de la carte ici
$derniernumerobeneficiaires = $this->beneficiaire->getnumerobeneficiairesperdu($numeroBeneficiaireCarte);
$beneficiaires = $this->beneficiaire->getBeneficiaire($numeroBeneficiaireCarte);
$beneficiaires = $this->beneficiaire->getBeneficiaireTag($versionTagCarte, $codeEntite, $numeroBeneficiaireCarte, $tagUuid);
$nbLignes = $beneficiaires->rowCount();
@ -106,30 +83,12 @@ class ControleurRechercheparcarte extends Controleur {
{
$beneficiaires->closeCursor(); // Fermer le curseur
$msgErreur = "$numeroBeneficiaireCarte : Carte introuvable / Card not found";
/*
var_dump(
array(
"nbLignes" => $nbLignes,
"msgErreur" => $msgErreur,
)
);
exit();
*/
}
else
{
$beneficiaire = $beneficiaires->fetch();
$beneficiaire = $beneficiaires->fetch(PDO::FETCH_ASSOC);
$beneficiaires->closeCursor(); // Fermer le curseur
/*
var_dump(
array(
"beneficiaire" => $beneficiaire,
"nbLignes" => $nbLignes,
)
);
exit();
*/
$_SESSION['p_idBeneficiaire_C'] = $beneficiaire['idBeneficiaire'];
$_SESSION['p_idBeneficiaire_sav'] = $_SESSION['p_idBeneficiaire_C'];
@ -140,9 +99,6 @@ class ControleurRechercheparcarte extends Controleur {
}
}
// var_dump($msgErreur);
// exit();
$this->genererVue(array('msgErreur' => $msgErreur));
}
}

View File

@ -1,14 +1,16 @@
<?php
require_once 'Functions.php';
require_once 'Societeusercentral.php';
class Cronnettoyerfihierstemp
{
private $societeusercentral;
public function __construct()
{
// $this->societeusercentral = new Societeusercentral();
}
// function suppression($dossier_traite , $extension_choisie, $age_requis)
function suppression($dossier_traite , $age_requis)
{
$repertoire = opendir($dossier_traite);
@ -19,20 +21,10 @@ class Cronnettoyerfihierstemp
$infos = pathinfo($chemin);
// $extension = $infos['extension'];
$age_fichier = time() - filemtime($chemin);
// if($fichier!="." AND $fichier!=".." AND !is_dir($fichier)
// $extension == $extension_choisie AND $age_fichier > $age_requis)
/*
echo "Chemai, : ".$chemin." Age : ".$age_fichier;
echo "<br>";
*/
if($fichier!="." AND $fichier!=".." AND !is_dir($fichier) AND $age_fichier > $age_requis)
if($fichier!="." AND $fichier!=".." AND !is_dir($chemin) AND $age_fichier > $age_requis)
{
unlink($chemin);
}
@ -66,11 +58,51 @@ class Cronnettoyerfihierstemp
}
$nettoyerfihierstemp = new Cronnettoyerfihierstemp();
$nettoyerfihierstemp = new Cronnettoyerfihierstemp();
$societeusercentral = (new Societeusercentral())->getSocieteuserSaas();
/* KANE => maj 14/02/2026
$nettoyerfihierstemp->suppression( "../Temp" , "3600" );
$nettoyerfihierstemp->suppression( "../Temp/import" , "432000" );
*/
$tempProduction = $societeusercentral['tempProduction'];
$tempPrestation = $societeusercentral['tempPrestation'];
$tempGarant = $societeusercentral['tempGarant'];
$tempAssure = $societeusercentral['tempAssure'];
$tempRh = $societeusercentral['tempRh'];
/*
var_dump(
array(
"tempProduction" => $tempProduction,
"tempPrestation" =>$tempPrestation,
"tempGarant" => $tempGarant,
"tempAssure" => $tempAssure,
"tempRh" => $tempRh
)
);
exit();
*/
// Production
$nettoyerfihierstemp->suppression($tempProduction."/Temp" , "3600" );
$nettoyerfihierstemp->suppression($tempProduction."/Temp/import" , "432000" );
// Prestation
$nettoyerfihierstemp->suppression($tempPrestation."/Temp" , "3600" );
$nettoyerfihierstemp->suppression($tempPrestation."/Temp/import" , "432000" );
// Garant
$nettoyerfihierstemp->suppression($tempGarant."/Temp" , "3600" );
$nettoyerfihierstemp->suppression($tempGarant."/Temp/import" , "432000" );
// Assure
$nettoyerfihierstemp->suppression($tempAssure."/Temp" , "3600" );
$nettoyerfihierstemp->suppression($tempAssure."/Temp/import" , "432000" );
// RH
$nettoyerfihierstemp->suppression($tempRh."/Temp" , "3600" );
$nettoyerfihierstemp->suppression($tempRh."/Temp/import" , "432000" );
?>

View File

@ -1,95 +1,95 @@
<?php //ICB0 71:0 81:c46 82:1515 ?><?php //002cd
<?php //ICB0 71:0 81:c6e 82:1551 ?><?php //002cd
if(extension_loaded('ionCube Loader')){die('The file '.__FILE__." is corrupted.\n");}echo("\nScript error: the ".(($cli=(php_sapi_name()=='cli')) ?'ionCube':'<a href="https://www.ioncube.com">ionCube</a>')." Loader for PHP needs to be installed.\n\nThe ionCube Loader is the industry standard PHP extension for running protected PHP code,\nand can usually be added easily to a PHP installation.\n\nFor Loaders please visit".($cli?":\n\nhttps://get-loader.ioncube.com\n\nFor":' <a href="https://get-loader.ioncube.com">get-loader.ioncube.com</a> and for')." an instructional video please see".($cli?":\n\nhttp://ioncu.be/LV\n\n":' <a href="http://ioncu.be/LV">http://ioncu.be/LV</a> ')."\n\n");exit(199);
?>
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
jZHhVVVjDt8U6wVbImDDSy2Wsnnpsm===
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
ikCmGDPZ2oiThgQ1pPfA=
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
tzPK2sTgEiWU7VwUrPD7V7j87jqRUCGNislDCle==
HR+cPxJofe0rMXktm4WpewZm7UUp1x6XUtXtOzsTyIDEi25Nmk7IKvVoQtzhzhynNSTGYGgh6fjF
4oH4UV8tu8tUy1NhkXtkbEYP5SjT45ZuMhTbwn7+EzUKOH6wmBfRt+Q1bacsFsAyNQLSZyCu6IAZ
QcoieXTE5fWdShtEslO6MGOxO9lYoL4KvN2FPinm46+455xuANRVSagSRBE0DLrn4qgazaQcvIWg
KC/UZMGMqGYaiWuhrkr8+BeQ0YHxgJlXqFlLZFndn7nAgn5eMh3RBJDvDy6oQepsJ/idV39FsH0C
NyRB8nLCauvu1hflQsmDL9N21R7P2HDA5T63Gp77n1iY4kfBYr1cMzV+dbK87dCU0q/ucqHd1CG3
4ZcuJAJFjot1YllrPhfo7sExahvJ5k/tHN6meuR0CpEMOJHdEXANs7BVsuplrgD+yEu9UO7U4fFy
3Eo7EzJUjMw1tanok/9Y8tpXlFlrdIqVjG6FHf1lkZGtYXzc1+nFASiEil0NoXm7XM+VDydtyabI
fnEeg4FvNRwCTt4FCI9ez1y1T9kioMlv56wpY4bPRTrWqzbZuzMcoXe0rGHPFVAYB3S7cwvHOO3v
Ov7hP24hFpxFCgCI1UARk3bJDM7Id9dX/D7EuUQXsNBF5Y3qrrDtSk8Wmn/2GJC+mVaEsxHUHz6t
LCHaOnmqfxkWPa92+4Hi1YBNYayw7kjG25Kk50/v4isOs7S2MDWH2/XInqgr4n+xl8zi274uVi0f
cYpJA8E8cYpMLKxHyfbYl9/hmLkgwXhz8pDOG7Q4I8HTET8Z4HjvWfVjP8nzDGzVsVjxHtIL7km0
4Zcc5/MzbDZJcQVfgkjrdRtnAdc6IQaaXHkniY/9A+3rgkd2LoCJTvn3qQz9iHTdok/igIEhsJQa
0eWUrVOFzrtaPMU1WFIpwDHcXAGpxTN6anI/BXrspPG3tD2F1fsrJMoDJFR+uXwobKaWOtCdeGGt
4pt82qB2iS4KeEnZ6rR/ocrrTYFaYBfk7lKX39o9wno9koeOHGDhnMDxbsMk7mAe5qprrbGHQWPc
sQXIE5k/tks1lnhvGe7vwd/06knSIH9gh44o5+l+8GO2mbt8S31J0cC8LE62EBAgQIjazEYCmFrU
Zx7PL9Tes59N9HHwKnExvHhlR65gHQX25SHCm1VLNMyH1oLv7Y0PjZ/eaQhazJZiNarmURnyzepe
PDbLZEZIbQywLCHCrdQN38XGctwDVgVAzyup7dZpaCteSsFor7JxWs/knajvOCsthhS0xk/RNg7Y
PQbmxxBzjg+oHjHbUi7lvslgfEv7yBR+YGr2IJPJHGXA75YWR/JksvRKJdvf0XZ5w7SPOwfsH9Tw
eEz2YFEYm/CvC0QHzQtvi4aCn1J+9DMsaZPFw3CB91vbI7aJwPIDp5G7N7OTw4R2cvkKdkaO77tY
XZq3axkIhW9kvGP5K17qrYEx9z7RJjmdNBUS3erobM3TppJmSlcw+5+fAd6Rd4BRDffLCbQwOnsE
T0c0bPwZcQPSr5bIT2lDa2yu4X5usQn/xj327rgW1cGbYQTtAxP0NqHzfPNf45Eu6o1eEeelZKDF
l5xHv7+f/WhLihuBYGPxQxegfj0CkPL/SEEVNWAE1bXnqBipbPr/Xm03yLl+/c3I1Rv92fBKLiha
qvrMw0UQnIuldM5wv/biNbyq4PIjxhakQQD6t9+BT7aVUrRQbEnHERG8ppARrreINzGsP9E1UC8z
lICtVixPMj/uT0XkyotAmb4X4gHYQpAb8xTjZScfunFE4vaDK7BSiv773RCUH/9MvWokaf/3335y
TixriqdbEehgP2yNSGGuT7kTDSNMhe6GypPG0NODlJzNjz4Qy/xOAX6lKrV6sjcpfVwhj6/fP6n0
fpdKv/5O1tZkrmKDvbnnATP0Yvzl7Qn1FwFZ5F7RODzdu8IjhRQAzmaRZE+n50HsZNgOpVbTCl0f
IK8TpTqHCviOK36zdWcvewP4DzYliFpiQRE4ituCcEKO1ZEdfiX7qCeEXR5uIYWs2DGRbd49hlQI
2B7dlW7aaGDPNHxM8MIweC/tSCBbOMgeirfrk0VGzlkHkEfzVZINQNfEM6sGwfZ6iOTPx6HN+prC
IKXAc0HokMgGDdOL8S/yqXIKAs+6R63OXQy2wWrH9kU3mR2oIQLXSh0TxovLcvaTBnPregXfKju4
h6T2h1NpQMwMztYhVGtjiD3Cwf4=

View File

@ -28712,3 +28712,46 @@ function enregistrerconsultationassureur()
}
});
}
async function envoyer_demande_reconnaissance_faciale() {
// alert("envoyer_demande_reconnaissance_faciale");
// return;
// Demande de confirmation multilingue
const isConfirm = await confirm_ebene_sweet(
"Confirmez-vous la validation?",
"Do you confirm validation?"
);
if (!isConfirm) {
return false;
}
try {
await $.ajax({
url: $("#racineWeb").val() + "Ajaxdetaildentisterie/valider/",
type: 'POST',
data: ''
});
alert_ebene(
"Demande envoyée!",
"Request sent!"
);
fiche_beneficiaire();
} catch (error) {
console.error("Erreur :", error);
}
}
function init_demande_reconnaissance_faciale() {
// alert("init_demande_reconnaissance_faciale");
// return;
// $("#idHtagcarte").val(idHtagcarte);
$("#telephoneAutre").focus();
$("#div_demande_reconnaissance_faciale").modal({backdrop: 'static', keyboard: false, show: true });
$("#div_demande_reconnaissance_faciale").modal("show");
}

View File

@ -1301,5 +1301,90 @@ public function getTarifActeAdherent($idAdherent)
$this->executerRequete($sql, array($idOtpprestation, $otpStatus, $user));
}
public function getVersionTagCarteEncours() {
$sql = 'SELECT versionTagCarte FROM societeuser LIMIT 1;';
$resultat = $this->executerRequete($sql);
$ligne = $resultat->fetch(PDO::FETCH_ASSOC);
return $ligne['versionTagCarte'];
}
public function getBeneficiaireTag($versionTagCarte, $codeEntite, $numeroBeneficiaireCarte, $tagUuid)
{
$sql = 'call sp_p_get_beneficiaire_tag(?, ?, ?, ?);';
$beneficiaire = $this->executerRequete($sql, array($versionTagCarte, $codeEntite, $numeroBeneficiaireCarte, $tagUuid));
return $beneficiaire;
}
public function demandereconnaissancefaciale($telephoneAutre)
{
$codeSociete = $_SESSION['p_codeSociete'];
$codePrestataire = $_SESSION['p_codePrestataire_C'];
$idBeneficiaire = $_SESSION['p_idBeneficiaire_C'];
$user = $_SESSION['p_login'];
$sql = 'call sp_p_demandereconnaissancefaciale(?, ?, ?, ?, ?);';
$this->executerRequete($sql, array($codeSociete, $codePrestataire, $idBeneficiaire, $telephoneAutre, $user));
}
public function checkdemandereconnaissancefaciale()
{
$codeSociete = $_SESSION['p_codeSociete'];
$codePrestataire = $_SESSION['p_codePrestataire_C'];
$idBeneficiaire = $_SESSION['p_idBeneficiaire_C'];
$sql = 'call sp_p_checkdemandereconnaissancefaciale(?, ?, ?);';
$resultat = $this->executerRequete($sql, array($codeSociete, $codePrestataire, $idBeneficiaire));
$ligne = $resultat->fetch(PDO::FETCH_ASSOC);
return $ligne;
}
public function fn_etat_demandereconnaissancefaciale()
{
$codeSociete = $_SESSION['p_codeSociete'];
$codePrestataire = $_SESSION['p_codePrestataire_C'];
$idBeneficiaire = $_SESSION['p_idBeneficiaire_C'];
$sql = 'select fn_etat_demandereconnaissancefaciale(?, ?, ?) as etatDemanderecFac';
$resultat = $this->executerRequete($sql, array($codeSociete, $codePrestataire, $idBeneficiaire));
$ligne = $resultat->fetch(PDO::FETCH_ASSOC);
return $ligne['etatDemanderecFac'];
}
public function fn_libelle_etat_demandereconnaissancefaciale()
{
$codeSociete = $_SESSION['p_codeSociete'];
$codePrestataire = $_SESSION['p_codePrestataire_C'];
$idBeneficiaire = $_SESSION['p_idBeneficiaire_C'];
$sql = 'select fn_libelle_etat_demandereconnaissancefaciale(?, ?, ?, ?) as libelleEtatDemanderecFac';
$resultat = $this->executerRequete($sql, array($codeSociete, $codePrestataire, $idBeneficiaire, $_SESSION['p_lang']));
$ligne = $resultat->fetch(PDO::FETCH_ASSOC);
return $ligne['libelleEtatDemanderecFac'];
}
public function fn_message_demandereconnaissancefaciale()
{
$codeSociete = $_SESSION['p_codeSociete'];
$codePrestataire = $_SESSION['p_codePrestataire_C'];
$idBeneficiaire = $_SESSION['p_idBeneficiaire_C'];
$sql = 'select fn_message_demandereconnaissancefaciale(?, ?, ?, ?) as messagePrestataireRecFac';
$resultat = $this->executerRequete($sql, array($codeSociete, $codePrestataire, $idBeneficiaire, $_SESSION['p_lang']));
$ligne = $resultat->fetch(PDO::FETCH_ASSOC);
return $ligne['messagePrestataireRecFac'];
}
}

1
Societes/envoyx/Ged/test Normal file
View File

@ -0,0 +1 @@
test

View File

@ -0,0 +1 @@
test

View File

@ -0,0 +1 @@
test

View File

@ -12,7 +12,7 @@
</style>
<span class="login100-form-title" style="font-family: Play-Bold; color:#e5e5e5; margin-top: 12px; margin-bottom:10px;">
Portail Prestataire centralisé dev01
Portail Prestataire
</span>
<?php if (isset($msgErreur) and $msgErreur>" "): ?>

View File

@ -113,7 +113,6 @@
$handle = null;
if($_SESSION['p_lienPhoto_C']>" " && $faceRegistered=="1")
{
// $lienPhoto = $_SESSION['p_dossierPhoto_C'].$_SESSION['p_dossierSociete'].'/Photos/'.$_SESSION['p_lienPhoto_C'];
$lienPhoto = $_SESSION['p_lienPhotoFace'].$_SESSION['p_lienPhoto_C'];
// Vérifie si le fichier existe en essayant de l'ouvrir
$handle = @fopen($lienPhoto, "r");
@ -138,6 +137,9 @@
"p_dossierPhoto_C" => $_SESSION['p_dossierPhoto_C'],
"p_dossierSociete" => $_SESSION['p_dossierSociete'],
"handle" => $handle,
"etatDemanderecFac" => $etatDemanderecFac,
"libelleEtatDemanderecFac" => $libelleEtatDemanderecFac,
"messagePrestataireRecFac" => $messagePrestataireRecFac,
)
);
*/
@ -154,6 +156,32 @@
$imgData = $_SESSION['p_photoAssureCrypte'];
?>
<!-- Recharger la page si photo vérifiée pour activer le bouton enregistrer -->
<?php if ($faceRegistered=="1" && in_array($etatDemanderecFac, ["1", "6"] , true)) :
$_SESSION['p_okId_face'] = "1";
?>
<script type="text/javascript">
face_confirmee = <?= $face_confirmee ?>;
if(face_confirmee!='1'){
// alert("On va activer le bouton enregistrer");
location.reload();
}
</script>
<?php endif; ?>
<!-- Si une demande est détectée -->
<?php if ($faceRegistered=="1" && in_array($etatDemanderecFac, ["0", "2", "4"] , true)) :
// echo "<br> demande est détectée";
?>
<script type="text/javascript">
// alert("On va recharger la page pour checker à nouveau");
setTimeout(function() {
location.reload();
}, 10000);
</script>
<?php endif; ?>
<INPUT class="sr-only datepicker" TYPE="text" id="debutMoisDecompte" NAME="debutMoisDecompte" value="<?= dateLang($_SESSION['p_debutMoisDecompte']) ?>" readonly>
<INPUT class="sr-only datepicker" TYPE="text" id="finMoisDecompte" name="finMoisDecompte">
@ -208,14 +236,45 @@
<?php if ($faceRegistered=="1") : ?>
<tr>
<td>
<button style='font-size:15pt; width:100%; font-weight:bold;' type="button" class="btn btn-primary" onClick="javascript:ebene_init_confirm_photo_face();">
<i class="fa fa-camera" aria-hidden="true"></i> &nbsp; &nbsp; <?= _("AUTHENTIFIER LA PHOTO DU PATIENT") ?>
</button>
<?php if ($face_confirmee!="1") : ?>
<button style='font-size:15pt; width:100%; font-weight:bold;' type="button" class="btn btn-primary" onClick="javascript:ebene_init_confirm_photo_face();">
<i class="fa fa-camera" aria-hidden="true"></i> &nbsp; &nbsp; <?= _("AUTHENTIFIER LA PHOTO DU PATIENT") ?>
</button>
<?php else: ?>
<button style='font-size:15pt; width:100%; font-weight:bold;' type="button" class="btn btn-primary" disabled >
<i class="fa fa-camera" aria-hidden="true"></i> &nbsp; &nbsp; <?= _("AUTHENTIFIER LA PHOTO DU PATIENT") ?>
</button>
<?php endif; ?>
</td>
<td>
<?php if ($face_confirmee!="1" && in_array($etatDemanderecFac, ["-1", "3", "4", "5"] , true)) : ?>
<button style='font-size:15pt; width:100%; font-weight:bold;' type="button" class="btn btn-info" onClick="javascript:init_demande_reconnaissance_faciale();">
<i class="fa fa-mobile" aria-hidden="true"></i> &nbsp; &nbsp; <?= _("ENVOYER UNE DEMANDE POUR AUTHENTIFICATION") ?>
</button>
<?php else: ?>
<button style='font-size:15pt; width:100%; font-weight:bold;' type="button" class="btn btn-info" disabled >
<i class="fa fa-mobile" aria-hidden="true"></i> &nbsp; &nbsp; <?= _("ENVOYER UNE DEMANDE POUR AUTHENTIFICATION") ?>
</button>
<?php endif; ?>
</td>
</tr>
<?php if($etatDemanderecFac>="0") : ?>
<tr>
<td colspan="2">
<marquee behavior="scroll" direction="left" scrollamount="15" style="background-color:red;color:white; font-weight:bold; font-size:14pt">
<?= $messagePrestataireRecFac; ?>
</marquee>
<td>
</tr>
<?php endif; ?>
<?php else: ?>
<tr>
<td>
<td colspan='2'>
<button style='font-size:15pt; width:100%; font-weight:bold;' type="button" class="btn btn-primary" onClick="javascript:ebene_init_photo_face();">
<i class="fa fa-floppy-disk" aria-hidden="true"></i> &nbsp; &nbsp;<?= _("ENREGISTRER LA PHOTO DU PATIENT") ?>
</button>
@ -790,6 +849,49 @@
</form>
<?php endif; ?>
<div id="div_demande_reconnaissance_faciale" class="modal fade" role="dialog">
<div class="modal-dialog" style="max-width: 50%;" role="document" data-bs-backdrop="static" data-bs-keyboard="false">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-bs-dismiss="modal">&times;</button>
<legend class="modal-title text-center"><?= _("Destinanaire de la demande de reconnaissance faciale");?></legend>
</div>
<div class="modal-body">
<form class="form-horizontal" action="Fichebeneficiaire/demandereconnaissancefaciale" method="post" style='font-size:10pt;'>
<table class="table table-responsive table-condensed" style='font-size:12pt;'>
<tbody>
<tr>
<td> <?= _("Destinanaire de la demande");?></td>
<td >
<INPUT class="form-control" name="telephoneDefaut" id="telephoneDefaut" value="<?= $_SESSION['p_telephonePortableAdherent_C'] ?>" readonly style='font-size:12pt;'>
</td>
</tr>
<tr>
<td> <?= _("Autre Destinanaire");?></td>
<td >
<INPUT class="form-control" name="telephoneAutre" id="telephoneAutre" value="<?= $_SESSION['p_telephonePortableAdherent_C'] ?>" required AUTOCOMPLETE="OFF" autofocus style='font-size:12pt;'>
</td>
</tr>
<tr>
<td colspan="2">
<input id="btn_enreg_dm" name="btn_enreg_dm" class = "form-control btn btn-primary" type="submit" value="<?= _("Envoyer la demande") ?>" style='font-size:12pt;'>
</td>
</tr>
</tbody>
</table>
</form>
</div>
<div class="modal-footer">
<button type="button" id="btn-fermer-modal" class="btn btn-default" data-bs-dismiss="modal"><?= _("Fermer") ?></button>
</div>
</div>
</div>
</div>
<?php if($faceActif=='1') : ?>
<?php include 'faceebene/ebenetraitementimage.php'; ?>
<?php endif; ?>

View File

@ -2,27 +2,329 @@
$this->titre = "INTER-SANTE - "._("Recherche du patient par carte") ;
?>
<style>
@import url('https://fonts.googleapis.com/css2?family=Rajdhani:wght@500;700&family=Exo+2:wght@400;600&display=swap');
/* ===== WRAPPER & BORDURE ANIMÉE ===== */
.scan-wrapper {
position: relative;
width: 100%;
max-width: 720px;
margin: 40px auto;
}
.scan-wrapper::before {
content: '';
position: absolute;
inset: -3px;
border-radius: 20px;
background: linear-gradient(135deg, #00c9ff, #0055a5, #00e5ff, #0055a5, #00c9ff);
background-size: 300% 300%;
animation: borderGlow 3s linear infinite;
z-index: 0;
}
.scan-wrapper.has-value::before {
background: linear-gradient(135deg, #00c853, #1b5e20, #69f0ae, #1b5e20, #00c853);
background-size: 300% 300%;
}
.scan-wrapper.has-error::before {
background: linear-gradient(135deg, #ff1744, #b71c1c, #ff6e6e, #b71c1c, #ff1744);
background-size: 300% 300%;
}
@keyframes borderGlow {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
/* ===== INNER CONTAINER ===== */
.scan-inner {
position: relative;
z-index: 1;
background: #050f20;
border-radius: 18px;
padding: 16px 20px 20px;
overflow: hidden;
}
/* Ligne de scan animée */
.scan-inner::after {
content: '';
position: absolute;
left: 0; right: 0;
height: 2px;
background: linear-gradient(90deg, transparent 0%, #00e5ff 30%, #ffffff 50%, #00e5ff 70%, transparent 100%);
animation: scanLine 2.5s ease-in-out infinite;
pointer-events: none;
z-index: 2;
opacity: 0.7;
}
@keyframes scanLine {
0% { top: 0%; opacity: 0; }
5% { opacity: 0.8; }
95% { opacity: 0.8; }
100% { top: 100%; opacity: 0; }
}
/* ===== COINS DÉCORATIFS ===== */
.scan-corner {
position: absolute;
width: 20px; height: 20px;
border-color: #00c9ff;
border-style: solid;
z-index: 4;
transition: border-color 0.3s;
}
.scan-corner.tl { top: 10px; left: 10px; border-width: 2px 0 0 2px; border-radius: 4px 0 0 0; }
.scan-corner.tr { top: 10px; right: 10px; border-width: 2px 2px 0 0; border-radius: 0 4px 0 0; }
.scan-corner.bl { bottom: 10px; left: 10px; border-width: 0 0 2px 2px; border-radius: 0 0 0 4px; }
.scan-corner.br { bottom: 10px; right: 10px; border-width: 0 2px 2px 0; border-radius: 0 0 4px 0; }
.scan-wrapper.has-value .scan-corner { border-color: #00c853; }
.scan-wrapper.has-error .scan-corner { border-color: #ff1744; }
/* ===== LABEL EN-TÊTE ===== */
.scan-label {
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
font-family: 'Exo 2', sans-serif;
font-size: 9.5pt;
font-weight: 600;
letter-spacing: 3px;
text-transform: uppercase;
color: rgba(0, 180, 230, 0.6);
margin-bottom: 6px;
}
.nfc-icon-pulse {
animation: pulse 2.2s ease-in-out infinite;
}
@keyframes pulse {
0%, 100% { opacity: 0.35; transform: scale(1); }
50% { opacity: 1; transform: scale(1.2); }
}
/* ===== CHAMP INPUT ===== */
#donneesCarte {
font-family: 'Rajdhani', monospace !important;
font-size: 24pt !important;
font-weight: 700;
height: 130px !important;
width: 100% !important;
text-align: center;
/* Données masquées (sécurité) */
color: transparent !important;
text-shadow: 0 0 10px rgba(0, 229, 255, 0.8) !important;
caret-color: #00e5ff;
/* Fond & bordure */
background: transparent !important;
border: none !important;
outline: none !important;
box-shadow: none !important;
letter-spacing: 4px;
position: relative;
z-index: 3;
transition: text-shadow 0.3s;
}
#donneesCarte::placeholder {
font-family: 'Exo 2', sans-serif !important;
font-size: 20pt !important;
font-weight: 600;
color: rgba(0, 210, 255, 0.85) !important;
text-shadow: 0 0 12px rgba(0, 210, 255, 0.5) !important;
letter-spacing: 1px;
}
#donneesCarte:focus::placeholder {
color: rgba(0, 210, 255, 0.55) !important;
text-shadow: 0 0 8px rgba(0, 210, 255, 0.3) !important;
}
/* État : données détectées */
#donneesCarte.reading {
text-shadow: 0 0 14px rgba(0, 200, 83, 0.9) !important;
animation: none !important;
}
/* ===== INDICATEUR DE LECTURE ===== */
.reading-indicator {
display: none;
text-align: center;
margin-top: 6px;
font-family: 'Exo 2', sans-serif;
font-size: 11pt;
font-weight: 600;
letter-spacing: 2px;
color: #00c853;
text-transform: uppercase;
animation: fadeInUp 0.3s ease;
}
.reading-indicator.active {
display: block;
}
@keyframes fadeInUp {
from { opacity: 0; transform: translateY(6px); }
to { opacity: 1; transform: translateY(0); }
}
/* ===== SPINNER WAIT ===== */
#div_wait_nfc {
min-height: 0;
transition: min-height 0.3s;
}
/* ===== MESSAGE ERREUR ===== */
.alert-danger {
max-width: 720px;
margin: 16px auto 0;
border-radius: 10px;
border: 1px solid #ff1744;
background: rgba(183, 28, 28, 0.15);
color: #ff6e6e;
text-align: center;
padding: 10px 16px;
}
</style>
<form id="frmrechercheparcarte" name="frmrechercheparcarte" method="post" action="Rechercheparcarte/index/">
<INPUT style='font-size:40pt; height: 50px; text-align: center;' class="form-control" TYPE="text" id="donneesCarte" name="donneesCarte" autofocus AUTOCOMPLETE="OFF" placeholder="<?= _("Veuillez scanner la carte NFC!")?>">
<input id="lancerrechercheparcarte" name="lancerrechercheparcarte" class="sr-only" type="submit" value="<?= _("Rechercher") ?>" >
<div class="scan-wrapper" id="scan-wrapper">
<div class="scan-inner">
<!-- Coins décoratifs -->
<div class="scan-corner tl"></div>
<div class="scan-corner tr"></div>
<div class="scan-corner bl"></div>
<div class="scan-corner br"></div>
<!-- Label -->
<div class="scan-label">
<svg class="nfc-icon-pulse" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#00c9ff" stroke-width="2" stroke-linecap="round">
<path d="M20 6a10 10 0 0 1 0 12"/>
<path d="M17 9a6 6 0 0 1 0 6"/>
<path d="M14 11.5a2 2 0 0 1 0 1"/>
<line x1="4" y1="12" x2="4.01" y2="12"/>
</svg>
INTER-SANTÉ &nbsp;·&nbsp; NFC / QR Code
</div>
<!-- Champ principal -->
<INPUT
class="form-control"
TYPE="text"
id="donneesCarte"
name="donneesCarte"
autofocus
AUTOCOMPLETE="OFF"
placeholder="<?= _("Veuillez scanner la carte NFC ou le QR code!")?>">
<!-- Indicateur -->
<div class="reading-indicator" id="reading-indicator">
<i class="fa fa-check-circle"></i>&nbsp;
<span id="indicator-text"><?= _("Carte détectée") ?></span>
</div>
</div>
</div>
<input id="lancerrechercheparcarte" name="lancerrechercheparcarte" class="sr-only" type="submit" value="<?= _("Rechercher") ?>">
</form>
<div id ="div_wait_nfc"> </div>
<?php if (isset($msgErreur) && $msgErreur>" "): ?>
<div class="alert alert-danger" style="height:38px; padding:5px; text-align: center;">
<H4><?= $msgErreur ?></H4>
</div>
<div id="div_wait_nfc"></div>
<?php if (isset($msgErreur) && $msgErreur > " "): ?>
<div class="alert alert-danger">
<H4><?= $msgErreur ?></H4>
</div>
<?php endif; ?>
<script>
document.getElementById('donneesCarte').addEventListener('change', function () {
if (this.value.length > 3) {
var div_wait_nfc = $('#div_wait_nfc');
div_wait_nfc.html('<div style="padding-top:80px; text-align:center; font-size:14px; color: #4caf50;"><span><i class="fa fa-spinner fa-spin fa-5x" >' + '</span></div>');
// alert("submit");
this.form.submit();
}
const inputField = document.getElementById('donneesCarte');
const indicator = document.getElementById('reading-indicator');
const indicatorText = document.getElementById('indicator-text');
const scanWrapper = document.getElementById('scan-wrapper');
// ===== SÉCURITÉ : empêcher copie/coller =====
inputField.addEventListener('contextmenu', e => e.preventDefault());
inputField.addEventListener('copy', e => e.preventDefault());
inputField.addEventListener('cut', e => e.preventDefault());
// ===== MAINTIEN DU FOCUS =====
inputField.addEventListener('blur', function() {
setTimeout(() => this.focus(), 10);
});
const focusInterval = setInterval(function() {
if (document.activeElement !== inputField && !document.hidden) {
inputField.focus();
}
}, 200);
document.addEventListener('keydown', function(e) {
if (!e.ctrlKey && !e.altKey && !e.metaKey && document.activeElement !== inputField) {
inputField.focus();
}
});
document.getElementById('frmrechercheparcarte').addEventListener('submit', function() {
clearInterval(focusInterval);
});
// ===== DÉTECTION DU TYPE =====
function detectScanType(value) {
return value.endsWith('qr') ? 'qr' : 'nfc';
}
// ===== FEEDBACK VISUEL À LA SAISIE =====
inputField.addEventListener('input', function() {
if (this.value.length > 0) {
this.classList.add('reading');
indicator.classList.add('active');
scanWrapper.classList.add('has-value');
scanWrapper.classList.remove('has-error');
const type = detectScanType(this.value);
indicatorText.textContent = type === 'qr'
? '<?= _("QR code détecté") ?>'
: '<?= _("Carte détectée") ?>';
} else {
this.classList.remove('reading');
indicator.classList.remove('active');
scanWrapper.classList.remove('has-value', 'has-error');
}
});
// ===== SOUMISSION AUTO =====
inputField.addEventListener('change', function() {
if (this.value.length > 3) {
const type = detectScanType(this.value);
const message = type === 'qr'
? '<?= _("Traitement du QR code...") ?>'
: '<?= _("Lecture de la carte...") ?>';
$('#div_wait_nfc').html(
'<div style="padding-top:60px; text-align:center; font-family:\'Exo 2\',sans-serif; color:#00c9ff;">'
+ '<i class="fa fa-spinner fa-spin fa-4x"></i>'
+ '<p style="margin-top:20px; font-size:13pt; letter-spacing:2px; text-transform:uppercase;">' + message + '</p>'
+ '</div>'
);
this.form.submit();
}
});
// ===== FOCUS INITIAL =====
window.addEventListener('load', () => inputField.focus());
document.addEventListener('DOMContentLoaded', () => inputField.focus());
// ===== Afficher erreur en rouge si présente =====
<?php if (isset($msgErreur) && $msgErreur > " "): ?>
scanWrapper.classList.add('has-error');
<?php endif; ?>
</script>

View File

@ -432,8 +432,18 @@
// $style = "background-color: #F5DF4D;";
$style = "background-color: $colorTests;";
$test = "MODE TEST";
error_reporting(E_ALL);
ini_set('display_errors', 1);
}
else
{
error_reporting(E_ALL & ~E_DEPRECATED & ~E_STRICT);
ini_set('display_errors', 0);
}
ini_set('log_errors', 1);
ini_set('error_log', __DIR__ . '/logs/error.log');
//var_dump($style);
?>
@ -474,8 +484,6 @@
<img src="<?= $_SESSION['p_lienLogo'] ?>"
alt="Profile"
style="max-height:40px;"
class="rounded-circle">
<span class="text-truncate d-inline-block" style="max-width:300px;">
<?=$companyDisplayName?>
</span>
@ -635,9 +643,29 @@
<input class="sr-only" type="text" id="nomSociete" name="nomSociete" value="<?= $_SESSION['p_nomSociete'] ?>">
<section class="section main-dashboard">
<div id="contenu">
<div id="div_test_gabarit">
</div>
<div id="div_test_gabarit">
<?php
/*
$err_report = ini_get('error_reporting');
$disp_err = ini_get('display_errors');
var_dump(
array(
// "codeGcAssureurDefaut" => $_SESSION['codeGcAssureurDefaut'],
// "codeGcAssureur_C" => $_SESSION['codeGcAssureur_C'],
// "dossierSociete" => $_SESSION['dossierSociete'],
// "bdTests" => $_SESSION['p_bdTests_C'],
// "err_report" => $err_report,
// "disp_err" => $disp_err,
)
);
*/
?>
<?= $contenu ?>
</div>
</section>
@ -889,7 +917,7 @@
<!--<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.css" integrity="sha512-3pIirOrwegjM6erE5gPSwkUzO+3cTjpnV9lexlNZqvupR64iZBnOOTiiLPb9M36zpMScbmUNIcHUqKD47M719g==" crossorigin="anonymous" referrerpolicy="no-referrer" />-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.js" integrity="sha512-VEd+nq25CkR676O+pLBnDW09R7VQX9Mdiij052gVCp5yVH3jGtH70Ho/UUv4mJDsEdTvqRCFZg0NKGiojGnUCw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="Js/fonctions.js?ver=2026.02.11.00"></script>
<script src="Js/fonctions.js?ver=2026.02.22.04"></script>
<script src="Bootstrap/js/bootstrap.min.js"></script>
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>

View File

@ -1,151 +0,0 @@
<?php
$_SESSION['p_messageFace'] = "";
?>
<div class="modal fade" id="pop_rec_faciale" role="dialog" data-backdrop="static" data-keyboard="false" >
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button id="btn_close_pop_rec_faciale" name="btn_close_pop_rec_faciale" type="button" class="close" data-bs-dismiss="modal" onclick="javascript:fiche_beneficiaire();"> <?= _("Fermer") ?> </button>
<h4 class="modal-title"> <?= _("RECONNAISSANCE FACIALE") ?> </h4>
</div>
<div class="modal-body">
<!-- Début ajout 25/09/20225 -->
<div class="row">
<?php include 'liveness.php'; ?>
</div>
<!-- <div id="div_ebene" hidden> -->
<div id="div_ebene">
<!-- Fin ajout 25/09/20225 -->
<table class="table table-responsive table-condensed">
<tbody>
<tr>
<td width="48%">
<button id="ebene_take_photo_face" name="ebene_take_photo_face" style='font-size:15pt;' type="button" class="form-control btn btn-primary" onclick="javascript:takephoto();"> <?= _("PRENDRE UNE PHOTO") ?> </button>
</td>
<td > </td>
<?php if ($faceRegistered=="1") : ?>
<td width="48%">
<button disabled id="ebene_confirmer_photo_face" name="ebene_confirmer_photo_face" style='font-size:15pt;' type="button" class="form-control btn btn-primary" onclick="javascript:ebene_confirmer_photo_face();"> <?= _("CONFIRMER LA PHOTO") ?> </button>
</td>
<?php endif; ?>
<?php if ($faceRegistered!="1") : ?>
<td width="48%">
<button disabled id="ebene_enregistrer_photo_face" name="ebene_enregistrer_photo_face" style='font-size:15pt;' type="button" class="form-control btn btn-primary" onclick="javascript:ebene_enregistrer_photo_face();"> <?= _("ENREGISTRER LA PHOTO") ?> </button>
</td>
<?php endif; ?>
</tr>
</tbody>
</table>
<div class="row">
<div class="col-6" >
<legend style="text-align:center" >Webcam</legend>
<video id="video_face" name="video_face" autoplay height="250" align="center"></video><br />
</div>
<div class="col-6" >
<legend style="text-align:center" >Photo</legend>
<img id="photo_face" name="photo_face" src="" />
<form id="form_face" name="form_face" enctype="multipart/form-data" method="post" action="Fichebeneficiaire/ebeneenregistrerface">
<INPUT class="sr-only" TYPE="text" id="compare_face" name="compare_face" value="<?= $faceRegistered ?>">
<INPUT class="sr-only" TYPE="text" id="del_face" name="del_face" value="0">
<INPUT class="image-tag" TYPE="hidden" id="image_face" name="image_face" >
</form>
</div>
</div>
<canvas id="canvas" name="canvas" style="display: none;" width="350" height="260"></canvas>
<?php if ($faceRegistered=="1") : ?>
<!--
<button disabled id="ebene_supprimer_photo_face" name="ebene_supprimer_photo_face" style='font-size:15pt;' type="button" class="form-control btn btn-danger" onclick="javascript:ebene_supprimer_photo_face();"> <?= _("SUPPRIMER LA PHOTO") ?> </button>
<span style='font-size:12pt;font-weight: bold;' ><?= _("Motif Suppression") ?> :</span> <INPUT disabled class="form-control" TYPE="text" id="motif" NAME="motif" style='font-size:12pt;font-weight: bold;' >
-->
<?php endif; ?>
<div id="message_face" name="message_face" >
<H2 style="background-color:yellow;">
<marquee behavior="scroll" direction="left" scrollamount="10"> </marquee>
</H2>
<INPUT class="sr-only" TYPE="text" id="photo_succes" name="photo_succes" value="0">
</div>
<div id="div_wait_face_ebene">
</div>
</div>
<script type="text/javascript">
var video = document.getElementById('video_face');
var canvas = document.getElementById('canvas');
var photo = document.getElementById('photo_face');
var image_face = document.getElementById('image_face');
navigator.getMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia || navigator.mediaDevices.getUserMedia || navigator.moxGetUserMedia;
if (navigator.mediaDevices.getUserMedia)
{
navigator.mediaDevices.getUserMedia({video: true })
.then(function (stream) {
video.srcObject = stream;
})
.catch(function (e) { alert(e.name + ": " + e.message); });
}
else
{
navigator.getMedia({ video: { mandatory: { maxWidth: 350, maxHeight: 260 } } }, function(stream) {
video.src = stream;
}, function(e) {
alert(e);
console.log("Failed!", e);
});
}
function takephoto() {
$('#message_face').html("");
$("#div_wait_face_ebene").html('');
// var ctx = canvas.getContext("2d").drawImage(video, 0, 0, 350, 260, 0, 0, 350, 260);
var ctx = canvas.getContext("2d").drawImage(video, 0, 0, 350, 260);
var data = canvas.toDataURL('image/jpeg');
// var data = canvas.toDataURL('image/jpeg', 0.7);
photo.setAttribute('src', data);
$("#image_face").val(data);
var faceRegistered = $("#faceRegistered").val();
$("#ebene_enregistrer_photo_face").enable();
if(faceRegistered=="1")
{
$("#ebene_confirmer_photo_face").enable();
$("#ebene_supprimer_photo_face").enable();
$("#motif").enable();
}
}
</script>
</div>
<div class="modal-footer">
<button id="close_poprec_faciane" name="close_poprec_faciane" type="button" class="btn btn-default" data-bs-dismiss="modal" onclick="javascript:fiche_beneficiaire();" > <?= _("Fermer") ?> </button>
</div>
</div>
</div>
</div>

View File

@ -1,139 +0,0 @@
<?php
$_SESSION['p_messageFace'] = "";
?>
<div class="modal fade" id="pop_rec_faciale" role="dialog" data-backdrop="static" data-keyboard="false" >
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button id="btn_close_pop_rec_faciale" name="btn_close_pop_rec_faciale" type="button" class="close" data-bs-dismiss="modal" onclick="javascript:fiche_beneficiaire();"> <?= _("Fermer") ?> </button>
<h4 class="modal-title"> <?= _("RECONNAISSANCE FACIALE") ?> </h4>
</div>
<div class="modal-body">
<table class="table table-responsive table-condensed">
<tbody>
<tr>
<td width="48%">
<button id="ebene_take_photo_face" name="ebene_take_photo_face" style='font-size:15pt;' type="button" class="form-control btn btn-primary" onclick="javascript:takephoto();"> <?= _("PRENDRE UNE PHOTO") ?> </button>
</td>
<td > </td>
<?php if ($faceRegistered=="1") : ?>
<td width="48%">
<button disabled id="ebene_confirmer_photo_face" name="ebene_confirmer_photo_face" style='font-size:15pt;' type="button" class="form-control btn btn-primary" onclick="javascript:ebene_confirmer_photo_face();"> <?= _("CONFIRMER LA PHOTO") ?> </button>
</td>
<?php endif; ?>
<?php if ($faceRegistered!="1") : ?>
<td width="48%">
<button disabled id="ebene_enregistrer_photo_face" name="ebene_enregistrer_photo_face" style='font-size:15pt;' type="button" class="form-control btn btn-primary" onclick="javascript:ebene_enregistrer_photo_face();"> <?= _("ENREGISTRER LA PHOTO") ?> </button>
</td>
<?php endif; ?>
</tr>
</tbody>
</table>
<div class="row">
<div class="col-6" >
<legend style="text-align:center" >Webcam</legend>
<video id="video_face" name="video_face" autoplay 350="450" height="250" align="center"></video><br />
</div>
<div class="col-6" >
<legend style="text-align:center" >Photo</legend>
<img id="photo_face" name="photo_face" src="" />
<form id="form_face" name="form_face" enctype="multipart/form-data" method="post" action="Fichebeneficiaire/ebeneenregistrerface">
<INPUT class="sr-only" TYPE="text" id="compare_face" name="compare_face" value="<?= $faceRegistered ?>">
<INPUT class="sr-only" TYPE="text" id="del_face" name="del_face" value="0">
<INPUT class="image-tag" TYPE="hidden" id="image_face" name="image_face" >
</form>
</div>
</div>
<canvas id="canvas" name="canvas" style="display: none;" width="350" height="260"></canvas>
<?php if ($faceRegistered=="1") : ?>
<!--
<button disabled id="ebene_supprimer_photo_face" name="ebene_supprimer_photo_face" style='font-size:15pt;' type="button" class="form-control btn btn-danger" onclick="javascript:ebene_supprimer_photo_face();"> <?= _("SUPPRIMER LA PHOTO") ?> </button>
<span style='font-size:12pt;font-weight: bold;' ><?= _("Motif Suppression") ?> :</span> <INPUT disabled class="form-control" TYPE="text" id="motif" NAME="motif" style='font-size:12pt;font-weight: bold;' >
-->
<?php endif; ?>
<div id="message_face" name="message_face" >
<H2 style="background-color:yellow;">
<marquee behavior="scroll" direction="left" scrollamount="10"> </marquee>
</H2>
<INPUT class="sr-only" TYPE="text" id="photo_succes" name="photo_succes" value="0">
</div>
<div id="div_wait_face_ebene">
</div>
<script type="text/javascript">
var video = document.getElementById('video_face');
var canvas = document.getElementById('canvas');
var photo = document.getElementById('photo_face');
var image_face = document.getElementById('image_face');
navigator.getMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia || navigator.mediaDevices.getUserMedia || navigator.moxGetUserMedia;
if (navigator.mediaDevices.getUserMedia)
{
navigator.mediaDevices.getUserMedia({video: true })
.then(function (stream) {
video.srcObject = stream;
})
.catch(function (e) { alert(e.name + ": " + e.message); });
}
else
{
navigator.getMedia({ video: { mandatory: { maxWidth: 350, maxHeight: 260 } } }, function(stream) {
video.src = stream;
}, function(e) {
alert(e);
console.log("Failed!", e);
});
}
function takephoto() {
$('#message_face').html("");
$("#div_wait_face_ebene").html('');
// var ctx = canvas.getContext("2d").drawImage(video, 0, 0, 350, 260, 0, 0, 350, 260);
var ctx = canvas.getContext("2d").drawImage(video, 0, 0, 350, 260);
var data = canvas.toDataURL('image/jpeg');
// var data = canvas.toDataURL('image/jpeg', 0.7);
photo.setAttribute('src', data);
$("#image_face").val(data);
var faceRegistered = $("#faceRegistered").val();
$("#ebene_enregistrer_photo_face").enable();
if(faceRegistered=="1")
{
$("#ebene_confirmer_photo_face").enable();
$("#ebene_supprimer_photo_face").enable();
$("#motif").enable();
}
}
</script>
</div>
<div class="modal-footer">
<button id="close_poprec_faciane" name="close_poprec_faciane" type="button" class="btn btn-default" data-bs-dismiss="modal" onclick="javascript:fiche_beneficiaire();" > <?= _("Fermer") ?> </button>
</div>
</div>
</div>
</div>

View File

@ -1,337 +0,0 @@
<style>
:root { font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif; }
/*body { margin: 0; background: #0f172a; color: #e2e8f0; }*/
header { padding: 16px 24px; background: #111827; display:flex; align-items:center; gap:12px; }
h1 { font-size: 18px; margin: 0; }
/*main { display:grid; grid-template-columns: 1fr 360px; gap: 16px; padding: 16px; }*/
.stage { position: relative; aspect-ratio: 16/9; background: #111827; border: 1px solid #1f2937; border-radius: 12px; overflow: hidden; }
/* video, canvas { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; } */
.panel { background: #111827; border: 1px solid #1f2937; border-radius: 12px; padding: 16px; }
.row { display:flex; justify-content: space-between; align-items:center; margin: 8px 0; }
.pill { display:inline-flex; align-items:center; gap:8px; padding:6px 10px; border-radius:999px; border:1px solid #1f2937; font-size:12px; }
.ok { color:#10b981; }
.warn { color:#f59e0b; }
.bad { color:#ef4444; }
button { background:#1f2937; color:#e5e7eb; border:1px solid #374151; border-radius:10px; padding:10px 12px; cursor:pointer; }
button:disabled { opacity:.5; cursor:not-allowed; }
small { color:#94a3b8; }
.meter { height: 8px; border-radius: 999px; background:#0b1220; border:1px solid #1f2937; overflow:hidden; }
.meter > div { height: 100%; background: linear-gradient(90deg,#22c55e,#16a34a); width:0%; }
.grid { display:grid; grid-template-columns: 1fr 1fr; gap:8px; }
.kpi { background:#0b1220; border:1px solid #1f2937; border-radius:10px; padding:10px; }
code { background:#0b1220; padding:2px 6px; border-radius:6px; }
</style>
<header>
<h1>Détection de vivacité (Liveness)</h1>
<div class="pill"><span>🎥</span><span id="camStatus">Caméra : inactif</span></div>
<div class="pill"><span>🧠</span><span id="mpStatus">Modèle : non chargé</span></div>
</header>
<div class="col-6" >
<section class="stage">
<video id="video" playsinline muted height="250"></video>
<canvas id="overlay"></canvas>
</section>
</div>
<div class="col-6" >
<div class="row" style="margin-bottom:8px">
<button id="btnStart">Démarrer</button>
<button class="sr-only" id="btnStop" disabled>Arrêter</button>
</div>
<div class="row">
<strong>Statut vivacité</strong>
<span id="liveBadge" class="pill bad">Non vérifié</span>
</div>
<div class="meter" style="margin:8px 0 16px">
<div id="liveMeter"></div>
</div>
<div class="grid">
<div class="kpi"><div>Clignements</div><div id="blinkCount" style="font-size:22px">0</div><small>EAR&lt;seuil</small></div>
<div class="kpi"><div>Mouvements tête</div><div id="headMoves" style="font-size:22px">0</div><small>yaw/roll Δ</small></div>
<div class="kpi"><div>Confiance visage</div><div id="faceScore" style="font-size:22px">0.00</div><small>presence score</small></div>
<div class="kpi"><div>FPS</div><div id="fps" style="font-size:22px">0</div><small>approx</small></div>
</div>
<!--
<div id="blinkCount" style="font-size:22px">0</div>
<div id="headMoves" style="font-size:22px">0</div>
<div id="faceScore" style="font-size:22px">0.00</div>
<div id="fps" style="font-size:22px">0</div>
-->
<div class="sr-only">
<input id="earThresh" type="number" min="0" max="1" step="0.01" value="0.21">
<input id="closedFrames" type="number" min="1" max="15" step="1" value="3">
<input id="moveThresh" type="number" min="0" max="30" step="0.5" value="6">
<!-- <input id="proofNeeded" type="number" min="1" max="10" step="1" value="3"> -->
<input id="proofNeeded" type="number" min="1" max="10" step="1" value="2">
</div>
</div>
<!-- </main> -->
<!-- MediaPipe Tasks Vision (web) -->
<script type="module">
// -- Dépendances MediaPipe Tasks Vision
import {
FilesetResolver,
FaceLandmarker,
DrawingUtils
} from "https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision/vision_bundle.js";
// URLs modèles (hébergés par Google)
const MP_FACE_TASK = "https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/1/face_landmarker.task";
// Références DOM
const video = document.getElementById('video');
const canvas = document.getElementById('overlay');
const ctx = canvas.getContext('2d');
const btnStart = document.getElementById('btnStart');
const btnStop = document.getElementById('btnStop');
const camStatus = document.getElementById('camStatus');
const mpStatus = document.getElementById('mpStatus');
const blinkCountEl = document.getElementById('blinkCount');
const headMovesEl = document.getElementById('headMoves');
const faceScoreEl = document.getElementById('faceScore');
const fpsEl = document.getElementById('fps');
const liveBadge = document.getElementById('liveBadge');
const liveMeter = document.getElementById('liveMeter');
const earThreshEl = document.getElementById('earThresh');
const closedFramesEl= document.getElementById('closedFrames');
const moveThreshEl = document.getElementById('moveThresh');
const proofNeededEl = document.getElementById('proofNeeded');
// État
let running = false;
let faceLandmarker; // modèle
let lastVideoTime = -1;
let rafId = null;
// Métriques liveness
let blinkCount = 0;
let closedConsec = 0;
let lastEAR = 1;
let headMoves = 0;
let lastYaw = null, lastRoll = null;
let facePresenceScore = 0;
let livenessScore = 0; // somme pondérée des preuves
let lastFpsT = performance.now();
let frames = 0;
// Indices MediaPipe FaceMesh pour calcul EAR (6 points par œil)
// Schéma: EAR = (||p2-p6|| + ||p3-p5||) / (2*||p1-p4||)
const LEFT_EYE = [33,160,158,133,153,144];
const RIGHT_EYE = [263,387,385,362,380,373];
const distance = (a,b)=> Math.hypot(a.x-b.x, a.y-b.y);
function eyeEAR(landmarks, idxs){
const [p1,p2,p3,p4,p5,p6] = idxs.map(i=>landmarks[i]);
const vert = distance(p2,p6) + distance(p3,p5);
const horiz= distance(p1,p4)*2;
return horiz>0 ? (vert/horiz) : 0;
}
function estimateYawRoll(landmarks){
// yaw ~ orientation horizontale via ligne yeux, roll ~ inclinaison de la tête
const left = avgPoint([33,133].map(i=>landmarks[i]));
const right= avgPoint([263,362].map(i=>landmarks[i]));
const dx = right.x - left.x;
const dy = right.y - left.y;
const roll = -rad2deg(Math.atan2(dy, dx));
// yaw approximé par asymétrie distance nez-centres yeux
const nose = landmarks[1] || landmarks[4];
const midEye = {x:(left.x+right.x)/2, y:(left.y+right.y)/2};
const yaw = rad2deg(Math.atan2(nose.x - midEye.x, 0.5)); // pseudo-yaw basé sur décalage nez
return {yaw, roll};
}
const rad2deg = r=> r*180/Math.PI;
const avgPoint = (pts)=>({x: pts.reduce((s,p)=>s+p.x,0)/pts.length, y: pts.reduce((s,p)=>s+p.y,0)/pts.length});
function updateLiveUI(){
blinkCountEl.textContent = String(blinkCount);
headMovesEl.textContent = String(headMoves);
faceScoreEl.textContent = facePresenceScore.toFixed(2);
// Score simple: 1 point par clignement (max 2), 1 point par move tête (max 2), +1 si présence stable (>0.5)
const maxBlinkPoints = Math.min(blinkCount, 2);
const maxMovePoints = Math.min(headMoves, 2);
const presencePoint = facePresenceScore > 0.5 ? 1 : 0;
livenessScore = maxBlinkPoints + maxMovePoints + presencePoint;
const proofNeeded = Number(proofNeededEl.value);
const pct = Math.min(100, Math.round(100*livenessScore/Math.max(1,proofNeeded)));
liveMeter.style.width = pct + '%';
const div_ebene = document.getElementById("div_ebene");
if(livenessScore >= proofNeeded){
liveBadge.className = 'pill ok';
liveBadge.textContent = 'Vivant confirmé';
// alert('Vivant confirmé');
stop();
// $("#div_ebene").fadeIn();
// $("#div_ebene").show();
// div_ebene.style.display = "block";
// div_ebene.classList.remove("hidden");
} else if (livenessScore>0){
liveBadge.className = 'pill warn';
liveBadge.textContent = 'Indices de vivacité';
} else {
liveBadge.className = 'pill bad';
liveBadge.textContent = 'Non vérifié';
}
}
async function loadModel(){
mpStatus.textContent = 'Modèle : chargement…';
const filesetResolver = await FilesetResolver.forVisionTasks(
// wasm path (CDN jsDelivr) — laisse MediaPipe gérer les dépendances
'https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.11/wasm'
);
faceLandmarker = await FaceLandmarker.createFromOptions(filesetResolver,{
baseOptions: { modelAssetPath: MP_FACE_TASK },
runningMode: 'VIDEO',
numFaces: 1,
outputFaceBlendshapes: false,
outputFacialTransformationMatrixes: true
});
mpStatus.textContent = 'Modèle : prêt';
}
async function start(){
try{
btnStart.disabled = true;
await loadModel();
const stream = await navigator.mediaDevices.getUserMedia({
video: { facingMode: 'user', width: {ideal: 1280}, height:{ideal:720} },
audio: false
});
video.srcObject = stream;
await video.play();
camStatus.textContent = 'Caméra : OK';
running = true;
canvas.width = video.videoWidth || 1280;
canvas.height= video.videoHeight|| 720;
btnStop.disabled = false;
lastVideoTime = -1;
loop();
}catch(err){
console.error(err);
camStatus.textContent = 'Caméra : échec ('+ (err?.name||'Erreur') +')';
btnStart.disabled = false;
}
}
function stop(){
running = false;
if(rafId) cancelAnimationFrame(rafId);
const stream = video.srcObject;
if(stream){
stream.getTracks().forEach(t=>t.stop());
}
video.srcObject = null;
btnStart.disabled = false;
btnStop.disabled = true;
camStatus.textContent = 'Caméra : inactif';
mpStatus.textContent = faceLandmarker ? 'Modèle : prêt' : 'Modèle : non chargé';
}
function drawLandmarks(landmarks){
ctx.clearRect(0,0,canvas.width, canvas.height);
const drawUtils = new DrawingUtils(ctx);
// Points clés yeux + traits simples
const eyePts = [...LEFT_EYE, ...RIGHT_EYE];
drawUtils.drawLandmarks(landmarks.filter((_,i)=> eyePts.includes(i)), {lineWidth: 2, color: '#22c55e', radius: 2});
}
function loop(){
if(!running) return;
const startT = performance.now();
const nowVideoTime = video.currentTime;
if(nowVideoTime !== lastVideoTime){
lastVideoTime = nowVideoTime;
const res = faceLandmarker.detectForVideo(video, performance.now());
const faces = res.faceLandmarks || [];
if(faces.length){
const lm = faces[0];
drawLandmarks(lm);
// EAR pour chaque œil
const earL = eyeEAR(lm, LEFT_EYE);
const earR = eyeEAR(lm, RIGHT_EYE);
const ear = (earL + earR)/2;
const earThresh = Number(earThreshEl.value);
const closedNeeded = Number(closedFramesEl.value);
if(ear < earThresh){
closedConsec++;
} else {
if(closedConsec >= closedNeeded){
blinkCount++;
}
closedConsec = 0;
}
// Head movement (yaw/roll change)
const {yaw, roll} = estimateYawRoll(lm);
const moveThresh = Number(moveThreshEl.value);
if(lastYaw!==null && lastRoll!==null){
const dYaw = Math.abs(yaw - lastYaw);
const dRoll= Math.abs(roll - lastRoll);
if(dYaw > moveThresh || dRoll > moveThresh){
headMoves++;
}
}
lastYaw = yaw; lastRoll = roll;
// Présence visage (proxy via nb de points vs bruit)
facePresenceScore = 0.7; // simplifié: présent
} else {
ctx.clearRect(0,0,canvas.width, canvas.height);
facePresenceScore = 0.0;
}
// MAJ UI
updateLiveUI();
}
// FPS approx
frames++;
const t = performance.now();
if(t - lastFpsT > 1000){
fpsEl.textContent = String(frames);
frames = 0; lastFpsT = t;
}
rafId = requestAnimationFrame(loop);
const endT = performance.now();
// Option: utiliser endT-startT si besoin de profiler
}
btnStart.addEventListener('click', start);
btnStop.addEventListener('click', stop);
// Conseil : demander permission caméra immédiatement (optionnel)
// navigator.mediaDevices.getUserMedia({video:true}).then(s=>s.getTracks().forEach(t=>t.stop()));
</script>

View File

@ -1,321 +0,0 @@
<style>
:root { font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif; }
body { margin: 0; background: #0f172a; color: #e2e8f0; }
header { padding: 16px 24px; background: #111827; display:flex; align-items:center; gap:12px; }
h1 { font-size: 18px; margin: 0; }
main { display:grid; grid-template-columns: 1fr 360px; gap: 16px; padding: 16px; }
.stage { position: relative; aspect-ratio: 16/9; background: #111827; border: 1px solid #1f2937; border-radius: 12px; overflow: hidden; }
video, canvas { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.panel { background: #111827; border: 1px solid #1f2937; border-radius: 12px; padding: 16px; }
.row { display:flex; justify-content: space-between; align-items:center; margin: 8px 0; }
.pill { display:inline-flex; align-items:center; gap:8px; padding:6px 10px; border-radius:999px; border:1px solid #1f2937; font-size:12px; }
.ok { color:#10b981; }
.warn { color:#f59e0b; }
.bad { color:#ef4444; }
button { background:#1f2937; color:#e5e7eb; border:1px solid #374151; border-radius:10px; padding:10px 12px; cursor:pointer; }
button:disabled { opacity:.5; cursor:not-allowed; }
small { color:#94a3b8; }
.meter { height: 8px; border-radius: 999px; background:#0b1220; border:1px solid #1f2937; overflow:hidden; }
.meter > div { height: 100%; background: linear-gradient(90deg,#22c55e,#16a34a); width:0%; }
.grid { display:grid; grid-template-columns: 1fr 1fr; gap:8px; }
.kpi { background:#0b1220; border:1px solid #1f2937; border-radius:10px; padding:10px; }
code { background:#0b1220; padding:2px 6px; border-radius:6px; }
</style>
<header>
<h1>Détection de vivacité (Liveness)</h1>
<div class="pill"><span>🎥</span><span id="camStatus">Caméra : inactif</span></div>
<div class="pill"><span>🧠</span><span id="mpStatus">Modèle : non chargé</span></div>
</header>
<main>
<section class="stage">
<video id="video" playsinline muted></video>
<canvas id="overlay"></canvas>
</section>
<aside class="panel">
<div class="row" style="margin-bottom:8px">
<button id="btnStart">Démarrer</button>
<button id="btnStop" disabled>Arrêter</button>
</div>
<div class="row">
<strong>Statut vivacité</strong>
<span id="liveBadge" class="pill bad">Non vérifié</span>
</div>
<div class="meter" style="margin:8px 0 16px">
<div id="liveMeter"></div>
</div>
<div class="grid">
<div class="kpi"><div>Clignements</div><div id="blinkCount" style="font-size:22px">0</div><small>EAR&lt;seuil</small></div>
<div class="kpi"><div>Mouvements tête</div><div id="headMoves" style="font-size:22px">0</div><small>yaw/roll Δ</small></div>
<div class="kpi"><div>Confiance visage</div><div id="faceScore" style="font-size:22px">0.00</div><small>presence score</small></div>
<div class="kpi"><div>FPS</div><div id="fps" style="font-size:22px">0</div><small>approx</small></div>
</div>
<hr style="border-color:#1f2937; margin:16px 0" />
<input class="sr-only" id="earThresh" type="number" min="0" max="1" step="0.01" value="0.21">
<input class="sr-only" id="closedFrames" type="number" min="1" max="15" step="1" value="3">
<input class="sr-only" id="moveThresh" type="number" min="0" max="30" step="0.5" value="6">
<input class="sr-only" id="proofNeeded" type="number" min="1" max="10" step="1" value="3">
<hr style="border-color:#1f2937; margin:16px 0" />
<p><strong>Conseils :</strong> placez-vous face caméra, éclairez le visage, clignez des yeux et tournez légèrement la tête.</p>
</aside>
</main>
<!-- MediaPipe Tasks Vision (web) -->
<script type="module">
// -- Dépendances MediaPipe Tasks Vision
import {
FilesetResolver,
FaceLandmarker,
DrawingUtils
} from "https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision/vision_bundle.js";
// URLs modèles (hébergés par Google)
const MP_FACE_TASK = "https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/1/face_landmarker.task";
// Références DOM
const video = document.getElementById('video');
const canvas = document.getElementById('overlay');
const ctx = canvas.getContext('2d');
const btnStart = document.getElementById('btnStart');
const btnStop = document.getElementById('btnStop');
const camStatus = document.getElementById('camStatus');
const mpStatus = document.getElementById('mpStatus');
const blinkCountEl = document.getElementById('blinkCount');
const headMovesEl = document.getElementById('headMoves');
const faceScoreEl = document.getElementById('faceScore');
const fpsEl = document.getElementById('fps');
const liveBadge = document.getElementById('liveBadge');
const liveMeter = document.getElementById('liveMeter');
const earThreshEl = document.getElementById('earThresh');
const closedFramesEl= document.getElementById('closedFrames');
const moveThreshEl = document.getElementById('moveThresh');
const proofNeededEl = document.getElementById('proofNeeded');
// État
let running = false;
let faceLandmarker; // modèle
let lastVideoTime = -1;
let rafId = null;
// Métriques liveness
let blinkCount = 0;
let closedConsec = 0;
let lastEAR = 1;
let headMoves = 0;
let lastYaw = null, lastRoll = null;
let facePresenceScore = 0;
let livenessScore = 0; // somme pondérée des preuves
let lastFpsT = performance.now();
let frames = 0;
// Indices MediaPipe FaceMesh pour calcul EAR (6 points par œil)
// Schéma: EAR = (||p2-p6|| + ||p3-p5||) / (2*||p1-p4||)
const LEFT_EYE = [33,160,158,133,153,144];
const RIGHT_EYE = [263,387,385,362,380,373];
const distance = (a,b)=> Math.hypot(a.x-b.x, a.y-b.y);
function eyeEAR(landmarks, idxs){
const [p1,p2,p3,p4,p5,p6] = idxs.map(i=>landmarks[i]);
const vert = distance(p2,p6) + distance(p3,p5);
const horiz= distance(p1,p4)*2;
return horiz>0 ? (vert/horiz) : 0;
}
function estimateYawRoll(landmarks){
// yaw ~ orientation horizontale via ligne yeux, roll ~ inclinaison de la tête
const left = avgPoint([33,133].map(i=>landmarks[i]));
const right= avgPoint([263,362].map(i=>landmarks[i]));
const dx = right.x - left.x;
const dy = right.y - left.y;
const roll = -rad2deg(Math.atan2(dy, dx));
// yaw approximé par asymétrie distance nez-centres yeux
const nose = landmarks[1] || landmarks[4];
const midEye = {x:(left.x+right.x)/2, y:(left.y+right.y)/2};
const yaw = rad2deg(Math.atan2(nose.x - midEye.x, 0.5)); // pseudo-yaw basé sur décalage nez
return {yaw, roll};
}
const rad2deg = r=> r*180/Math.PI;
const avgPoint = (pts)=>({x: pts.reduce((s,p)=>s+p.x,0)/pts.length, y: pts.reduce((s,p)=>s+p.y,0)/pts.length});
function updateLiveUI(){
blinkCountEl.textContent = String(blinkCount);
headMovesEl.textContent = String(headMoves);
faceScoreEl.textContent = facePresenceScore.toFixed(2);
// Score simple: 1 point par clignement (max 2), 1 point par move tête (max 2), +1 si présence stable (>0.5)
const maxBlinkPoints = Math.min(blinkCount, 2);
const maxMovePoints = Math.min(headMoves, 2);
const presencePoint = facePresenceScore > 0.5 ? 1 : 0;
livenessScore = maxBlinkPoints + maxMovePoints + presencePoint;
const proofNeeded = Number(proofNeededEl.value);
const pct = Math.min(100, Math.round(100*livenessScore/Math.max(1,proofNeeded)));
liveMeter.style.width = pct + '%';
if(livenessScore >= proofNeeded){
liveBadge.className = 'pill ok';
liveBadge.textContent = 'Vivant confirmé';
} else if (livenessScore>0){
liveBadge.className = 'pill warn';
liveBadge.textContent = 'Indices de vivacité';
} else {
liveBadge.className = 'pill bad';
liveBadge.textContent = 'Non vérifié';
}
}
async function loadModel(){
mpStatus.textContent = 'Modèle : chargement…';
const filesetResolver = await FilesetResolver.forVisionTasks(
// wasm path (CDN jsDelivr) — laisse MediaPipe gérer les dépendances
'https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.11/wasm'
);
faceLandmarker = await FaceLandmarker.createFromOptions(filesetResolver,{
baseOptions: { modelAssetPath: MP_FACE_TASK },
runningMode: 'VIDEO',
numFaces: 1,
outputFaceBlendshapes: false,
outputFacialTransformationMatrixes: true
});
mpStatus.textContent = 'Modèle : prêt';
}
async function start(){
try{
btnStart.disabled = true;
await loadModel();
const stream = await navigator.mediaDevices.getUserMedia({
video: { facingMode: 'user', width: {ideal: 1280}, height:{ideal:720} },
audio: false
});
video.srcObject = stream;
await video.play();
camStatus.textContent = 'Caméra : OK';
running = true;
canvas.width = video.videoWidth || 1280;
canvas.height= video.videoHeight|| 720;
btnStop.disabled = false;
lastVideoTime = -1;
loop();
}catch(err){
console.error(err);
camStatus.textContent = 'Caméra : échec ('+ (err?.name||'Erreur') +')';
btnStart.disabled = false;
}
}
function stop(){
running = false;
if(rafId) cancelAnimationFrame(rafId);
const stream = video.srcObject;
if(stream){
stream.getTracks().forEach(t=>t.stop());
}
video.srcObject = null;
btnStart.disabled = false;
btnStop.disabled = true;
camStatus.textContent = 'Caméra : inactif';
mpStatus.textContent = faceLandmarker ? 'Modèle : prêt' : 'Modèle : non chargé';
}
function drawLandmarks(landmarks){
ctx.clearRect(0,0,canvas.width, canvas.height);
const drawUtils = new DrawingUtils(ctx);
// Points clés yeux + traits simples
const eyePts = [...LEFT_EYE, ...RIGHT_EYE];
drawUtils.drawLandmarks(landmarks.filter((_,i)=> eyePts.includes(i)), {lineWidth: 2, color: '#22c55e', radius: 2});
}
function loop(){
if(!running) return;
const startT = performance.now();
const nowVideoTime = video.currentTime;
if(nowVideoTime !== lastVideoTime){
lastVideoTime = nowVideoTime;
const res = faceLandmarker.detectForVideo(video, performance.now());
const faces = res.faceLandmarks || [];
if(faces.length){
const lm = faces[0];
drawLandmarks(lm);
// EAR pour chaque œil
const earL = eyeEAR(lm, LEFT_EYE);
const earR = eyeEAR(lm, RIGHT_EYE);
const ear = (earL + earR)/2;
const earThresh = Number(earThreshEl.value);
const closedNeeded = Number(closedFramesEl.value);
if(ear < earThresh){
closedConsec++;
} else {
if(closedConsec >= closedNeeded){
blinkCount++;
}
closedConsec = 0;
}
// Head movement (yaw/roll change)
const {yaw, roll} = estimateYawRoll(lm);
const moveThresh = Number(moveThreshEl.value);
if(lastYaw!==null && lastRoll!==null){
const dYaw = Math.abs(yaw - lastYaw);
const dRoll= Math.abs(roll - lastRoll);
if(dYaw > moveThresh || dRoll > moveThresh){
headMoves++;
}
}
lastYaw = yaw; lastRoll = roll;
// Présence visage (proxy via nb de points vs bruit)
facePresenceScore = 0.7; // simplifié: présent
} else {
ctx.clearRect(0,0,canvas.width, canvas.height);
facePresenceScore = 0.0;
}
// MAJ UI
updateLiveUI();
}
// FPS approx
frames++;
const t = performance.now();
if(t - lastFpsT > 1000){
fpsEl.textContent = String(frames);
frames = 0; lastFpsT = t;
}
rafId = requestAnimationFrame(loop);
const endT = performance.now();
// Option: utiliser endT-startT si besoin de profiler
}
btnStart.addEventListener('click', start);
btnStop.addEventListener('click', stop);
// Conseil : demander permission caméra immédiatement (optionnel)
// navigator.mediaDevices.getUserMedia({video:true}).then(s=>s.getTracks().forEach(t=>t.stop()));
</script>
</body>
</html>

File diff suppressed because one or more lines are too long