Files
maria_uslugi/traitement_inscription_praticien.php

394 lines
14 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;
}
// =====================
// Sécurité de base
// =====================
if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') {
ui_exit(
$translations['err_acces_incorrect_titre'] ?? 'Accès incorrect',
$translations['err_acces_incorrect_msg'] ?? "Cette page doit être appelée depuis le formulaire d'inscription.",
405,
'info',
'inscription_praticien.php',
$translations['retour_formulaire'] ?? 'Retour au formulaire'
);
}
// =====================
// Récupération & checks
// =====================
$nom = trim($_POST['nom'] ?? '');
$prenom = trim($_POST['prenom'] ?? '');
$email = trim($_POST['email'] ?? '');
$mdp = $_POST['mot_de_passe'] ?? '';
$siret = preg_replace('/\D/', '', $_POST['siret'] ?? '');
// Champs obligatoires
if ($nom === '' || $prenom === '' || $email === '' || $mdp === '') {
ui_exit(
$translations['err_titre'] ?? 'Un problème est survenu',
$translations['err_champs_obligatoires'] ?? 'Merci de remplir tous les champs obligatoires.',
400,
'error',
'inscription_praticien.php',
$translations['retour_formulaire'] ?? 'Retour au formulaire'
);
}
// Email valide + pas d'injection d'entêtes
if (! filter_var($email, FILTER_VALIDATE_EMAIL) || preg_match('/[\r\n]/', $email)) {
ui_exit(
$translations['err_titre'] ?? 'Un problème est survenu',
$translations['err_email_non_valide'] ?? 'Email invalide.',
400,
'error',
'inscription_praticien.php'
);
}
// SIRET longueur
if (strlen($siret) !== 14) {
ui_exit(
$translations['err_titre'] ?? 'Un problème est survenu',
$translations['err_siret_invalide'] ?? 'Numéro SIRET invalide (14 chiffres requis).',
400,
'error',
'inscription_praticien.php'
);
}
// Luhn
function luhnCheck($num)
{
$arr = str_split(strrev($num));
$sum = 0;
foreach ($arr as $i => $n) {
$n = (int) $n;
if ($i % 2) {
$n *= 2;
if ($n > 9) {
$n -= 9;
}
}
$sum += $n;
}
return $sum % 10 === 0;
}
if (! luhnCheck($siret)) {
ui_exit(
$translations['err_titre'] ?? 'Un problème est survenu',
$translations['err_siret_invalide'] ?? 'Numéro SIRET invalide (échec vérification).',
400,
'error',
'inscription_praticien.php'
);
}
// =====================
// Transaction
// =====================
try {
$pdo->beginTransaction();
// Email déjà utilisé ?
$stmt = $pdo->prepare("SELECT id FROM compte WHERE email = :email LIMIT 1");
$stmt->execute(['email' => $email]);
if ($stmt->fetch()) {
$pdo->rollBack();
ui_exit(
$translations['err_titre'] ?? 'Un problème est survenu',
$translations['err_email_deja_utilise'] ?? 'Cet email est déjà utilisé.',
409,
'error',
'inscription_praticien.php'
);
}
// SIRET déjà utilisé ?
$stmt = $pdo->prepare("SELECT id FROM praticien WHERE siret = :siret LIMIT 1");
$stmt->execute(['siret' => $siret]);
if ($stmt->fetch()) {
$pdo->rollBack();
ui_exit(
$translations['err_titre'] ?? 'Un problème est survenu',
$translations['err_siret_deja_utilise'] ?? 'Ce numéro SIRET est déjà enregistré.',
409,
'error',
'inscription_praticien.php'
);
}
// Acceptation CGU
$accept_cgu = isset($_POST['accept_cgu']) ? 1 : 0;
if ($accept_cgu !== 1) {
$pdo->rollBack();
ui_exit(
$translations['err_titre'] ?? 'Un problème est survenu',
$translations['cgu_obligatoire'] ?? 'Vous devez accepter les CGU.',
400,
'info',
'inscription_praticien.php'
);
}
// 1) Préparer la date d'hier pour forcer l'expiration immédiate
$hier = date('Y-m-d', strtotime('-1 day'));
// 2) Créer le praticien avec les champs d'abonnement initialisés
$stmt = $pdo->prepare("
INSERT INTO praticien (
nom,
prenom,
email,
siret,
accepted_cgu,
abonnement_id,
date_expiration
) VALUES (
:nom,
:prenom,
:email,
:siret,
:accepted_cgu,
NULL,
:date_exp
)
");
$stmt->execute([
'nom' => $nom,
'prenom' => $prenom,
'email' => $email,
'siret' => $siret,
'accepted_cgu' => $accept_cgu,
'date_exp' => $hier, // On met hier pour que le script de vérification dise "C'est expiré !"
]);
$praticien_id = (int) $pdo->lastInsertId();
// 2) Créer le compte
$mot_de_passe_hash = password_hash($mdp, PASSWORD_DEFAULT);
$token = bin2hex(random_bytes(32));
$token_validation_expire = (new DateTime('+6 hours'))->format('Y-m-d H:i:s');
$stmt = $pdo->prepare("
INSERT INTO compte (
email,
mot_de_passe,
role,
reference_id,
token_validation,
token_validation_expire,
email_valide
)
VALUES (
:email,
:mdp,
'praticien',
:ref_id,
:token,
:token_expire,
0
)
");
$stmt->execute([
'email' => $email,
'mdp' => $mot_de_passe_hash,
'ref_id' => $praticien_id,
'token' => $token,
'token_expire' => $token_validation_expire,
]);
// Commit avant envoi mail
$pdo->commit();
} catch (Throwable $e) {
if ($pdo->inTransaction()) {
$pdo->rollBack();
}
error_log('Inscription praticien - DB error: ' . $e->getMessage());
ui_exit(
$translations['err_titre'] ?? 'Un problème est survenu',
$translations['err_serveur'] ?? 'Erreur serveur.',
500,
'error',
'/'
);
}
// =====================
// Email de validation
// =====================
$validation_url = "https://uslugi.fr/validation.php?token=" . urlencode($token);
$validation_url_html = htmlspecialchars($validation_url, ENT_QUOTES, 'UTF-8');
$prenom_nom = htmlspecialchars("$prenom $nom", ENT_QUOTES, 'UTF-8');
$sujet = $translations['mail_valid_sujet'];
// Corps HTML mail
$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'>" . sprintf($translations['mail_valid_bonjour_nom'], $prenom_nom) . "</div>
<p>" . $translations['mail_valid_merci_praticien'] . "</p>
<p>" . $translations['mail_valid_action'] . "</p>
<a href='$validation_url_html' class='btn'>" . $translations['mail_valid_btn'] . "</a>
<p class='link-fallback'>" . $translations['mail_valid_fallback'] . "<br>
<a href='$validation_url_html'>$validation_url_html</a>
</p>
<div class='footer'>
" . $translations['mail_valid_expire'] . "<br>
" . $translations['mail_valid_ignore'] . "<br><br>
" . $translations['mail_valid_signature'] . "
</div>
</div>
</body>
</html>";
// Texte alternative
$text = strip_tags(
sprintf($translations['mail_valid_bonjour_nom'], "$prenom $nom") . "\n\n" .
$translations['mail_valid_merci_praticien'] . "\n" .
$translations['mail_valid_action'] . "\n" .
($translations['mail_valid_fallback'] ?? 'Si le bouton ne fonctionne pas, utilisez ce lien :') . "\n" .
$validation_url . "\n\n" .
$translations['mail_valid_expire'] . "\n" .
$translations['mail_valid_ignore'] . "\n" .
($translations['mail_valid_signature'] ?? 'USLUGI.FR')
);
// Envoi
list($sent, $err) = uslugi_mail(
$email,
$sujet,
$html,
$text,
[
'to_name' => "$prenom $nom",
]
);
if (! $sent) {
error_log("Validation mail NOT sent to $email : $err");
// On ne bloque pas l’utilisateur : il pourra redemander un mail.
}
// =====================
// Écran final succès
// =====================
echo '
<!DOCTYPE html><html lang="fr"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>' . htmlspecialchars($translations['insc_merci_titre'] ?? 'Merci !', ENT_QUOTES, 'UTF-8') . '</title>
<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:600px;width:98%;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}
.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">
<div style="width:102px;height:102px;border-radius:50%;background:rgba(30,128,80,.08);border:3px solid rgba(30,128,80,.20);display:flex;align-items:center;justify-content:center;margin:0 auto 20px;">
<div style="width:48px;height:36px;border:5px solid #1e8050;border-top:0;border-left:0;transform:rotate(45deg);"></div>
</div>
<h1>' . htmlspecialchars($translations['insc_merci_titre'] ?? 'Merci !', ENT_QUOTES, 'UTF-8') . '</h1>
<p>' . htmlspecialchars($translations['insc_merci_ligne1'] ?? 'Votre compte a bien été créé.', ENT_QUOTES, 'UTF-8') . '</p>
<p>' . htmlspecialchars($translations['insc_merci_ligne2'] ?? 'Vérifiez vos emails pour valider votre adresse.', ENT_QUOTES, 'UTF-8') . '</p>
<div class="row">
<a class="btn btn-outline" href="/">' . htmlspecialchars($translations['retour_acceuil'] ?? 'Retour à l’accueil', ENT_QUOTES, 'UTF-8') . '</a>
</div>
</div>
</body></html>';