Files

214 lines
7.9 KiB
PHP
Raw Permalink 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
declare (strict_types = 1);
require_once __DIR__ . '/../includes/bootstrap_global.php';
/**
* UI helper: affiche une jolie carte centrée puis exit.
* $type: 'error' | 'info' | 'success'
*/
function ui_exit(string $title, string $message, int $status = 400, string $type = 'error', ?string $cta_href = '/', ?string $cta_label = null): void
{
http_response_code($status);
$title = htmlspecialchars($title, ENT_QUOTES, 'UTF-8');
$message = nl2br(htmlspecialchars($message, ENT_QUOTES, 'UTF-8'));
$cta_href = $cta_href ? htmlspecialchars($cta_href, ENT_QUOTES, 'UTF-8') : null;
$cta_label = $cta_label ?? 'OK';
// Styles d'icône selon le type
$iconBorder = '#B91C1C'; // rouge par défaut (error)
$iconBg = 'rgba(185,28,28,.08)';
$iconRing = 'rgba(185,28,28,.25)';
$checkCSS = ''; // pour success
if ($type === 'info') {
$iconBorder = '#1D4ED8';
$iconBg = 'rgba(29,78,216,.08)';
$iconRing = 'rgba(29,78,216,.25)';
} elseif ($type === 'success') {
$iconBorder = '#1E8050';
$iconBg = 'rgba(30,128,80,.08)';
$iconRing = 'rgba(30,128,80,.20)';
$checkCSS = 'width:48px;height:36px;border:5px solid #1e8050;border-top:0;border-left:0;transform:rotate(45deg);';
}
echo '<!DOCTYPE html><html lang="fr"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">';
echo '<title>' . $title . '</title>';
echo '<style>
html,body{height:100%;margin:0}
body{display:flex;align-items:center;justify-content:center;background:#8CA9FF;font-family:Montserrat,system-ui,Segoe UI,Roboto,Arial}
.card{max-width:720px;width:94%;background:#fff;border:1px solid #e5e7eb;border-radius:14px;box-shadow:0 8px 24px rgba(0,0,0,.08);padding:28px;text-align:center}
h1{margin:6px 0 10px;font-size:clamp(22px,2.4vw,28px)}
p{margin:0 0 18px;color:#6b7280;font-size:clamp(16px,2.2vw,18px)}
.row{display:flex;gap:10px;justify-content:center;flex-wrap:wrap;margin-top:8px}
.btn{padding:10px 14px;border-radius:10px;text-decoration:none;display:inline-block}
.btn-primary{background:#2563eb;color:#fff}
.btn-outline{border:1px solid #d1d5db;color:#374151;background:#fff}
</style></head><body><div class="card">';
// Icône
echo '<div style="width:102px;height:102px;border-radius:50%;background:' . $iconBg . ';border:3px solid ' . $iconRing . ';display:flex;align-items:center;justify-content:center;margin:0 auto 20px;">';
if ($type === 'success') {
echo '<div style="' . $checkCSS . '"></div>';
} elseif ($type === 'info') {
echo '<div style="width:14px;height:48px;border-left:5px solid ' . $iconBorder . ';position:relative;">
<div style="position:absolute;top:-18px;left:-5px;width:10px;height:10px;background:' . $iconBorder . ';border-radius:50%;"></div>
</div>';
} else { // error
echo '<div style="position:relative;width:48px;height:48px;">
<div style="position:absolute;top:0;left:22px;width:5px;height:48px;background:' . $iconBorder . ';transform:rotate(45deg);border-radius:2px;"></div>
<div style="position:absolute;top:0;left:22px;width:5px;height:48px;background:' . $iconBorder . ';transform:rotate(-45deg);border-radius:2px;"></div>
</div>';
}
echo '</div>';
echo '<h1>' . $title . '</h1>';
echo '<p>' . $message . '</p>';
if ($cta_href) {
echo '<div class="row"><a class="btn btn-outline" href="' . $cta_href . '">' . $cta_label . '</a></div>';
}
echo '</div></body></html>';
exit;
}
// =====================
// 1) Token présent & valide
// =====================
$rawToken = trim((string) ($_GET['token'] ?? ''));
if ($rawToken === '') {
ui_exit(
$translations['err_titre'] ?? 'Un problème est survenu',
$translations['err_lien_invalide'] ?? 'Lien invalide.',
400,
'error',
'/',
$translations['retour_acceuil'] ?? 'Retour à l’accueil'
);
}
// Optionnel : on vérifie le format attendu (bin2hex(32) => 64 hexdigits)
if (! preg_match('/^[A-Fa-f0-9]{64}$/', $rawToken)) {
ui_exit(
$translations['err_titre'] ?? 'Un problème est survenu',
$translations['err_lien_invalide'] ?? 'Lien invalide.',
400,
'error',
'/',
$translations['retour_acceuil'] ?? 'Retour à l’accueil'
);
}
// =====================
// 2) Récupération du compte
// =====================
$stmt = $pdo->prepare("SELECT * FROM compte WHERE token_validation = :token LIMIT 1");
$stmt->execute(['token' => $rawToken]);
$compte = $stmt->fetch();
if (! $compte) {
ui_exit(
$translations['err_titre'] ?? 'Un problème est survenu',
$translations['err_token_invalide'] ?? 'Token invalide.',
400,
'error',
'/',
$translations['retour_acceuil'] ?? 'Retour à l’accueil'
);
}
// =====================
// 3) Validité temporelle (6h)
// =====================
try {
if (empty($compte['token_validation_expire'])) {
throw new RuntimeException('token_validation_expire manquant');
}
$expireAt = new DateTime((string) $compte['token_validation_expire']);
} catch (Throwable $e) {
ui_exit(
$translations['err_titre'] ?? 'Un problème est survenu',
$translations['tvalidat_err_lien_invalide'] ?? $translations['err_lien_invalide'] ?? 'Lien invalide.',
400,
'error',
'/',
$translations['retour_acceuil'] ?? 'Retour à l’accueil'
);
}
$now = new DateTime();
if ($now > $expireAt) {
ui_exit(
$translations['err_titre'] ?? 'Un problème est survenu',
$translations['tvalidat_err_lien_expire'] ?? $translations['err_lien_expire'] ?? 'Le lien de validation a expiré.',
410,
'info',
'/connexion.php',
$translations['btn_se_connecter'] ?? 'Se connecter'
);
}
// =====================
// 4) Valider l'email (maj compte)
// =====================
try {
$stmt = $pdo->prepare("
UPDATE compte
SET email_valide = 1,
token_validation = NULL,
token_validation_expire = NULL,
token_autologin = NULL,
token_autologin_expire = NULL
WHERE id = :id
");
$stmt->execute(['id' => $compte['id']]);
} catch (Throwable $e) {
error_log('Validation email - UPDATE échouée: ' . $e->getMessage());
ui_exit(
$translations['err_titre'] ?? 'Un problème est survenu',
$translations['err_serveur'] ?? 'Erreur serveur.',
500,
'error',
'/',
$translations['retour_acceuil'] ?? 'Retour à l’accueil'
);
}
// =====================
// 4bis) Auto-login direct après validation
// =====================
session_regenerate_id(true);
$_SESSION['compte_id'] = (int) $compte['id'];
$_SESSION['role'] = (string) $compte['role'];
$_SESSION['reference_id'] = (int) $compte['reference_id'];
if ($_SESSION['role'] === 'client') {
$_SESSION['client_id'] = (int) $compte['reference_id'];
header('Location: /public/client/informations.php');
exit;
}
if ($_SESSION['role'] === 'praticien') {
$_SESSION['praticien_id'] = (int) $compte['reference_id'];
header('Location: /public/praticien/informations.php');
exit;
}
header('Location: /connexion.php');
exit;
// =====================
// 5) Écran final (succès)
// =====================
// Le texte de succès chez toi contient un lien HTML ; on affiche un message “texte” + un vrai bouton vers la connexion.
$successMsg = isset($translations['success_validation_texte'])
? strip_tags((string) $translations['success_validation_texte'])
: 'Votre compte est confirmé. Vous pouvez maintenant vous connecter.';
ui_exit(
$translations['success_validation_titre'] ?? 'Compte confirmé !',
$successMsg,
200,
'success',
'/connexion.php',
$translations['btn_se_connecter'] ?? 'Se connecter'
);