214 lines
7.9 KiB
PHP
214 lines
7.9 KiB
PHP
<?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'
|
||
);
|