Files
maria_uslugi/valider_email_cabinet.php
2026-03-05 10:25:39 +01:00

238 lines
9.2 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
require_once __DIR__ . '/../includes/bootstrap_global.php';
// Helpers
function h($s){ return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8'); }
function dt_to_ts(?string $s): int { return $s ? strtotime($s) ?: 0 : 0; }
// ------------------------------------------------------------
// 1) Arrivée par lien GET ?token=...&email=...
// ------------------------------------------------------------
$erreur = '';
$success = '';
// Si on arrive via le lien d'activation
if (isset($_GET['token'], $_GET['email'])) {
$token = trim((string)$_GET['token']);
$email = strtolower(trim((string)$_GET['email']));
if ($token === '' || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
$erreur = $translations['err_lien_invalide'] ?? 'Lien invalide.';
} else {
// Vérifier que le token/email existent et sont dans la fenêtre 24h
$sql = "SELECT id, cree_le, modifie_le, token_validation
FROM compte
WHERE email = :email AND token_validation = :token
LIMIT 1";
$stmt = $pdo->prepare($sql);
$stmt->execute([':email' => $email, ':token' => $token]);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$row) {
$erreur = $translations['err_lien_invalide'] ?? 'Lien invalide.';
} else {
// Fenêtre de validité 24h
$t0 = max(dt_to_ts($row['modifie_le'] ?? null), dt_to_ts($row['cree_le'] ?? null));
$ageH = (time() - $t0) / 3600;
if ($ageH > 24) {
$erreur = $translations['err_lien_expire'] ?? 'Le lien a expiré. Demandez un nouvel envoi.';
} else {
// On autorise la page de changement de mot de passe via session
$_SESSION['reset_email'] = $email;
$_SESSION['code_valide'] = true;
// Redirection propre (on retire token/email de l'URL)
$lang = $_SESSION['lang'] ?? 'ru';
header('Location: valider_email_cabinet.php');
exit;
}
}
}
}
// ------------------------------------------------------------
// 2) Sécurité d’accès à la page sans token
// ------------------------------------------------------------
if (!isset($_SESSION['reset_email'], $_SESSION['code_valide']) || !$_SESSION['code_valide']) {
// Si pas de session valide ET pas d’erreur déjà définie → rediriger
if ($erreur === '') {
header("Location: mdp_oublie.php");
exit;
}
}
// ------------------------------------------------------------
// 3) Soumission du nouveau mot de passe
// ------------------------------------------------------------
if ($_SERVER['REQUEST_METHOD'] === 'POST' && empty($success) && empty($erreur)) {
$mdp1 = $_POST['mot_de_passe'] ?? '';
$mdp2 = $_POST['confirm_mot_de_passe'] ?? '';
if (strlen($mdp1) < 8 || $mdp1 !== $mdp2) {
$erreur = $translations['erreur_mdp_invalides'] ?? 'Mot de passe invalide.';
} else {
try {
$hash = password_hash($mdp1, PASSWORD_DEFAULT);
$stmt = $pdo->prepare("
UPDATE compte
SET mot_de_passe = :hash,
email_valide = 1,
token_validation = NULL,
modifie_le = NOW()
WHERE email = :email
LIMIT 1
");
$stmt->execute([
':hash' => $hash,
':email' => $_SESSION['reset_email'],
]);
// Nettoyage session (garder la langue)
$lang = $_SESSION['lang'] ?? 'ru';
session_unset();
session_destroy();
session_start();
$_SESSION['lang'] = $lang;
$success = $translations['success_mdp_mis_a_jour'] ?? 'Mot de passe mis à jour. Votre email est confirmé.';
} catch (Throwable $e) {
error_log('valider_mail.php update pwd: '.$e->getMessage());
$erreur = $translations['erreur_generique'] ?? 'Erreur, veuillez réessayer.';
}
}
}
?>
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title><?= h($translations['nouveau_mdp_title'] ?? 'Nouveau mot de passe') ?></title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="<?= asset('/includes/site_style.css') ?>">
<link rel="stylesheet" href="<?= asset('/includes/mobil_style.css') ?>">
<style>
.strength-bar { height: 8px; display: flex; margin-bottom: 10px; border-radius: 5px; overflow: hidden; }
.strength-fill { flex: 1; background: #ccc; transition: background-color 0.3s ease; }
.toggle-password { position: absolute; right: 10px; top: 50%; transform: translateY(-50%); cursor: pointer; font-size: 18px; }
.field-wrapper { position: relative; }
</style>
</head>
<body>
<header class="site-header">
<div class="container">
<div class="brand"><a href="index.php"><img src="public/uploads/img/logo.png" width="130" alt="USLUGI.FR"></a></div>
<nav class="header-actions">
<div class="lang-switch">
<?php require_once __DIR__ . '/includes/menu_langue.php';?>
</div>
</nav>
</div>
</header>
<div class="main">
<div class="card shadow-sm p-4" style="min-width: 380px; max-width: 480px; width: 100%;">
<h3 class="mb-4 text-center"><?= h($translations['nouveau_mdp_h3'] ?? 'Définir un nouveau mot de passe') ?></h3>
<?php if (!empty($erreur)): ?>
<div class="alert alert-danger py-2"><?= h($erreur) ?></div>
<div class="text-center">
<a class="btn btn-danger" href="mdp_oublie.php"><?= h($translations['renvoyer_lien'] ?? 'Renvoyer un lien') ?></a>
</div>
<?php endif; ?>
<?php if (!empty($success)): ?>
<div class="alert alert-primary py-2 text-center">
<div><?= h($success) ?></div>
</div>
<a href="connexion.php" class="btn btn-danger"><?= h($translations['btn_se_connecter'] ?? 'Se connecter') ?></a>
<?php endif; ?>
<?php if (empty($success) && empty($erreur)): ?>
<form method="POST">
<!-- Nouveau mot de passe -->
<div class="mb-3 field-wrapper">
<input type="password" name="mot_de_passe" id="mot_de_passe" class="form-control" placeholder="<?= h($translations['nouveau_mdp_placeholder'] ?? 'Nouveau mot de passe') ?>" required>
<span class="toggle-password" onclick="toggle('mot_de_passe')">👁️</span>
</div>
<div id="niveau-securite" class="mb-2 text-muted"><?= h($translations['mdp_regle_min'] ?? 'Au moins 8 caractères, lettres et chiffres.') ?></div>
<div class="strength-bar mb-3">
<div class="strength-fill"></div>
<div class="strength-fill"></div>
<div class="strength-fill"></div>
</div>
<!-- Confirmation mot de passe -->
<div class="mb-4 field-wrapper">
<input type="password" name="confirm_mot_de_passe" id="confirm_mot_de_passe" class="form-control" placeholder="<?= h($translations['confirm_mdp_placeholder'] ?? 'Confirmer le mot de passe') ?>" required>
<span class="toggle-password" onclick="toggle('confirm_mot_de_passe')">👁️</span>
</div>
<button type="submit" class="btn btn-primary w-100"><?= h($translations['btn_valider'] ?? 'Valider') ?></button>
</form>
<?php endif; ?>
</div>
<script>
const T = {
rule: '<?= addslashes($translations['mdp_regle_min'] ?? 'Au moins 8 caractères, lettres et chiffres.') ?>',
weak: '<?= addslashes($translations['securite_faible'] ?? 'Sécurité faible') ?>',
medium: '<?= addslashes($translations['securite_moyen'] ?? 'Sécurité moyenne') ?>',
strong: '<?= addslashes($translations['securite_fort'] ?? 'Sécurité forte') ?>'
};
function toggle(id) {
const el = document.getElementById(id);
el.type = el.type === 'password' ? 'text' : 'password';
}
document.getElementById('mot_de_passe')?.addEventListener('input', function () {
const val = this.value;
const segments = document.querySelectorAll('.strength-fill');
const niveauText = document.getElementById('niveau-securite');
segments.forEach(seg => seg.style.backgroundColor = '#ccc');
niveauText.textContent = T.rule;
niveauText.style.color = '#666';
const longOk = val.length >= 8;
const lettre = /[A-Za-z]/.test(val);
const chiffre = /\d/.test(val);
const maj = /[A-Z]/.test(val);
const special = /[^A-Za-z0-9]/.test(val);
let force = 0;
if (longOk && lettre && chiffre) force++;
if (maj) force++;
if (special) force++;
if (force === 1) {
segments[0].style.backgroundColor = 'red';
niveauText.textContent = T.weak;
niveauText.style.color = 'red';
} else if (force === 2) {
segments[0].style.backgroundColor = 'orange';
segments[1].style.backgroundColor = 'orange';
niveauText.textContent = T.medium;
niveauText.style.color = 'orange';
} else if (force >= 3) {
segments.forEach(seg => seg.style.backgroundColor = 'green');
niveauText.textContent = T.strong;
niveauText.style.color = 'green';
}
});
</script>
</div>
<footer class="site-footer">
<div class="container">
<p><?php echo $translations['copyr']?></p>
</div>
</footer>
</body>
</html>