Ajout d'un captcha + Réactualisation du css + ajout cgu

This commit is contained in:
Esteban
2026-06-29 16:20:59 +02:00
parent 57a34967bb
commit 4bab6548f7
16 changed files with 1139 additions and 17 deletions
+441
View File
@@ -0,0 +1,441 @@
<?php
// Démarrage de la session
session_start();
// 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;
}
// Nombre maximum de tentatives
$maxAttempts = 3;
// Tableau de sujets normaux
$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'
];
// Tableau de expéditeurs normaux
$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'
];
// Tableau de sujets spam
$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'
];
// Tableau de expéditeurs spam
$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'
];
// Tableau de previews normaux
$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.'
];
// Tableau de previews spam
$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.'
];
// Fonction pour construire un round de boîte de réception
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))
];
}
// Mélanger les tableaux
shuffle($normalPool);
shuffle($spamPool);
// Sélectionner 9 emails normaux et 1 spam
$selected = array_slice($normalPool, 0, 9);
$selected[] = $spamPool[0];
shuffle($selected);
// Retourner le round
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
);
}
// Récupérer le round actuel
$round = $_SESSION['captcha_round'];
$error = '';
$success = false;
$locked = false;
// Si formulaire soumis via POST
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$postedToken = $_POST['captcha_token'] ?? '';
$selectedMail = $_POST['selected_mail'] ?? '';
// Si token invalide
if (!hash_equals($round['token'], $postedToken)) {
$error = 'Session invalide, recharge la page.';
// Si plus d'essais
} elseif (($round['attempts_left'] ?? 0) <= 0) {
$locked = true;
$error = 'Tu nas plus dessais. Recharge une nouvelle série.';
// Si mail incorrect
} elseif ($selectedMail !== $round['correct_id']) {
$_SESSION['captcha_round']['attempts_left']--;
$round = $_SESSION['captcha_round'];
// Si plus d'essais après décrémentation
if (($round['attempts_left'] ?? 0) <= 0) {
$locked = true;
$error = 'Perdu. Tu nas plus dessais. Recharge une nouvelle série.';
// Sinon, message d'erreur
} else {
$error = 'Ce nest pas le bon mail. Regarde mieux le message le plus agressif ou trop urgent.';
}
// Si mail correct
} else {
$_SESSION['captcha_valid'] = true;
unset($_SESSION['captcha_round']);
$success = true;
}
}
// Récupérer le nombre d'essais restants
$attemptsLeft = $round['attempts_left'] ?? 0;
// Afficher le captcha
?>
<!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(mb_strtoupper(mb_substr($mail['sender'], 0, 1, 'UTF-8'), 'UTF-8'), 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>
+5 -5
View File
@@ -2,10 +2,10 @@
CREATE DATABASE IF NOT EXISTS portfolio CREATE DATABASE IF NOT EXISTS portfolio
-- On créer un utilisateur avec un mot de passe fort qui est à changer après execution dus script (voir bitwarden) -- On créer un utilisateur avec un mot de passe fort qui est à changer après execution dus script (voir bitwarden)
CREATE USER 'srv_portfolio'@'localhost' IDENTIFIED BY 'mdp'; CREATE USER 'srv_portfolio'@'%' IDENTIFIED BY 'mdp';
-- On met les droits au compte sur la base portfolio à l'utilisateur -- On met les droits au compte sur la base portfolio à l'utilisateur
GRANT ALL ON portfolio.* TO 'srv_portfolio'@'localhost'; GRANT ALL ON portfolio.* TO 'srv_portfolio'@'%';
-- On actualise les permissions -- On actualise les permissions
FLUSH PRIVILEGES; FLUSH PRIVILEGES;
@@ -14,7 +14,7 @@ FLUSH PRIVILEGES;
CREATE TABLE IF NOT EXISTS users ( CREATE TABLE IF NOT EXISTS users (
id INT UNSIGNED NOT NULL AUTO_INCREMENT, id INT UNSIGNED NOT NULL AUTO_INCREMENT,
username VARCHAR(50) NOT NULL, username VARCHAR(50) NOT NULL,
password VARCHAR(255) NOT NULL, -- Je laisse ici de la place pour prévoir un futur hashage et sallage password VARCHAR(255) NOT NULL,
role ENUM('admin', 'user') NOT NULL DEFAULT 'user', role ENUM('admin', 'user') NOT NULL DEFAULT 'user',
created_at DATETIME NULL DEFAULT NULL, created_at DATETIME NULL DEFAULT NULL,
last_login DATETIME NULL DEFAULT NULL, last_login DATETIME NULL DEFAULT NULL,
@@ -29,7 +29,7 @@ CREATE TABLE IF NOT EXISTS projects (
title VARCHAR(100) NOT NULL, title VARCHAR(100) NOT NULL,
tags VARCHAR(255) NULL, tags VARCHAR(255) NULL,
description TEXT NOT NULL, description TEXT NOT NULL,
image_url VARCHAR(255) NOT NULL, -- Stockage de l'image par URL (exemple : par CDN) image_url VARCHAR(255) NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP, created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id) PRIMARY KEY (id)
); );
@@ -42,7 +42,7 @@ CREATE TABLE IF NOT EXISTS experiences (
tags VARCHAR(255) NULL, tags VARCHAR(255) NULL,
description TEXT NOT NULL, description TEXT NOT NULL,
duration VARCHAR(100) NOT NULL, duration VARCHAR(100) NOT NULL,
image_url VARCHAR(255) NOT NULL, -- Stockage de l'image par URL (exemple : par CDN) image_url VARCHAR(255) NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP, created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id) PRIMARY KEY (id)
); );
+1 -1
View File
@@ -15,7 +15,7 @@
<a href="https://www.instagram.com/ours_one_" target="_blank" rel="noopener noreferrer">Instagram</a> <a href="https://www.instagram.com/ours_one_" target="_blank" rel="noopener noreferrer">Instagram</a>
<a href="https://git.eldorianet.work/esteban" target="_blank" rel="noopener noreferrer">Git</a> <a href="https://git.eldorianet.work/esteban" target="_blank" rel="noopener noreferrer">Git</a>
<span class="discord-handle" title="@ours1" onclick="alert('Discord : @ours1')">Discord</span> <span class="discord-handle" title="@ours1" onclick="alert('Discord : @ours1')">Discord</span>
<a href="../pages/cgu.php">Conditions générales et d'utilisation</a> <a href="../pages/cgu.php">CGU</a>
</div> </div>
</div> </div>
</footer> </footer>
+4
View File
@@ -8,6 +8,9 @@
// Ajout ici d'un démarrage de session : header étant dans toutes les pages // Ajout ici d'un démarrage de session : header étant dans toutes les pages
session_start(); session_start();
// Ajout ici la vérification du captcha
require_once('../scripts/requireCaptcha.php');
// Ajout des logs sur toutes les pages // Ajout des logs sur toutes les pages
require_once('../functions/sendLogs.php'); require_once('../functions/sendLogs.php');
?> ?>
@@ -27,6 +30,7 @@ require_once('../functions/sendLogs.php');
<a href="./../index.php">Accueil</a> <a href="./../index.php">Accueil</a>
<a href="./../pages/projects.php">Projets</a> <a href="./../pages/projects.php">Projets</a>
<a href="./../pages/xp.php">Expériences</a> <a href="./../pages/xp.php">Expériences</a>
<a href="./../pages/skills.php">Compétences</a>
<a href="./../pages/contact.php">Contact</a> <a href="./../pages/contact.php">Contact</a>
<?php <?php
// Vérification que l'utilisateur est admin, s'il est admin, il aura accès au panel admin // Vérification que l'utilisateur est admin, s'il est admin, il aura accès au panel admin
+3 -1
View File
@@ -28,4 +28,6 @@ function sendLog($action, $user="") {
curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $dataJson); curl_setopt($ch, CURLOPT_POSTFIELDS, $dataJson);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
} }
//
+1 -1
View File
@@ -4,7 +4,7 @@
// Le CSS est **probablement** généré par intelligence artificielle ou récupéré d'autre projet, cependant le code PHP / HTML / JS est globalement fait par un humain // Le CSS est **probablement** généré par intelligence artificielle ou récupéré d'autre projet, cependant le code PHP / HTML / JS est globalement fait par un humain
// Note 1 : Pour lancer un serveur local PHP Depuis VsCode : 'php -v' pour vérifier que php est bien installé et 'php -S localhost:8000' pour lancer le serveur // Note 1 : Pour lancer un serveur local PHP Depuis VsCode : 'php -v' pour vérifier que php est bien installé et 'php -S localhost:8000' pour lancer le serveur
// Note 2 : Je m'aide désormais de l'autocompletion de vsCode pour accélerer le développement avec Copilot (GitHub) mais le reste du code est entièrement développé par moi même mais copilot // Note 2 : Je m'aide désormais de l'autocompletion de vsCode pour accélerer le développement avec Copilot (GitHub) ou Devin mais le reste du code est entièrement développé par moi même mais copilot
// reste utile pour la génération de commentaires, de code répétitif ou de code basique (exemple : les formulaires de contact, les requêtes SQL basiques etc...) // reste utile pour la génération de commentaires, de code répétitif ou de code basique (exemple : les formulaires de contact, les requêtes SQL basiques etc...)
+59 -4
View File
@@ -1,9 +1,64 @@
<?php <?php
// CGU / CDU // CGU / CDU
// On ajoute ici le header
require_once('./../elements/header.php'); require_once('./../elements/header.php');
// Ajout du footer ?>
require_once('../elements/footer.php'); ?>
<main class="cgu-page">
<section class="cgu-card">
<h1> Conditions générales d'utilisation </h1>
<h2> Dernière mise à jour : 29 juin 2026</h2>
<hr>
<p>Les présentes conditions générales d'utilisation (CGU) régissent l'utilisation du site web estebanadmin.fr. En accédant à ce site, vous acceptez les présentes conditions.</p>
<h3> 1. Objet</h3>
<p>Le présent site a pour objectif de présenter le parcours, les compétences, les projets et les réalisations dEsteban. Le site peut également contenir des moyens de contact, des liens externes et des contenus liés à son activité personnelle, associative ou professionnelle.</p>
<h3> 2. Accès au site</h3>
<p>L'accès au site est gratuit et ouvert à tous. L'utilisateur s'engage à utiliser le site de manière responsable et conforme à la législation en vigueur.</p>
<p>L'éditeur se réserve le droit de suspendre, d'interrompre ou de modifier tout ou partie du site sans préavis, notamment pour des raisons techniques, légales, de sécurité, de maintenance ou en cas d'usage abusif.</p>
<h3> 3. Propriété intellectuelle</h3>
<p>Lensemble des éléments présents sur le site, notamment les textes, visuels, illustrations, logos, éléments graphiques, structure, code source et contenus originaux, est protégé par le droit de la propriété intellectuelle, sauf mention contraire.</p>
<p>Toute reproduction, représentation, diffusion, adaptation, modification ou exploitation, totale ou partielle, sans autorisation préalable écrite, est interdite, sauf dans les cas autorisés par la loi.</p>
<h3> 4. Utilisation de lintelligence artificielle</h3>
<p>Le site et certains de ses éléments ont pu être conçus avec l'assistance d'outils dintelligence artificielle. Cela peut notamment concerner la génération ou ladaptation de feuilles de style CSS, laide à la rédaction, lautocomplétion de code, la génération de commentaires, de structures répétitives, de formulaires simples ou de requêtes basiques.</p>
<p>L’éditeur précise cependant que le développement principal du projet, notamment le code PHP, HTML et JavaScript, larchitecture générale, lintégration, les choix techniques et la personnalisation globale du site, ont été réalisés majoritairement par un humain, à savoir Esteban MOUSSU.</p>
<p>L'utilisation d'outils tels que GitHub Copilot, Devin ou d'autres assistants similaires constitue une aide au développement et non une substitution complète au travail humain.</p>
<h3> 5. Hébergement et édition</h3>
<p>Ce projet est entièrement développé par Esteban MOUSSU.</p>
<p>Le site est hébergé en 2026 par lentreprise TerraTech Hebergement, en collaboration avec lassociation Eldoria Network.</p>
<p>Les informations diffusées sur le site le sont sous la responsabilité de son éditeur.</p>
<h3> 6. Exactitude des informations</h3>
<p>L’éditeur sefforce de fournir des informations aussi exactes et à jour que possible. Toutefois, aucune garantie nest donnée quant à lexactitude, lexhaustivité ou lactualité des contenus publiés.</p>
<p>Lutilisateur reconnaît utiliser les informations disponibles sur le site sous sa seule responsabilité.</p>
<h3> 7. Liens externes</h3>
<p>Le site peut contenir des liens vers des sites tiers. Ces liens sont fournis à titre informatif. L’éditeur ne saurait être tenu responsable du contenu, du fonctionnement ou des politiques de confidentialité de ces sites externes.</p>
<h3> 8. Responsabilité</h3>
<p>L’éditeur ne pourra être tenu responsable des dommages directs ou indirects résultant de lutilisation du site, dune interruption temporaire, dun dysfonctionnement technique ou dune impossibilité daccès.</p>
<p>Lutilisateur demeure seul responsable de lusage quil fait du site et des informations quil y consulte.</p>
<h3> 9. Données personnelles</h3>
<p>Le site peut proposer un ou plusieurs formulaires de contact. Les données éventuellement transmises par lutilisateur sont uniquement destinées au traitement de sa demande, sauf mention contraire clairement indiquée.</p>
<p>Conformément à la réglementation applicable, lutilisateur peut demander laccès, la rectification ou la suppression de ses données en contactant l’éditeur du site.</p>
<h3> 10. Sécurité</h3>
<p>Lutilisateur sinterdit de perturber le bon fonctionnement du site, dintroduire des programmes malveillants, de tenter un accès non autorisé ou de porter atteinte à lintégrité technique du service.</p>
<h3> 11. Modification des CGU</h3>
<p>L’éditeur se réserve le droit de modifier à tout moment les présentes CGU. Les modifications prennent effet dès leur publication sur cette page.</p>
<h3> 12. Droit applicable</h3>
<p>Les présentes CGU sont soumises au droit français. En cas de litige, et à défaut de résolution amiable, les juridictions compétentes seront celles déterminées par les règles de droit commun.</p>
</section>
</main>
<?php
require_once('../elements/footer.php');
?>
+1
View File
@@ -3,6 +3,7 @@
// Page Home PortFolio Esteban // Page Home PortFolio Esteban
// Cette page servira de page d'accueil où nous pourrons y retrouver une redirection vers les différents projets, espace de connexion, form de contact, etc... // Cette page servira de page d'accueil où nous pourrons y retrouver une redirection vers les différents projets, espace de connexion, form de contact, etc...
// Insertion du header // Insertion du header
require_once('./../elements/header.php'); require_once('./../elements/header.php');
+1
View File
@@ -4,6 +4,7 @@
// Egalement permettre à l'utilisateur de faire retour en arrière s'il s'est trompé (croix ou header) // Egalement permettre à l'utilisateur de faire retour en arrière s'il s'est trompé (croix ou header)
// On ajoute ici le Header // On ajoute ici le Header
require_once('./../elements/header.php'); require_once('./../elements/header.php');
+1
View File
@@ -3,6 +3,7 @@
// Page affichant les différents projets personnels / scolaires / professionnels // Page affichant les différents projets personnels / scolaires / professionnels
// On pourrait également rajouter des tags comme "En cours" ou même "En reflexion"... // On pourrait également rajouter des tags comme "En cours" ou même "En reflexion"...
// On ajoute le header // On ajoute le header
require_once('../elements/header.php'); require_once('../elements/header.php');
+1
View File
@@ -2,6 +2,7 @@
// Compétences // Compétences
// On ajoute ici le header // On ajoute ici le header
require_once('./../elements/header.php'); require_once('./../elements/header.php');
+1
View File
@@ -2,6 +2,7 @@
// Page affichant les différentes expériences pro (stages etc...) // Page affichant les différentes expériences pro (stages etc...)
// On ajoute le header // On ajoute le header
require_once('../elements/header.php'); require_once('../elements/header.php');
+14 -4
View File
@@ -2,13 +2,23 @@
// Lorsque l'utilisateur est renvoyé à cette page/fonction, il est déconnecté // Lorsque l'utilisateur est renvoyé à cette page/fonction, il est déconnecté
// Démarrage de session // Démarrage de session
session_start(); session_start();
// Destruction des variables de session // On sauvegarde l'état du captcha avant destruction
$captchaAlreadyValid = isset($_SESSION['captcha_valid']) && $_SESSION['captcha_valid'] === true;
// Destruction des variables de session
$_SESSION = array(); $_SESSION = array();
session_destroy(); session_destroy();
// Redirection de l'utilisateur vers home.php // Si le captcha avait déjà été validé, on recrée une session propre
header('Location: ../index.php'); // pour conserver uniquement cette information
if ($captchaAlreadyValid) {
session_start();
$_SESSION['captcha_valid'] = true;
}
// Redirection de l'utilisateur vers l'accueil
header('Location: ../index.php');
exit;
+7
View File
@@ -0,0 +1,7 @@
<?php
if (!isset($_SESSION['captcha_valid']) || $_SESSION['captcha_valid'] !== true) {
header('Location: ../captcha.php');
exit;
}
?>
+507
View File
@@ -0,0 +1,507 @@
body {
background:
radial-gradient(circle at top, rgba(108, 99, 255, 0.18), transparent 35%),
#0d0d0d;
margin: 0;
font-family: Arial, sans-serif;
color: white;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 24px;
box-sizing: border-box;
}
.captcha-shell {
width: 100%;
max-width: 1100px;
}
.captcha-card,
.success-screen {
background: linear-gradient(180deg, #111116 0%, #161622 100%);
border: 1px solid #2a2a3e;
border-radius: 24px;
box-shadow: 0 18px 40px rgba(0, 0, 0, 0.28);
padding: 30px;
}
.captcha-badge {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 8px 14px;
border-radius: 999px;
background: rgba(108, 99, 255, 0.14);
border: 1px solid rgba(108, 99, 255, 0.28);
color: #9d97ff;
font-size: 13px;
font-weight: bold;
margin-bottom: 18px;
}
.captcha-top {
display: flex;
justify-content: space-between;
align-items: flex-start;
gap: 24px;
margin-bottom: 18px;
}
.captcha-title {
margin: 0 0 10px;
font-size: 34px;
font-weight: 800;
}
.captcha-subtitle {
margin: 0;
color: #c1c1cf;
font-size: 16px;
line-height: 1.7;
max-width: 700px;
}
.captcha-target {
min-width: 240px;
background-color: #1a1a24;
border: 1px solid #2a2a3e;
border-radius: 18px;
padding: 18px;
}
.captcha-target span {
display: block;
color: #8f8fa8;
font-size: 12px;
text-transform: uppercase;
letter-spacing: 0.08em;
margin-bottom: 8px;
}
.captcha-target strong {
font-size: 22px;
color: #8f88ff;
}
.captcha-stats {
display: flex;
justify-content: space-between;
align-items: center;
gap: 16px;
margin-bottom: 18px;
flex-wrap: wrap;
}
.captcha-attempts {
background-color: #171b28;
border: 1px solid #283049;
border-radius: 14px;
padding: 12px 16px;
}
.captcha-attempts span {
display: block;
color: #99a0bc;
font-size: 12px;
text-transform: uppercase;
letter-spacing: 0.08em;
margin-bottom: 6px;
}
.captcha-attempts strong {
font-size: 22px;
color: #ffffff;
}
.captcha-reset,
.captcha-secondary-button {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 12px 18px;
border-radius: 12px;
text-decoration: none;
color: white;
background-color: #2a314a;
border: 1px solid #3d4767;
transition: transform 0.2s ease, background-color 0.2s ease;
}
.captcha-reset:hover,
.captcha-secondary-button:hover {
background-color: #394362;
transform: translateY(-1px);
}
.captcha-error {
margin-bottom: 18px;
background-color: rgba(161, 44, 47, 0.15);
border: 1px solid rgba(255, 84, 84, 0.45);
border-radius: 12px;
color: #ffb8bb;
padding: 14px 16px;
font-size: 14px;
}
.mailbox {
background-color: #0f1118;
border: 1px solid #22263a;
border-radius: 20px;
overflow: hidden;
}
.mailbox-toolbar {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
padding: 16px 20px;
background-color: #141825;
border-bottom: 1px solid #22263a;
}
.mailbox-dots {
display: flex;
gap: 8px;
}
.mailbox-dots span {
width: 10px;
height: 10px;
border-radius: 50%;
display: block;
}
.mailbox-dots span:nth-child(1) {
background-color: #ff5f57;
}
.mailbox-dots span:nth-child(2) {
background-color: #febc2e;
}
.mailbox-dots span:nth-child(3) {
background-color: #28c840;
}
.mailbox-label {
color: #d6daf0;
font-size: 14px;
font-weight: bold;
}
.mail-list {
display: flex;
flex-direction: column;
}
.mail-option {
position: relative;
}
.mail-option-disabled {
pointer-events: none;
}
.mail-option input {
position: absolute;
opacity: 0;
pointer-events: none;
}
.mail-row {
display: grid;
grid-template-columns: 48px minmax(120px, 220px) 1fr 70px;
gap: 14px;
align-items: center;
padding: 16px 18px;
border-bottom: 1px solid #1d2234;
cursor: pointer;
transition:
background-color 0.2s ease,
border-color 0.2s ease,
transform 0.2s ease,
box-shadow 0.2s ease;
}
.mail-row:hover {
background-color: #161b2a;
transform: translateX(2px);
}
.mail-option input:checked + .mail-row {
background-color: rgba(108, 99, 255, 0.14);
box-shadow: inset 0 0 0 1px rgba(108, 99, 255, 0.35);
}
.mail-avatar {
width: 42px;
height: 42px;
border-radius: 50%;
background: linear-gradient(180deg, #2f3550 0%, #1f2334 100%);
border: 1px solid #303650;
display: flex;
align-items: center;
justify-content: center;
color: #d7dcf2;
font-weight: bold;
font-size: 15px;
}
.mail-sender {
font-weight: bold;
color: white;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.mail-content {
min-width: 0;
}
.mail-subject {
color: #f3f4fb;
font-size: 15px;
margin-bottom: 4px;
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.mail-preview {
color: #b5b8ca;
font-size: 13px;
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.mail-time {
color: #8f8fa8;
font-size: 13px;
text-align: right;
}
.captcha-footer {
display: flex;
justify-content: space-between;
align-items: center;
gap: 16px;
margin-top: 24px;
}
.captcha-note {
color: #b7bbcd;
font-size: 14px;
line-height: 1.6;
max-width: 720px;
}
.captcha-actions {
display: flex;
gap: 12px;
}
.captcha-submit {
background: linear-gradient(180deg, #7a72ff 0%, #5e56eb 100%);
color: white;
border: none;
border-radius: 12px;
padding: 14px 24px;
font-size: 15px;
font-weight: bold;
cursor: pointer;
transition: background-color 0.2s ease, transform 0.2s ease, box-shadow 0.2s ease;
box-shadow: 0 12px 24px rgba(94, 86, 235, 0.28);
}
.captcha-submit:hover {
transform: translateY(-1px) scale(1.01);
box-shadow: 0 16px 30px rgba(94, 86, 235, 0.34);
}
.success-mode {
overflow: hidden;
}
.success-screen {
text-align: center;
position: relative;
overflow: hidden;
animation: successPop 0.6s ease;
}
.success-icon {
font-size: 68px;
margin-bottom: 14px;
animation: bounceIn 0.9s ease;
}
.success-screen h1 {
margin: 0 0 12px;
font-size: 40px;
}
.success-screen p {
margin: 0 auto 24px;
max-width: 520px;
color: #ced2e6;
font-size: 18px;
}
.success-loader {
width: 240px;
height: 10px;
margin: 0 auto;
background: #23283d;
border-radius: 999px;
overflow: hidden;
border: 1px solid #323a5b;
}
.success-loader span {
display: block;
height: 100%;
width: 0;
background: linear-gradient(90deg, #62d26f 0%, #9cffaf 100%);
animation: loadingBar 1.8s linear forwards;
}
.success-burst {
position: absolute;
inset: 0;
pointer-events: none;
background:
radial-gradient(circle at 20% 30%, rgba(255, 215, 0, 0.25), transparent 18%),
radial-gradient(circle at 80% 20%, rgba(98, 210, 111, 0.22), transparent 18%),
radial-gradient(circle at 30% 80%, rgba(122, 114, 255, 0.2), transparent 20%),
radial-gradient(circle at 75% 70%, rgba(255, 105, 180, 0.16), transparent 18%);
animation: burstPulse 1s ease-in-out infinite alternate;
}
@keyframes successPop {
from {
opacity: 0;
transform: scale(0.96);
}
to {
opacity: 1;
transform: scale(1);
}
}
@keyframes bounceIn {
0% {
opacity: 0;
transform: scale(0.3) translateY(20px);
}
60% {
opacity: 1;
transform: scale(1.08) translateY(-6px);
}
100% {
transform: scale(1) translateY(0);
}
}
@keyframes loadingBar {
from {
width: 0;
}
to {
width: 100%;
}
}
@keyframes burstPulse {
from {
opacity: 0.7;
transform: scale(1);
}
to {
opacity: 1;
transform: scale(1.03);
}
}
@media (max-width: 900px) {
.captcha-top {
flex-direction: column;
}
.captcha-target {
width: 100%;
min-width: 0;
}
.mail-row {
grid-template-columns: 42px 1fr 56px;
}
.mail-sender {
display: none;
}
.captcha-footer {
flex-direction: column;
align-items: stretch;
}
.captcha-actions {
width: 100%;
}
.captcha-submit,
.captcha-secondary-button {
width: 100%;
}
}
@media (max-width: 640px) {
body {
padding: 14px;
}
.captcha-card,
.success-screen {
padding: 20px;
border-radius: 18px;
}
.captcha-title {
font-size: 28px;
}
.mailbox-toolbar {
padding: 14px 16px;
}
.mail-row {
grid-template-columns: 36px 1fr;
gap: 10px;
padding: 14px 14px;
}
.mail-time {
grid-column: 2;
text-align: left;
margin-top: 4px;
}
.success-screen h1 {
font-size: 30px;
}
.success-screen p {
font-size: 16px;
}
.success-loader {
width: 100%;
}
}
+92 -1
View File
@@ -771,4 +771,95 @@ main {
.quick-link-card p { .quick-link-card p {
font-size: 16px; font-size: 16px;
} }
} }
/* ---- PAGE CGU ---- */
.cgu-page {
max-width: 980px;
margin: 48px auto 72px;
padding: 0 24px;
box-sizing: border-box;
}
.cgu-card {
background: linear-gradient(180deg, #111116 0%, #15151f 100%);
border: 1px solid #2a2a3e;
border-radius: 20px;
padding: 40px;
box-shadow: 0 18px 40px rgba(0, 0, 0, 0.28);
}
.cgu-card h1 {
margin: 0 0 10px;
color: white;
font-size: 38px;
font-weight: 800;
line-height: 1.2;
}
.cgu-card h2 {
margin: 0 0 24px;
color: #b8b8c7;
font-size: 17px;
font-weight: 500;
}
.cgu-card hr {
border: none;
height: 1px;
background-color: #2a2a3e;
margin: 0 0 28px;
}
.cgu-card h3 {
margin: 30px 0 12px;
color: #8f88ff;
font-size: 22px;
font-weight: 700;
}
.cgu-card p {
margin: 0 0 14px;
color: #c7c7d4;
font-size: 16px;
line-height: 1.8;
}
.cgu-card p:last-child {
margin-bottom: 0;
}
.cgu-card br {
display: none;
}
@media (max-width: 700px) {
.cgu-page {
margin: 28px auto 48px;
padding: 0 14px;
}
.cgu-card {
padding: 24px 18px;
border-radius: 16px;
}
.cgu-card h1 {
font-size: 28px;
}
.cgu-card h2 {
font-size: 15px;
margin-bottom: 18px;
}
.cgu-card h3 {
font-size: 19px;
margin-top: 24px;
}
.cgu-card p {
font-size: 15px;
line-height: 1.7;
}
}