Files
Portfolio-Esteban/captcha.php
T
2026-06-29 16:34:35 +02:00

447 lines
16 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
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();
// Recharger une nouvelle série si demandé
if (isset($_GET['reload']) && $_GET['reload'] === '1') {
unset($_SESSION['captcha_round']);
header('Location: ./captcha.php');
exit;
}
// Si le captcha est déjà validé, rediriger vers l'accueil
if (isset($_SESSION['captcha_valid']) && $_SESSION['captcha_valid'] === true) {
header('Location: ./index.php');
exit;
}
$maxAttempts = 3;
$normalSubjects = [
'Votre rendez-vous est confirmé',
'Photo de famille',
'Invitation à déjeuner',
'Votre facture est disponible',
'Message de votre médecin',
'Votre colis arrivera demain',
'Reçu de paiement',
'Informations sur votre abonnement',
'Rappel de rendez-vous',
'Bulletin dinformation',
'Horaire modifié',
'Demande de nouvelles',
'Anniversaire ce week-end',
'Confirmation de réservation',
'Mise à jour de votre compte',
'Message du voisin',
'Résultats danalyse disponibles',
'Programme de la semaine',
'Votre commande a bien été envoyée',
'Merci pour votre visite',
'Document joint',
'Nouvelles de la famille',
'Convocation à la réunion',
'Changement dhoraire',
'Votre facture deau',
'Votre relevé est prêt',
'Confirmation de présence',
'Infos importantes pour demain',
'Rappel amical',
'Livraison prévue aujourdhui',
'Votre réservation est confirmée',
'Message de la mairie',
'Avis de passage',
'Votre ticket est traité',
'Mise à jour de votre dossier',
'Message de l’école',
'Facture mensuelle',
'Invitation à la réunion',
'Confirmation de paiement',
'Votre commande est en route',
'Rappel de consultation',
'Nouvelle réponse reçue',
'Votre dossier a été mis à jour',
'Planning de la semaine',
'Reçu de réservation',
'Informations utiles',
'Votre assurance vous écrit',
'Message de votre pharmacien',
'Document disponible en ligne',
'Petit rappel important',
'Votre livraison est confirmée',
'Message du service client',
'Votre demande a été reçue',
'Lettre dinformation',
'Nouvelles du jour',
'Confirmation de votre présence',
'Votre justificatif est prêt',
'Reçu de transaction',
'Votre compte a été mis à jour',
'Avis dinformation',
'Votre dossier avance',
'Information concernant votre contrat',
'Message de votre banque',
'Votre échéance approche',
'Réponse à votre demande',
'Merci pour votre confiance',
'Votre pharmacie vous informe',
'Rappel de paiement',
'Votre colis a quitté lentrepôt',
'Votre abonnement continue',
'Message de votre mutuelle',
'Invitation familiale',
'Nouveau message reçu',
'Votre place est réservée',
'Votre facture du mois',
'Compte-rendu envoyé',
'Votre demande est en cours',
'Rappel pour demain',
'Réception confirmée',
'Votre transport est réservé',
'Bonne réception',
'Votre document est validé',
'Votre suivi est disponible',
'Petit message amical',
'Confirmation de livraison',
'Votre note est disponible',
'Mise à jour dinformations',
'Votre service est activé',
'Votre message a bien été transmis',
'Reçu officiel',
'Votre planning a changé',
'Votre passage est confirmé',
'Information de dernière minute',
'Votre compte-rendu médical',
'Votre inscription est validée',
'Réponse automatique',
'Votre dossier est complet',
'Nouveau document reçu',
'Votre reçu est disponible',
'Votre commande est confirmée',
'Votre rendez-vous approche',
'Dernières informations'
];
$normalSenders = [
'Docteur Martin',
'Julie',
'Paul',
'Service client',
'École primaire',
'Mairie',
'Famille Dupont',
'Pharmacie du Centre',
'EDF Service',
'Voisinage',
'Transport local',
'Maison de santé',
'Claire Bernard',
'Assurance Habitation',
'Bibliothèque municipale',
'Banque familiale',
'Centre médical',
'La Poste',
'Mutuelle Santé',
'Service facturation'
];
$spamSubjects = [
'URGENT !!! VOTRE COMPTE SERA SUPPRIMÉ AUJOURDHUI',
'FÉLICITATIONS !!! VOUS AVEZ GAGNÉ 5000 € MAINTENANT',
'CLIQUEZ ICI IMMÉDIATEMENT POUR ÉVITER LE BLOCAGE',
'VOTRE COLIS EST BLOQUÉ, PAYEZ TOUT DE SUITE',
'DERNIÈRE ALERTE : CONFIRMEZ VOTRE MOT DE PASSE',
'ACTION OBLIGATOIRE DANS LES 5 MINUTES',
'VOTRE BANQUE EXIGE UNE VÉRIFICATION IMMÉDIATE',
'RÉCUPÉREZ VOTRE CADEAU GRATUIT MAINTENANT',
'ALERTE SÉCURITÉ : VOTRE IDENTITÉ EST EN DANGER',
'VOUS ÊTES LE GRAND GAGNANT DU JOUR',
'PAIEMENT REFUSÉ !!! METTEZ À JOUR VOTRE CARTE',
'CONFIRMEZ VOS INFORMATIONS SINON FERMETURE',
'OFFRE SECRÈTE EXCEPTIONNELLE À RÉCUPÉRER',
'VOTRE SESSION EXPIRE, CLIQUEZ MAINTENANT',
'REMBOURSEMENT IMMÉDIAT DISPONIBLE ICI',
'ATTENTION !!! COMPTE BLOQUÉ DANS QUELQUES MINUTES',
'DERNIÈRE CHANCE AVANT SUPPRESSION DÉFINITIVE',
'VOTRE MOT DE PASSE A ÉTÉ PIRATÉ, AGISSEZ',
'VÉRIFICATION URGENTE DE VOTRE CARTE BANCAIRE',
'CONFIRMEZ VOTRE IDENTITÉ POUR RECEVOIR VOTRE ARGENT'
];
$spamSenders = [
'service-urgent@compte-bloque-now.biz',
'cadeau-gratuit@super-offre-win.click',
'banque-alerte@verification-securite.top',
'colis-stop@paiement-obligatoire.help',
'admin-compte@action-immediate.world',
'support-prime@argent-rapide-fast.support',
'verification@motdepasse-danger.win',
'alerte@compte-fermeture.click'
];
$normalPreviews = [
'Bonjour, nous vous confirmons votre rendez-vous prévu cette semaine.',
'Je vous envoie les informations demandées, bonne journée.',
'Votre document est prêt, vous pouvez le consulter.',
'Merci pour votre message, voici les détails utiles.',
'Votre commande a bien été prise en compte.',
'Petit rappel pour ne rien oublier demain.',
'Nous restons à votre disposition pour toute question.',
'Voici un message dinformation concernant votre dossier.',
'Le service vous remercie et vous souhaite une bonne journée.',
'Vous trouverez ci-joint les éléments utiles.'
];
$spamPreviews = [
'Cliquez tout de suite sinon votre compte sera fermé dans quelques minutes.',
'Paiement obligatoire immédiat pour débloquer la situation.',
'Confirmez vos données personnelles maintenant pour éviter la suppression.',
'Votre cadeau gratuit vous attend, cliquez ici sans attendre.',
'Action urgente requise, réponse dans les 5 minutes demandée.',
'Dernier avertissement officiel avant blocage définitif.'
];
function firstLetterSafe(string $text): string
{
if (function_exists('mb_substr') && function_exists('mb_strtoupper')) {
return mb_strtoupper(mb_substr($text, 0, 1, 'UTF-8'), 'UTF-8');
}
return strtoupper(substr($text, 0, 1));
}
function buildInboxRound(
array $normalSubjects,
array $normalSenders,
array $normalPreviews,
array $spamSubjects,
array $spamSenders,
array $spamPreviews,
int $maxAttempts
): array {
$normalPool = [];
foreach ($normalSubjects as $index => $subject) {
$normalPool[] = [
'id' => 'normal_' . $index,
'sender' => $normalSenders[array_rand($normalSenders)],
'subject' => $subject,
'preview' => $normalPreviews[array_rand($normalPreviews)],
'is_spam' => false,
'time' => sprintf('%02d:%02d', random_int(8, 19), random_int(0, 59))
];
}
$spamPool = [];
foreach ($spamSubjects as $index => $subject) {
$spamPool[] = [
'id' => 'spam_' . $index,
'sender' => $spamSenders[array_rand($spamSenders)],
'subject' => $subject,
'preview' => $spamPreviews[array_rand($spamPreviews)],
'is_spam' => true,
'time' => sprintf('%02d:%02d', random_int(0, 23), random_int(0, 59))
];
}
shuffle($normalPool);
shuffle($spamPool);
$selected = array_slice($normalPool, 0, 9);
$selected[] = $spamPool[0];
shuffle($selected);
return [
'token' => bin2hex(random_bytes(16)),
'correct_id' => $spamPool[0]['id'],
'emails' => $selected,
'attempts_left' => $maxAttempts
];
}
if (!isset($_SESSION['captcha_round']) || !is_array($_SESSION['captcha_round'])) {
$_SESSION['captcha_round'] = buildInboxRound(
$normalSubjects,
$normalSenders,
$normalPreviews,
$spamSubjects,
$spamSenders,
$spamPreviews,
$maxAttempts
);
}
$round = $_SESSION['captcha_round'];
$error = '';
$success = false;
$locked = false;
if (!isset($round['emails']) || !is_array($round['emails'])) {
$_SESSION['captcha_round'] = buildInboxRound(
$normalSubjects,
$normalSenders,
$normalPreviews,
$spamSubjects,
$spamSenders,
$spamPreviews,
$maxAttempts
);
$round = $_SESSION['captcha_round'];
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$postedToken = $_POST['captcha_token'] ?? '';
$selectedMail = $_POST['selected_mail'] ?? '';
if (!hash_equals($round['token'], $postedToken)) {
$error = 'Session invalide, recharge la page.';
} elseif (($round['attempts_left'] ?? 0) <= 0) {
$locked = true;
$error = 'Tu nas plus dessais. Recharge une nouvelle série.';
} elseif ($selectedMail !== $round['correct_id']) {
$_SESSION['captcha_round']['attempts_left']--;
$round = $_SESSION['captcha_round'];
if (($round['attempts_left'] ?? 0) <= 0) {
$locked = true;
$error = 'Perdu. Tu nas plus dessais. Recharge une nouvelle série.';
} else {
$error = 'Ce nest pas le bon mail. Regarde mieux le message le plus agressif ou trop urgent.';
}
} else {
$_SESSION['captcha_valid'] = true;
unset($_SESSION['captcha_round']);
$success = true;
}
}
$attemptsLeft = $round['attempts_left'] ?? 0;
?>
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Test anti-robot</title>
<link rel="stylesheet" href="./styles/captcha.css">
</head>
<body class="<?php echo $success ? 'success-mode' : ''; ?>">
<main class="captcha-shell">
<?php if ($success): ?>
<section class="success-screen">
<div class="success-burst"></div>
<div class="success-icon">✅</div>
<h1>Vérification réussie</h1>
<p>Bravo, tu as trouvé le mail frauduleux. Redirection en cours...</p>
<div class="success-loader">
<span></span>
</div>
</section>
<script>
setTimeout(function () {
window.location.href = './index.php';
}, 1800);
</script>
<?php else: ?>
<form class="captcha-card" method="post" action="">
<div class="captcha-badge">🛡️ Test anti-robot</div>
<div class="captcha-top">
<div>
<h1 class="captcha-title">Vérification humaine</h1>
<p class="captcha-subtitle">
Pour continuer, cliquez sur le <strong>mail frauduleux</strong> parmi les 10 messages ci-dessous.
</p>
</div>
<div class="captcha-target">
<span>Vérification demandée</span>
<strong>Trouver le spam</strong>
</div>
</div>
<div class="captcha-stats">
<div class="captcha-attempts">
<span>Essais restants</span>
<strong><?php echo htmlspecialchars((string) $attemptsLeft, ENT_QUOTES, 'UTF-8'); ?> / <?php echo htmlspecialchars((string) $maxAttempts, ENT_QUOTES, 'UTF-8'); ?></strong>
</div>
<?php if ($locked): ?>
<a class="captcha-reset" href="./captcha.php?reload=1">Recharger une nouvelle série</a>
<?php endif; ?>
</div>
<?php if ($error !== ''): ?>
<div class="captcha-error"><?php echo htmlspecialchars($error, ENT_QUOTES, 'UTF-8'); ?></div>
<?php endif; ?>
<div class="mailbox">
<div class="mailbox-toolbar">
<div class="mailbox-dots">
<span></span>
<span></span>
<span></span>
</div>
<div class="mailbox-label">Test anti-robot : trouvez le mail qui ressemble à une arnaque</div>
</div>
<div class="mail-list">
<?php foreach ($round['emails'] as $mail): ?>
<label class="mail-option <?php echo $locked ? 'mail-option-disabled' : ''; ?>">
<input
type="radio"
name="selected_mail"
value="<?php echo htmlspecialchars($mail['id'], ENT_QUOTES, 'UTF-8'); ?>"
<?php echo $locked ? 'disabled' : 'required'; ?>
>
<span class="mail-row">
<span class="mail-avatar">
<?php echo htmlspecialchars(firstLetterSafe($mail['sender']), ENT_QUOTES, 'UTF-8'); ?>
</span>
<span class="mail-sender">
<?php echo htmlspecialchars($mail['sender'], ENT_QUOTES, 'UTF-8'); ?>
</span>
<span class="mail-content">
<span class="mail-subject">
<?php echo htmlspecialchars($mail['subject'], ENT_QUOTES, 'UTF-8'); ?>
</span>
<span class="mail-preview">
<?php echo htmlspecialchars($mail['preview'], ENT_QUOTES, 'UTF-8'); ?>
</span>
</span>
<span class="mail-time">
<?php echo htmlspecialchars($mail['time'], ENT_QUOTES, 'UTF-8'); ?>
</span>
</span>
</label>
<?php endforeach; ?>
</div>
</div>
<input
type="hidden"
name="captcha_token"
value="<?php echo htmlspecialchars($round['token'], ENT_QUOTES, 'UTF-8'); ?>"
>
<div class="captcha-footer">
<p class="captcha-note">
Tu as plusieurs essais. Les faux mails utilisent souvent lurgence, les cadeaux improbables, les menaces ou les demandes de mot de passe.
</p>
<div class="captcha-actions">
<?php if ($locked): ?>
<a class="captcha-secondary-button" href="./captcha.php?reload=1">Nouvelle série</a>
<?php else: ?>
<button type="submit" class="captcha-submit">Valider ma sélection</button>
<?php endif; ?>
</div>
</div>
</form>
<?php endif; ?>
</main>
</body>
</html>