Files
maria_uslugi/traitement_inscription_client.php

311 lines
12 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;
}
// =====================
// Accès direct interdit
// =====================
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_client.php',
$translations['retour_formulaire'] ?? 'Retour au formulaire'
);
}
// =====================
// Données & vérifs
// =====================
$nom = trim($_POST['nom'] ?? '');
$prenom = trim($_POST['prenom'] ?? '');
$email = trim($_POST['email'] ?? '');
$mdp = $_POST['mot_de_passe'] ?? '';
// 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_client.php',
$translations['retour_formulaire'] ?? 'Retour au formulaire'
);
}
// Email valide + pas d’injection CR/LF
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_client.php'
);
}
// Acceptation CGU
$accept_cgu = isset($_POST['accept_cgu']) ? 1 : 0;
if ($accept_cgu !== 1) {
ui_exit(
$translations['err_titre'] ?? 'Un problème est survenu',
$translations['cgu_obligatoire'] ?? 'Vous devez accepter les CGU.',
400,
'info',
'inscription_client.php'
);
}
// =====================
// Transaction (client + compte)
// =====================
try {
$pdo->beginTransaction();
// Email déjà pris ?
$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_client.php'
);
}
// 1) Insert client
$stmt = $pdo->prepare("INSERT INTO client (nom, prenom, email, accepted_cgu) VALUES (:nom, :prenom, :email, :accepted_cgu)");
$stmt->execute([
'nom' => $nom,
'prenom' => $prenom,
'email' => $email,
'accepted_cgu' => $accept_cgu,
]);
$client_id = (int) $pdo->lastInsertId();
// 2) Créer 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,
'client',
:ref_id,
:token,
:token_expire,
0
)
");
$stmt->execute([
'email' => $email,
'mdp' => $mot_de_passe_hash,
'ref_id' => $client_id,
'token' => $token,
'token_expire' => $token_validation_expire,
]);
// Commit avant l’envoi du mail
$pdo->commit();
} catch (Throwable $e) {
if ($pdo->inTransaction()) {
$pdo->rollBack();
}
error_log('Inscription client - 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_safe = htmlspecialchars("$prenom $nom", ENT_QUOTES, 'UTF-8');
$sujet = $translations['mail_valid_sujet'];
$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_safe) . "</div>
<p>" . $translations['mail_valid_merci'] . "</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>";
$text = strip_tags(
sprintf($translations['mail_valid_bonjour_nom'], "$prenom $nom") . "\n\n" .
$translations['mail_valid_merci'] . "\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 du mail (non bloquant)
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.
}
// =====================
// É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>';