351 lines
11 KiB
PHP
Executable File
351 lines
11 KiB
PHP
Executable File
<?php
|
||
require_once 'Framework/Controleur.php';
|
||
require_once 'Modele/Societeusercentral.php';
|
||
require_once 'Modele/Menuvueutilisateur.php';
|
||
|
||
class ControleurTesterreconnaissancefaciale extends Controleur {
|
||
private $menuvue;
|
||
private $societeusercentral;
|
||
|
||
public function __construct()
|
||
{
|
||
$this->menuvue = new Menuvueutilisateur();
|
||
$this->menuvue->getMenuVue('Testerreconnaissancefaciale');
|
||
$this->societeusercentral = new societeusercentral();
|
||
}
|
||
public function index()
|
||
{
|
||
$codeSociete = $_SESSION['codeSociete'];
|
||
// $paramreconnaissancefaciale = $this->societeusercentral->getSocieteusersReconnaissanceFaciale($codeSociete);
|
||
// $this->genererVue(array('paramreconnaissancefaciale' => $paramreconnaissancefaciale));
|
||
$this->genererVue();
|
||
}
|
||
|
||
|
||
public function diditverifyandmatch(
|
||
string $apiKey,
|
||
string $selfie,
|
||
string $reference,
|
||
float $minLiveScore = 0.80, // ex: 0.80 (=80%) liveness pass
|
||
float $minFaceScore = 75.0 // ex: 75/100 face match pass
|
||
): array {
|
||
// 1) Passive Liveness
|
||
$livePayload = buildImagePayload($selfie, 'image'); // 'image' ou 'image_base64'
|
||
$liveResp = diditpostjson(
|
||
'https://verification.didit.me/v2/passive-liveness/',
|
||
$apiKey,
|
||
$livePayload
|
||
);
|
||
$liveScore = $liveResp['liveness']['score'] ?? null; // valeur typique 0..1
|
||
$liveStatus = $liveResp['liveness']['status'] ?? null; // e.g. Approved/Rejected/In Review
|
||
|
||
if (!is_numeric($liveScore)) {
|
||
throw new RuntimeException('Réponse Liveness invalide: score manquant');
|
||
}
|
||
if ($liveScore < $minLiveScore || (is_string($liveStatus) && stripos($liveStatus, 'rejected') !== false)) {
|
||
return [
|
||
'success' => false,
|
||
'stage' => 'liveness',
|
||
'reason' => 'fail_threshold',
|
||
'details' => [
|
||
'score' => $liveScore,
|
||
'status' => $liveStatus,
|
||
'min_required' => $minLiveScore,
|
||
],
|
||
];
|
||
}
|
||
|
||
// 2) Face Match 1:1 (selfie validé vs référence)
|
||
$matchPayload = buildImagePayload($selfie, 'source', true) +
|
||
buildImagePayload($reference, 'target', true);
|
||
$matchResp = diditpostjson(
|
||
'https://verification.didit.me/v2/face-match/',
|
||
$apiKey,
|
||
$matchPayload
|
||
);
|
||
$faceScore = $matchResp['face_match']['score'] ?? null; // 0..100
|
||
$faceStatus = $matchResp['face_match']['status'] ?? null; // Approved/Rejected/In Review
|
||
|
||
$passed = is_numeric($faceScore) && $faceScore >= $minFaceScore &&
|
||
!(is_string($faceStatus) && stripos($faceStatus, 'rejected') !== false);
|
||
|
||
return [
|
||
'success' => $passed,
|
||
'stage' => 'face_match',
|
||
'decision_threshold' => $minFaceScore,
|
||
'liveness' => [
|
||
'score' => $liveScore,
|
||
'status' => $liveStatus,
|
||
],
|
||
'face_match' => [
|
||
'score' => $faceScore,
|
||
'status' => $faceStatus,
|
||
'warnings' => $matchResp['face_match']['warnings'] ?? [],
|
||
],
|
||
'raw' => [
|
||
'liveness' => $liveResp,
|
||
'face_match' => $matchResp,
|
||
],
|
||
];
|
||
}
|
||
|
||
/* ---------- Helpers ---------- */
|
||
|
||
public function diditpostjson(string $url, string $apiKey, array $payload): array {
|
||
$ch = curl_init($url);
|
||
curl_setopt_array($ch, [
|
||
CURLOPT_POST => true,
|
||
CURLOPT_RETURNTRANSFER => true,
|
||
CURLOPT_HTTPHEADER => [
|
||
'Accept: application/json',
|
||
'Content-Type: application/json',
|
||
'x-api-key: ' . $apiKey, // Auth Didit
|
||
],
|
||
CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_SLASHES),
|
||
CURLOPT_TIMEOUT => 60,
|
||
]);
|
||
$raw = curl_exec($ch);
|
||
$err = curl_error($ch);
|
||
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
|
||
curl_close($ch);
|
||
|
||
if ($err) {
|
||
throw new RuntimeException("Erreur cURL: $err");
|
||
}
|
||
if ($status < 200 || $status >= 300) {
|
||
throw new RuntimeException("HTTP $status: $raw");
|
||
}
|
||
$json = json_decode($raw, true);
|
||
if (!is_array($json)) {
|
||
throw new RuntimeException("JSON invalide: $raw");
|
||
}
|
||
return $json;
|
||
}
|
||
|
||
/**
|
||
* Construit le payload attendu:
|
||
* - si $prefix='image' (liveness), retourne ['image' | 'image_base64' => ...]
|
||
* - sinon pour Face Match: ['{prefix}_image' | '{prefix}_image_base64' => ...]
|
||
*/
|
||
public function buildImagePayload(string $val, string $prefix, bool $forMatch=false): array {
|
||
// URL ?
|
||
if (preg_match('~^https?://~i', $val)) {
|
||
$key = $forMatch ? "{$prefix}_image" : 'image';
|
||
return [$key => $val];
|
||
}
|
||
// Fichier local ?
|
||
if (is_file($val)) {
|
||
$bin = file_get_contents($val);
|
||
if ($bin === false) {
|
||
throw new RuntimeException("Lecture impossible: $val");
|
||
}
|
||
$key = $forMatch ? "{$prefix}_image_base64" : 'image_base64';
|
||
return [$key => base64_encode($bin)];
|
||
}
|
||
// Sinon, assume base64 “nu”
|
||
if (preg_match('~^[A-Za-z0-9+/=\r\n]+$~', $val)) {
|
||
$key = $forMatch ? "{$prefix}_image_base64" : 'image_base64';
|
||
return [$key => $val];
|
||
}
|
||
throw new InvalidArgumentException("Image non reconnue (URL, fichier ou base64 attendu): $val");
|
||
}
|
||
|
||
|
||
public function tester()
|
||
{
|
||
$apiKey = "lL18NHzgOta3_uKXYKcIG2s5a_Rys9Vq49JrDPVtESc";
|
||
|
||
|
||
$userImagePath = "/var/www/html/production/Temp/mbadan.jpg"; // photo prise en temps réel
|
||
$referenceImagePath = "/var/www/html/production/Temp/mbadan.jpg"; // photo d'identité ou d'enregistrement
|
||
|
||
// Vérification que les fichiers existent
|
||
if (!file_exists($userImagePath) || !file_exists($referenceImagePath))
|
||
{
|
||
die("Erreur : l'un des fichiers images n'existe pas.\n");
|
||
}
|
||
|
||
/*
|
||
$API_KEY = getenv('DIDIT_API_KEY'); // récupérée dans le Business Console
|
||
$WORKFLOW = getenv('DIDIT_BIO_WORKFLOW_ID'); // workflow "Biometric Authentication"
|
||
$CALLBACK = getenv('DIDIT_WEBHOOK_URL'); // votre endpoint webhook
|
||
*/
|
||
|
||
$API_KEY = "lL18NHzgOta3_uKXYKcIG2s5a_Rys9Vq49JrDPVtESc";
|
||
$WORKFLOW = ""; // workflow "Biometric Authentication"
|
||
$CALLBACK = ""; // votre endpoint webhook
|
||
|
||
// 1) Charger et encoder en Base64 le portrait de référence (JPG/PNG)
|
||
/*
|
||
$portraitPath = __DIR__ . '/portrait_reference.jpg';
|
||
*/
|
||
$portraitPath = "/var/www/html/production/Temp/mbadan.jpg";
|
||
$portraitB64 = base64_encode(file_get_contents($portraitPath));
|
||
|
||
var_dump($portraitB64);
|
||
exit();
|
||
|
||
// 2) Construire la charge utile pour créer la session
|
||
$payload = [
|
||
"workflow_id" => $WORKFLOW,
|
||
"vendor_data" => "user-123", // votre identifiant utilisateur
|
||
"callback" => $CALLBACK,
|
||
"metadata" => ["reason" => "login"], // champ libre optionnel
|
||
"portrait_image"=> $portraitB64 // <- clé pour activer Face Match 1:1
|
||
];
|
||
|
||
$ch = curl_init('https://verification.didit.me/v2/session/');
|
||
curl_setopt_array($ch, [
|
||
CURLOPT_POST => true,
|
||
CURLOPT_HTTPHEADER => [
|
||
'accept: application/json',
|
||
'content-type: application/json',
|
||
'x-api-key: ' . $API_KEY
|
||
],
|
||
CURLOPT_POSTFIELDS => json_encode($payload),
|
||
CURLOPT_RETURNTRANSFER => true,
|
||
]);
|
||
|
||
$response = curl_exec($ch);
|
||
if ($response === false) {
|
||
throw new RuntimeException('Erreur cURL: ' . curl_error($ch));
|
||
}
|
||
$code = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
|
||
curl_close($ch);
|
||
|
||
if ($code < 200 || $code >= 300) {
|
||
throw new RuntimeException("Echec création session (HTTP $code): $response");
|
||
}
|
||
|
||
$session = json_decode($response, true);
|
||
|
||
// 🔗 URL à présenter/rediriger à l’utilisateur pour prendre le selfie + liveness
|
||
echo "Open verification URL: " . $session['url'] . PHP_EOL;
|
||
|
||
// Conservez ces champs pour la suite
|
||
$sessionId = $session['session_id'];
|
||
$sessionToken = $session['session_token'];
|
||
}
|
||
}
|
||
|
||
function diditverifyandmatch(
|
||
string $apiKey,
|
||
string $selfie,
|
||
string $reference,
|
||
float $minLiveScore = 0.80, // ex: 0.80 (=80%) liveness pass
|
||
float $minFaceScore = 75.0 // ex: 75/100 face match pass
|
||
): array {
|
||
// 1) Passive Liveness
|
||
$livePayload = buildImagePayload($selfie, 'image'); // 'image' ou 'image_base64'
|
||
$liveResp = diditpostjson(
|
||
'https://verification.didit.me/v2/passive-liveness/',
|
||
$apiKey,
|
||
$livePayload
|
||
);
|
||
$liveScore = $liveResp['liveness']['score'] ?? null; // valeur typique 0..1
|
||
$liveStatus = $liveResp['liveness']['status'] ?? null; // e.g. Approved/Rejected/In Review
|
||
|
||
if (!is_numeric($liveScore)) {
|
||
throw new RuntimeException('Réponse Liveness invalide: score manquant');
|
||
}
|
||
if ($liveScore < $minLiveScore || (is_string($liveStatus) && stripos($liveStatus, 'rejected') !== false)) {
|
||
return [
|
||
'success' => false,
|
||
'stage' => 'liveness',
|
||
'reason' => 'fail_threshold',
|
||
'details' => [
|
||
'score' => $liveScore,
|
||
'status' => $liveStatus,
|
||
'min_required' => $minLiveScore,
|
||
],
|
||
];
|
||
}
|
||
|
||
// 2) Face Match 1:1 (selfie validé vs référence)
|
||
$matchPayload = buildImagePayload($selfie, 'source', true) +
|
||
buildImagePayload($reference, 'target', true);
|
||
$matchResp = diditpostjson(
|
||
'https://verification.didit.me/v2/face-match/',
|
||
$apiKey,
|
||
$matchPayload
|
||
);
|
||
$faceScore = $matchResp['face_match']['score'] ?? null; // 0..100
|
||
$faceStatus = $matchResp['face_match']['status'] ?? null; // Approved/Rejected/In Review
|
||
|
||
$passed = is_numeric($faceScore) && $faceScore >= $minFaceScore &&
|
||
!(is_string($faceStatus) && stripos($faceStatus, 'rejected') !== false);
|
||
|
||
return [
|
||
'success' => $passed,
|
||
'stage' => 'face_match',
|
||
'decision_threshold' => $minFaceScore,
|
||
'liveness' => [
|
||
'score' => $liveScore,
|
||
'status' => $liveStatus,
|
||
],
|
||
'face_match' => [
|
||
'score' => $faceScore,
|
||
'status' => $faceStatus,
|
||
'warnings' => $matchResp['face_match']['warnings'] ?? [],
|
||
],
|
||
'raw' => [
|
||
'liveness' => $liveResp,
|
||
'face_match' => $matchResp,
|
||
],
|
||
];
|
||
}
|
||
|
||
function diditpostjson(string $url, string $apiKey, array $payload): array {
|
||
$ch = curl_init($url);
|
||
curl_setopt_array($ch, [
|
||
CURLOPT_POST => true,
|
||
CURLOPT_RETURNTRANSFER => true,
|
||
CURLOPT_HTTPHEADER => [
|
||
'Accept: application/json',
|
||
'Content-Type: application/json',
|
||
'x-api-key: ' . $apiKey, // Auth Didit
|
||
],
|
||
CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_SLASHES),
|
||
CURLOPT_TIMEOUT => 60,
|
||
]);
|
||
$raw = curl_exec($ch);
|
||
$err = curl_error($ch);
|
||
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
|
||
curl_close($ch);
|
||
|
||
if ($err) {
|
||
throw new RuntimeException("Erreur cURL: $err");
|
||
}
|
||
if ($status < 200 || $status >= 300) {
|
||
throw new RuntimeException("HTTP $status: $raw");
|
||
}
|
||
$json = json_decode($raw, true);
|
||
if (!is_array($json)) {
|
||
throw new RuntimeException("JSON invalide: $raw");
|
||
}
|
||
return $json;
|
||
}
|
||
|
||
function buildImagePayload(string $val, string $prefix, bool $forMatch=false): array {
|
||
// URL ?
|
||
if (preg_match('~^https?://~i', $val)) {
|
||
$key = $forMatch ? "{$prefix}_image" : 'image';
|
||
return [$key => $val];
|
||
}
|
||
// Fichier local ?
|
||
if (is_file($val)) {
|
||
$bin = file_get_contents($val);
|
||
if ($bin === false) {
|
||
throw new RuntimeException("Lecture impossible: $val");
|
||
}
|
||
$key = $forMatch ? "{$prefix}_image_base64" : 'image_base64';
|
||
return [$key => base64_encode($bin)];
|
||
}
|
||
// Sinon, assume base64 “nu”
|
||
if (preg_match('~^[A-Za-z0-9+/=\r\n]+$~', $val)) {
|
||
$key = $forMatch ? "{$prefix}_image_base64" : 'image_base64';
|
||
return [$key => $val];
|
||
}
|
||
throw new InvalidArgumentException("Image non reconnue (URL, fichier ou base64 attendu): $val");
|
||
}
|