Connexion tocken, stripe 3D, tracking analytic
This commit is contained in:
1 parent
1deb30fcd1
commit
bd311da711
17 files changed
+3324
-455
No files matched your search
@@ -0,0 +1,292 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
require_once __DIR__ . '/public/includes/init_auth.php';
|
||||
|
||||
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';
|
||||
|
||||
$iconBorder = '#B91C1C';
|
||||
$iconBg = 'rgba(185,28,28,.08)';
|
||||
$iconRing = 'rgba(185,28,28,.25)';
|
||||
$checkCSS = '';
|
||||
|
||||
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">';
|
||||
|
||||
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 {
|
||||
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;
|
||||
}
|
||||
|
||||
if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') {
|
||||
ui_exit(
|
||||
$translations['tvalidat_err_acces_titre'] ?? 'Accès incorrect',
|
||||
$translations['tvalidat_err_acces_msg'] ?? 'Accès invalide.',
|
||||
405,
|
||||
'info',
|
||||
'/connexion.php',
|
||||
$translations['btn_se_connecter'] ?? 'Se connecter'
|
||||
);
|
||||
}
|
||||
|
||||
$email = trim((string) ($_POST['email'] ?? ''));
|
||||
|
||||
if ($email === '' || ! filter_var($email, FILTER_VALIDATE_EMAIL) || preg_match('/[\r\n]/', $email)) {
|
||||
ui_exit(
|
||||
$translations['err_titre'] ?? 'Un problème est survenu',
|
||||
$translations['tvalidat_err_email_invalide'] ?? 'Email invalide.',
|
||||
400,
|
||||
'error',
|
||||
'/connexion.php',
|
||||
$translations['btn_se_connecter'] ?? 'Se connecter'
|
||||
);
|
||||
}
|
||||
|
||||
$pending = $_SESSION['pending_validation_resend'] ?? null;
|
||||
|
||||
if (
|
||||
empty($pending['authorized']) ||
|
||||
empty($pending['compte_id']) ||
|
||||
empty($pending['email']) ||
|
||||
empty($pending['expires_at']) ||
|
||||
(int) $pending['expires_at'] < time() ||
|
||||
! hash_equals((string) $pending['email'], $email)
|
||||
) {
|
||||
unset($_SESSION['pending_validation_resend']);
|
||||
|
||||
ui_exit(
|
||||
$translations['err_titre'] ?? 'Un problème est survenu',
|
||||
$translations['tvalidat_err_action_non_autorisee'] ?? 'Action non autorisée. Merci de vous reconnecter.',
|
||||
403,
|
||||
'error',
|
||||
'/connexion.php',
|
||||
$translations['btn_se_connecter'] ?? 'Se connecter'
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT id, email, role, reference_id, email_valide
|
||||
FROM compte
|
||||
WHERE id = :id AND email = :email
|
||||
LIMIT 1
|
||||
");
|
||||
$stmt->execute([
|
||||
'id' => (int) $pending['compte_id'],
|
||||
'email' => $email,
|
||||
]);
|
||||
$compte = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if (! $compte) {
|
||||
unset($_SESSION['pending_validation_resend']);
|
||||
ui_exit(
|
||||
$translations['err_titre'] ?? 'Un problème est survenu',
|
||||
$translations['tvalidat_err_compte_introuvable'] ?? 'Compte introuvable.',
|
||||
404,
|
||||
'error',
|
||||
'/connexion.php',
|
||||
$translations['btn_se_connecter'] ?? 'Se connecter'
|
||||
);
|
||||
}
|
||||
|
||||
if (! empty($compte['email_valide'])) {
|
||||
unset($_SESSION['pending_validation_resend']);
|
||||
ui_exit(
|
||||
$translations['tvalidat_info_titre'] ?? 'Information',
|
||||
$translations['tvalidat_info_email_deja_valide'] ?? 'Votre adresse email est déjà validée.',
|
||||
200,
|
||||
'info',
|
||||
'/connexion.php',
|
||||
$translations['btn_se_connecter'] ?? 'Se connecter'
|
||||
);
|
||||
}
|
||||
|
||||
$prenom = '';
|
||||
$nom = '';
|
||||
|
||||
if (($compte['role'] ?? '') === 'praticien') {
|
||||
$stmt = $pdo->prepare("SELECT prenom, nom FROM praticien WHERE id = :id LIMIT 1");
|
||||
$stmt->execute(['id' => (int) $compte['reference_id']]);
|
||||
$profil = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
} elseif (($compte['role'] ?? '') === 'client') {
|
||||
$stmt = $pdo->prepare("SELECT prenom, nom FROM client WHERE id = :id LIMIT 1");
|
||||
$stmt->execute(['id' => (int) $compte['reference_id']]);
|
||||
$profil = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
} else {
|
||||
$profil = false;
|
||||
}
|
||||
|
||||
if ($profil) {
|
||||
$prenom = trim((string) ($profil['prenom'] ?? ''));
|
||||
$nom = trim((string) ($profil['nom'] ?? ''));
|
||||
}
|
||||
|
||||
$token = bin2hex(random_bytes(32));
|
||||
$token_validation_expire = (new DateTime('+6 hours'))->format('Y-m-d H:i:s');
|
||||
$token_autologin = bin2hex(random_bytes(32));
|
||||
$token_autologin_expire = (new DateTime('+60 minutes'))->format('Y-m-d H:i:s');
|
||||
|
||||
$stmt = $pdo->prepare("
|
||||
UPDATE compte
|
||||
SET token_validation = :token,
|
||||
token_validation_expire = :token_expire,
|
||||
token_autologin = :al,
|
||||
token_autologin_expire = :al_exp
|
||||
WHERE id = :id
|
||||
LIMIT 1
|
||||
");
|
||||
$stmt->execute([
|
||||
'token' => $token,
|
||||
'token_expire' => $token_validation_expire,
|
||||
'al' => $token_autologin,
|
||||
'al_exp' => $token_autologin_expire,
|
||||
'id' => (int) $compte['id'],
|
||||
]);
|
||||
|
||||
} catch (Throwable $e) {
|
||||
error_log('renvoyer_validat_mail.php - DB error: ' . $e->getMessage());
|
||||
ui_exit(
|
||||
$translations['err_titre'] ?? 'Un problème est survenu',
|
||||
$translations['err_serveur'] ?? 'Erreur serveur.',
|
||||
500,
|
||||
'error',
|
||||
'/connexion.php',
|
||||
$translations['btn_se_connecter'] ?? 'Se connecter'
|
||||
);
|
||||
}
|
||||
|
||||
$validation_url = "https://uslugi.fr/validation.php?token=" . urlencode($token) . "&al=" . urlencode($token_autologin);
|
||||
$validation_url_html = htmlspecialchars($validation_url, ENT_QUOTES, 'UTF-8');
|
||||
|
||||
$prenom_nom = trim($prenom . ' ' . $nom);
|
||||
$to_name = $prenom_nom !== '' ? $prenom_nom : $email;
|
||||
|
||||
$sujet = $translations['mail_valid_sujet'] ?? 'Validation de votre adresse email';
|
||||
|
||||
$html = "<!DOCTYPE html>
|
||||
<html lang='fr'>
|
||||
<head>
|
||||
<meta charset='UTF-8'>
|
||||
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
|
||||
<meta name='viewport' content='width=device-width, initial-scale=1.0'>
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; background-color:#f4f4f4; padding:20px; }
|
||||
.mail-container { max-width:600px; margin:auto; background:#fff; padding:30px; border-radius:8px; box-shadow:0 0 10px rgba(0,0,0,0.1); }
|
||||
.title { font-size:20px; font-weight:bold; color:#333; margin-bottom:20px; }
|
||||
.btn { display:inline-block; margin-top:20px; padding:12px 24px; background-color:#E03C3F; color:#fff; text-decoration:none; border-radius:999px; font-weight:bold; }
|
||||
.footer { margin-top:30px; font-size:13px; color:#888; }
|
||||
.link-fallback { word-break: break-all; font-size:13px; margin-top:15px; color:#555; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class='mail-container'>
|
||||
<div class='title'>" . htmlspecialchars(sprintf($translations['mail_valid_bonjour_nom'] ?? 'Bonjour %s,', $to_name), ENT_QUOTES, 'UTF-8') . "</div>
|
||||
<p>" . htmlspecialchars($translations['tvalidat_mail_intro'] ?? 'Voici un nouveau lien pour valider votre adresse email.', ENT_QUOTES, 'UTF-8') . "</p>
|
||||
<p>" . htmlspecialchars($translations['mail_valid_action'] ?? 'Cliquez sur le bouton ci-dessous pour confirmer votre adresse.', ENT_QUOTES, 'UTF-8') . "</p>
|
||||
<a href='{$validation_url_html}' class='btn'>" . htmlspecialchars($translations['mail_valid_btn'] ?? 'Valider mon adresse email', ENT_QUOTES, 'UTF-8') . "</a>
|
||||
<p class='link-fallback'>" . htmlspecialchars($translations['mail_valid_fallback'] ?? 'Si le bouton ne fonctionne pas, utilisez ce lien :', ENT_QUOTES, 'UTF-8') . "<br>
|
||||
<a href='{$validation_url_html}'>{$validation_url_html}</a>
|
||||
</p>
|
||||
<div class='footer'>
|
||||
" . htmlspecialchars($translations['mail_valid_expire'] ?? 'Ce lien expire prochainement.', ENT_QUOTES, 'UTF-8') . "<br>
|
||||
" . htmlspecialchars($translations['mail_valid_ignore'] ?? 'Si vous n’êtes pas à l’origine de cette demande, ignorez ce message.', ENT_QUOTES, 'UTF-8') . "<br><br>
|
||||
" . htmlspecialchars($translations['mail_valid_signature'] ?? 'USLUGI.FR', ENT_QUOTES, 'UTF-8') . "
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>";
|
||||
|
||||
$text = strip_tags(
|
||||
sprintf($translations['mail_valid_bonjour_nom'] ?? 'Bonjour %s,', $to_name) . "\n\n" .
|
||||
($translations['tvalidat_mail_intro'] ?? 'Voici un nouveau lien pour valider votre adresse email.') . "\n" .
|
||||
($translations['mail_valid_action'] ?? 'Cliquez sur le lien suivant pour confirmer votre adresse.') . "\n" .
|
||||
$validation_url . "\n\n" .
|
||||
($translations['mail_valid_expire'] ?? 'Ce lien expire prochainement.') . "\n" .
|
||||
($translations['mail_valid_ignore'] ?? 'Si vous n\'êtes pas à l\'origine de cette demande, ignorez ce message.') . "\n\n" .
|
||||
($translations['mail_valid_signature'] ?? 'USLUGI.FR')
|
||||
);
|
||||
|
||||
list($sent, $err) = uslugi_mail(
|
||||
$email,
|
||||
$sujet,
|
||||
$html,
|
||||
$text,
|
||||
['to_name' => $to_name]
|
||||
);
|
||||
|
||||
unset($_SESSION['pending_validation_resend']);
|
||||
|
||||
if (! $sent) {
|
||||
error_log("Renvoi validation mail NOT sent to {$email}: {$err}");
|
||||
ui_exit(
|
||||
$translations['err_titre'] ?? 'Un problème est survenu',
|
||||
$translations['tvalidat_err_envoi'] ?? 'Le mail n’a pas pu être envoyé. Merci de réessayer plus tard.',
|
||||
500,
|
||||
'error',
|
||||
'/connexion.php',
|
||||
$translations['btn_se_connecter'] ?? 'Se connecter'
|
||||
);
|
||||
}
|
||||
|
||||
ui_exit(
|
||||
$translations['tvalidat_success_titre'] ?? 'Email envoyé',
|
||||
$translations['tvalidat_success_msg'] ?? 'Un nouveau lien de validation vient d’être envoyé à votre adresse email.',
|
||||
200,
|
||||
'success',
|
||||
'/connexion.php',
|
||||
$translations['btn_se_connecter'] ?? 'Se connecter'
|
||||
);
|
||||
Reference in new issue
Block a user