Version stable, aprelic, connexion CFRS et autres corrections
This commit is contained in:
1 parent
865de8a976
commit
e9d0010451
62 files changed
+17483
-7256
No files matched your search
@@ -292,9 +292,14 @@
|
||||
<li onclick="closeMenu(); openContactAdmin()">
|
||||
<?php echo htmlspecialchars($translations['contact_admin']) ?>
|
||||
</li>
|
||||
<li onclick="location.href='/public/deconnexion.php'">
|
||||
<?php echo htmlspecialchars($translations['menu_deconnexion']) ?>
|
||||
</li>
|
||||
<li class="menu-item-form">
|
||||
<form method="POST" action="/public/deconnexion.php" class="menu-logout-form">
|
||||
<input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars(ensure_csrf_token(), ENT_QUOTES, 'UTF-8') ?>">
|
||||
<button type="submit" class="menu-logout-btn">
|
||||
<?php echo htmlspecialchars($translations['menu_deconnexion'] ?? 'Déconnexion') ?>
|
||||
</button>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
@@ -1,59 +1,58 @@
|
||||
<?php
|
||||
// ⚠️ NE PAS inclure contact_admin.php ici (risque d'exécution à l'inclusion)
|
||||
require_once __DIR__ . '/../contact_admin.php';
|
||||
// ⚠️ NE PAS inclure contact_admin.php ici (risque d'exécution à l'inclusion)
|
||||
require_once __DIR__ . '/../contact_admin.php';
|
||||
|
||||
$sec_uid = (int) ($_SESSION['compte_id'] ?? $_SESSION['user_id'] ?? 0);
|
||||
|
||||
$sec_uid = (int)($_SESSION['compte_id'] ?? $_SESSION['user_id'] ?? 0);
|
||||
// =====================================================
|
||||
// [CONTEXT UTILISATEUR] — Initiales avatar secrétaire
|
||||
// =====================================================
|
||||
$prenomUser = trim((string) ($_SESSION['user_prenom'] ?? $_SESSION['prenom'] ?? ''));
|
||||
$nomUser = trim((string) ($_SESSION['user_nom'] ?? $_SESSION['nom'] ?? ''));
|
||||
|
||||
// =====================================================
|
||||
// [CONTEXT UTILISATEUR] — Initiales avatar secrétaire
|
||||
// =====================================================
|
||||
$prenomUser = trim((string)($_SESSION['user_prenom'] ?? $_SESSION['prenom'] ?? ''));
|
||||
$nomUser = trim((string)($_SESSION['user_nom'] ?? $_SESSION['nom'] ?? ''));
|
||||
if ($prenomUser === '' && $nomUser === '') {
|
||||
// petit fallback
|
||||
$prenomUser = 'Secr';
|
||||
$nomUser = 'Etaire';
|
||||
}
|
||||
$initiales = mb_strtoupper(
|
||||
mb_substr($prenomUser, 0, 1, 'UTF-8') .
|
||||
mb_substr($nomUser, 0, 1, 'UTF-8'),
|
||||
'UTF-8'
|
||||
);
|
||||
|
||||
if ($prenomUser === '' && $nomUser === '') {
|
||||
// petit fallback
|
||||
$prenomUser = 'Secr';
|
||||
$nomUser = 'Etaire';
|
||||
}
|
||||
$initiales = mb_strtoupper(
|
||||
mb_substr($prenomUser, 0, 1, 'UTF-8') .
|
||||
mb_substr($nomUser, 0, 1, 'UTF-8'),
|
||||
'UTF-8'
|
||||
);
|
||||
// =====================================================
|
||||
// [PRATICIEN COURANT] — affichage nom/prénom dans le header
|
||||
// - on prend ?praticien_id si présent, sinon une valeur de session si dispo
|
||||
// =====================================================
|
||||
$currentPraticienId = null;
|
||||
if (isset($_GET['praticien_id'])) {
|
||||
$currentPraticienId = (int) $_GET['praticien_id'];
|
||||
$_SESSION['current_praticien_id'] = $currentPraticienId; // mémorise pour les autres pages
|
||||
} elseif (! empty($_SESSION['current_praticien_id'])) {
|
||||
$currentPraticienId = (int) $_SESSION['current_praticien_id'];
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// [PRATICIEN COURANT] — affichage nom/prénom dans le header
|
||||
// - on prend ?praticien_id si présent, sinon une valeur de session si dispo
|
||||
// =====================================================
|
||||
$currentPraticienId = null;
|
||||
if (isset($_GET['praticien_id'])) {
|
||||
$currentPraticienId = (int)$_GET['praticien_id'];
|
||||
$_SESSION['current_praticien_id'] = $currentPraticienId; // mémorise pour les autres pages
|
||||
} elseif (!empty($_SESSION['current_praticien_id'])) {
|
||||
$currentPraticienId = (int)$_SESSION['current_praticien_id'];
|
||||
}
|
||||
$currentPraticienName = '';
|
||||
if ($currentPraticienId) {
|
||||
$stmt = $pdo->prepare("SELECT id, prenom, nom FROM praticien WHERE id = ? LIMIT 1");
|
||||
$stmt->execute([$currentPraticienId]);
|
||||
if ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$p = trim((string) ($row['prenom'] ?? ''));
|
||||
$n = trim((string) ($row['nom'] ?? ''));
|
||||
$pid = trim((string) ($row['id'] ?? ''));
|
||||
$currentPraticienName = trim($p . ' ' . $n);
|
||||
}
|
||||
}
|
||||
|
||||
$currentPraticienName = '';
|
||||
if ($currentPraticienId) {
|
||||
$stmt = $pdo->prepare("SELECT id, prenom, nom FROM praticien WHERE id = ? LIMIT 1");
|
||||
$stmt->execute([$currentPraticienId]);
|
||||
if ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$p = trim((string)($row['prenom'] ?? ''));
|
||||
$n = trim((string)($row['nom'] ?? ''));
|
||||
$pid = trim((string)($row['id'] ?? ''));
|
||||
$currentPraticienName = trim($p.' '.$n);
|
||||
}
|
||||
}
|
||||
// =====================================================
|
||||
// [Liste Praticien avec autorisations]
|
||||
// =====================================================
|
||||
$pid = (int) $currentPraticienId;
|
||||
$permRow = null;
|
||||
|
||||
// =====================================================
|
||||
// [Liste Praticien avec autorisations]
|
||||
// =====================================================
|
||||
$pid = (int)$currentPraticienId;
|
||||
$permRow = null;
|
||||
|
||||
if ($pid && $sec_uid) {
|
||||
$q = $pdo->prepare("
|
||||
if ($pid && $sec_uid) {
|
||||
$q = $pdo->prepare("
|
||||
SELECT sp.can_manage_rdv, sp.can_edit_slots
|
||||
FROM secretaire_praticien sp
|
||||
WHERE sp.secretaire_user_id = :u
|
||||
@@ -61,48 +60,50 @@ if ($pid && $sec_uid) {
|
||||
AND sp.is_active = 1
|
||||
LIMIT 1
|
||||
");
|
||||
$q->execute(['u' => $sec_uid, 'pid' => $pid]);
|
||||
$permRow = $q->fetch(PDO::FETCH_ASSOC) ?: null;
|
||||
}
|
||||
$q->execute(['u' => $sec_uid, 'pid' => $pid]);
|
||||
$permRow = $q->fetch(PDO::FETCH_ASSOC) ?: null;
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// [RETOUR / REFERER SÉCURISÉ]
|
||||
// =====================================================
|
||||
$ref = $_SERVER['HTTP_REFERER'] ?? '';
|
||||
$host = $_SERVER['HTTP_HOST'] ?? '';
|
||||
$safeRef = '';
|
||||
if ($ref) {
|
||||
$u = parse_url($ref);
|
||||
if (! empty($u['host']) && $u['host'] === $host) {
|
||||
$safeRef = $ref;
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// [RETOUR / REFERER SÉCURISÉ]
|
||||
// =====================================================
|
||||
$ref = $_SERVER['HTTP_REFERER'] ?? '';
|
||||
$host = $_SERVER['HTTP_HOST'] ?? '';
|
||||
$safeRef = '';
|
||||
if ($ref) {
|
||||
$u = parse_url($ref);
|
||||
if (!empty($u['host']) && $u['host'] === $host) $safeRef = $ref;
|
||||
}
|
||||
$fallbackBack = $safeRef ?: '/public/cabinet/dashboard.php';
|
||||
}
|
||||
$fallbackBack = $safeRef ?: '/public/cabinet/dashboard.php';
|
||||
|
||||
// =====================================================
|
||||
// [DETECTION MOBILE]
|
||||
// =====================================================
|
||||
$is_mobile = preg_match('/Mobile|Android|iPhone|iPad/i', $_SERVER['HTTP_USER_AGENT'] ?? '');
|
||||
// =====================================================
|
||||
// [DETECTION MOBILE]
|
||||
// =====================================================
|
||||
$is_mobile = preg_match('/Mobile|Android|iPhone|iPad/i', $_SERVER['HTTP_USER_AGENT'] ?? '');
|
||||
?>
|
||||
<!doctype html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<title><?= htmlspecialchars($PAGE_TITLE ?? 'Cabinet', ENT_QUOTES, 'UTF-8') ?></title>
|
||||
<?= $HEAD_EXTRA ?? '' ?>
|
||||
<title><?php echo htmlspecialchars($PAGE_TITLE ?? 'Cabinet', ENT_QUOTES, 'UTF-8') ?></title>
|
||||
<?php echo $HEAD_EXTRA ?? '' ?>
|
||||
|
||||
<!-- Montserrat -->
|
||||
|
||||
|
||||
|
||||
<!-- Bootstrap -->
|
||||
<link href="/css/bootstrap.min.css" rel="stylesheet">
|
||||
|
||||
<!-- Styles (chemins corrigés) -->
|
||||
<link rel="stylesheet" href="<?= asset('/includes/site_style.css') ?>">
|
||||
<link rel="stylesheet" href="<?= asset('/includes/custom_style.css') ?>"> <!-- ta home -->
|
||||
|
||||
<link rel="stylesheet" href="<?= asset('/includes/admin_style.css') ?>">
|
||||
<link rel="stylesheet" href="<?= asset('/includes/mobil_style.css') ?>">
|
||||
<link rel="stylesheet" href="<?php echo asset('/includes/site_style.css') ?>">
|
||||
<link rel="stylesheet" href="<?php echo asset('/includes/custom_style.css') ?>"> <!-- ta home -->
|
||||
|
||||
<link rel="stylesheet" href="<?php echo asset('/includes/admin_style.css') ?>">
|
||||
<link rel="stylesheet" href="<?php echo asset('/includes/mobil_style.css') ?>">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
@@ -113,11 +114,11 @@ $is_mobile = preg_match('/Mobile|Android|iPhone|iPad/i', $_SERVER['HTTP_USER_AGE
|
||||
<div class="header-left">
|
||||
<div class="brand">
|
||||
<a
|
||||
href="<?= htmlspecialchars($fallbackBack, ENT_QUOTES, 'UTF-8') ?>"
|
||||
href="<?php echo htmlspecialchars($fallbackBack, ENT_QUOTES, 'UTF-8') ?>"
|
||||
id="btnBack"
|
||||
class="btn btn-light btn-circle me-2"
|
||||
style="border-radius:5px; box-shadow:0 1px 2px rgba(0,0,0,.08);"
|
||||
aria-label="<?= htmlspecialchars($translations['retour'] ?? 'Retour', ENT_QUOTES, 'UTF-8') ?>"
|
||||
aria-label="<?php echo htmlspecialchars($translations['retour'] ?? 'Retour', ENT_QUOTES, 'UTF-8') ?>"
|
||||
>
|
||||
<svg viewBox="0 0 24 24" width="20" height="20" fill="none" aria-hidden="true">
|
||||
<path d="M15 6l-6 6 6 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
@@ -144,9 +145,9 @@ $is_mobile = preg_match('/Mobile|Android|iPhone|iPad/i', $_SERVER['HTTP_USER_AGE
|
||||
<!-- ⚡ A LA PLACE DE L’ICÔNE MESSAGES : le praticien courant -->
|
||||
<div class="text-nowrap" style="font-weight:600;">
|
||||
<?php if ($currentPraticienName): ?>
|
||||
<?= htmlspecialchars($currentPraticienName, ENT_QUOTES, 'UTF-8') ?>
|
||||
<?php echo htmlspecialchars($currentPraticienName, ENT_QUOTES, 'UTF-8') ?>
|
||||
<?php else: ?>
|
||||
<span class="text-muted"><?= htmlspecialchars($translations['aucun_praticien_selectionne'] ?? 'Praticien non sélectionné', ENT_QUOTES, 'UTF-8') ?></span>
|
||||
<span class="text-muted"><?php echo htmlspecialchars($translations['aucun_praticien_selectionne'] ?? 'Praticien non sélectionné', ENT_QUOTES, 'UTF-8') ?></span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
@@ -163,38 +164,43 @@ $is_mobile = preg_match('/Mobile|Android|iPhone|iPad/i', $_SERVER['HTTP_USER_AGE
|
||||
<ul class="dropdown-menu-custom menu-panel" id="menu" style="display:none; min-width: 220px;">
|
||||
<?php if (($_SESSION['role'] ?? '') === 'secretaire'): ?>
|
||||
<li onclick="location.href='/public/cabinet/dashboard.php'">
|
||||
<?= htmlspecialchars($translations['home'] ?? 'Accueil') ?>
|
||||
<?php echo htmlspecialchars($translations['home'] ?? 'Accueil') ?>
|
||||
</li>
|
||||
|
||||
<?php if ($pid && $permRow): ?>
|
||||
<?php if (!empty($permRow['can_manage_rdv'])): ?>
|
||||
<li onclick="location.href='/public/cabinet/agenda.php?praticien_id=<?= $pid ?>'">
|
||||
<?= htmlspecialchars($translations['sec_btn_agenda'] ?? 'Agenda') ?>
|
||||
<?php if (! empty($permRow['can_manage_rdv'])): ?>
|
||||
<li onclick="location.href='/public/cabinet/agenda.php?praticien_id=<?php echo $pid ?>'">
|
||||
<?php echo htmlspecialchars($translations['sec_btn_agenda'] ?? 'Agenda') ?>
|
||||
</li>
|
||||
<li onclick="location.href='/public/cabinet/rendez_vous_du_jour.php?praticien_id=<?= $pid ?>'">
|
||||
<?= htmlspecialchars($translations['sec_btn_rdv'] ?? 'Rendez-vous') ?>
|
||||
<li onclick="location.href='/public/cabinet/rendez_vous_du_jour.php?praticien_id=<?php echo $pid ?>'">
|
||||
<?php echo htmlspecialchars($translations['sec_btn_rdv'] ?? 'Rendez-vous') ?>
|
||||
</li>
|
||||
<li onclick="location.href='/public/cabinet/rendez_vous.php?praticien_id=<?= $pid ?>'">
|
||||
<?= htmlspecialchars($translations['sec_btn_rdv_jour'] ?? 'Les rendez-vous') ?>
|
||||
<li onclick="location.href='/public/cabinet/rendez_vous.php?praticien_id=<?php echo $pid ?>'">
|
||||
<?php echo htmlspecialchars($translations['sec_btn_rdv_jour'] ?? 'Les rendez-vous') ?>
|
||||
</li>
|
||||
<li onclick="location.href='/public/cabinet/reserver_rdv.php?praticien_id=<?= $pid ?>'">
|
||||
<?= htmlspecialchars($translations['sec_btn_prendre'] ?? 'Prendre un RDV') ?>
|
||||
<li onclick="location.href='/public/cabinet/reserver_rdv.php?praticien_id=<?php echo $pid ?>'">
|
||||
<?php echo htmlspecialchars($translations['sec_btn_prendre'] ?? 'Prendre un RDV') ?>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($permRow['can_edit_slots'])): ?>
|
||||
<li onclick="location.href='/public/cabinet/disponibilites.php?praticien_id=<?= $pid ?>'">
|
||||
<?= htmlspecialchars($translations['sec_btn_dispos'] ?? 'Disponibilités') ?>
|
||||
<?php if (! empty($permRow['can_edit_slots'])): ?>
|
||||
<li onclick="location.href='/public/cabinet/disponibilites.php?praticien_id=<?php echo $pid ?>'">
|
||||
<?php echo htmlspecialchars($translations['sec_btn_dispos'] ?? 'Disponibilités') ?>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<li onclick="closeMenu(); openContactAdmin()">
|
||||
<?= htmlspecialchars($translations['contact_admin'] ?? 'Contact Admin') ?>
|
||||
</li>
|
||||
<li onclick="location.href='/public/deconnexion.php'">
|
||||
<?= htmlspecialchars($translations['menu_deconnexion'] ?? 'Déconnexion') ?>
|
||||
<?php echo htmlspecialchars($translations['contact_admin'] ?? 'Contact Admin') ?>
|
||||
</li>
|
||||
<li class="menu-item-form">
|
||||
<form method="POST" action="/public/deconnexion.php" class="menu-logout-form">
|
||||
<input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars(ensure_csrf_token(), ENT_QUOTES, 'UTF-8') ?>">
|
||||
<button type="submit" class="menu-logout-btn">
|
||||
<?php echo htmlspecialchars($translations['menu_deconnexion'] ?? 'Déconnexion') ?>
|
||||
</button>
|
||||
</form>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
</ul>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
declare (strict_types = 1);
|
||||
|
||||
// Interdit l’accès direct au fichier (pas de HTML ici)
|
||||
if (isset($_SERVER['SCRIPT_FILENAME']) && realpath(__FILE__) === realpath($_SERVER['SCRIPT_FILENAME'])) {
|
||||
@@ -8,16 +8,18 @@ if (isset($_SERVER['SCRIPT_FILENAME']) && realpath(__FILE__) === realpath($_SERV
|
||||
}
|
||||
|
||||
/** Est-ce que l'utilisateur est connecté ? */
|
||||
function is_logged_in(): bool {
|
||||
function is_logged_in(): bool
|
||||
{
|
||||
return isset($_SESSION['compte_id'], $_SESSION['reference_id'])
|
||||
&& $_SESSION['compte_id'] !== ''
|
||||
&& $_SESSION['reference_id'] !== '';
|
||||
}
|
||||
|
||||
/** Timeout inactivité (2h) */
|
||||
function enforce_session_timeout(int $maxIdleSeconds = 7200): void {
|
||||
$now = time();
|
||||
$last = (int)($_SESSION['last_activity'] ?? 0);
|
||||
function enforce_session_timeout(int $maxIdleSeconds = 7200): void
|
||||
{
|
||||
$now = time();
|
||||
$last = (int) ($_SESSION['last_activity'] ?? 0);
|
||||
|
||||
if ($last > 0 && ($now - $last) > $maxIdleSeconds) {
|
||||
logout_and_redirect_to_login($_SERVER['REQUEST_URI'] ?? '/');
|
||||
@@ -26,59 +28,78 @@ function enforce_session_timeout(int $maxIdleSeconds = 7200): void {
|
||||
}
|
||||
|
||||
/** Anti open-redirect : n’autorise que les chemins internes commençant par '/' */
|
||||
function next_safe(?string $u): ?string {
|
||||
if (!$u) return null;
|
||||
if (!preg_match('#^/[^\\r\\n]*$#', $u)) return null;
|
||||
if (strpos($u, '//') === 0) return null;
|
||||
function next_safe(?string $u): ?string
|
||||
{
|
||||
if (! $u) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! preg_match('#^/[^\\r\\n]*$#', $u)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (strpos($u, '//') === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $u;
|
||||
}
|
||||
|
||||
function redirect_forbidden(?string $requestUri = null): void {
|
||||
function redirect_forbidden(?string $requestUri = null): void
|
||||
{
|
||||
$u = $requestUri ?: ($_SERVER['REQUEST_URI'] ?? '/');
|
||||
$u = next_safe($u) ?? '/';
|
||||
header('Location: /403.php?next=' . rawurlencode($u), true, 303);
|
||||
exit;
|
||||
}
|
||||
|
||||
function redirect_to_login_with_next(?string $requestUri = null): void {
|
||||
function redirect_to_login_with_next(?string $requestUri = null): void
|
||||
{
|
||||
$u = $requestUri ?: ($_SERVER['REQUEST_URI'] ?? '/');
|
||||
$u = next_safe($u) ?? '/';
|
||||
|
||||
$_SESSION['redirect_to'] = $u;
|
||||
header('Location: /connexion.php?next=' . rawurlencode($u), true, 303);
|
||||
exit;
|
||||
}
|
||||
|
||||
function logout_and_redirect_to_login(?string $requestUri = null): void {
|
||||
function logout_and_redirect_to_login(): void
|
||||
{
|
||||
$_SESSION = [];
|
||||
|
||||
if (session_status() === PHP_SESSION_ACTIVE) {
|
||||
$params = session_get_cookie_params();
|
||||
setcookie(
|
||||
session_name(),
|
||||
'',
|
||||
time() - 42000,
|
||||
$params['path'] ?? '/',
|
||||
$params['domain'] ?? '',
|
||||
(bool)($params['secure'] ?? false),
|
||||
(bool)($params['httponly'] ?? true)
|
||||
);
|
||||
}
|
||||
if (session_status() === PHP_SESSION_ACTIVE) {
|
||||
|
||||
setcookie(session_name(), '', [
|
||||
'expires' => time() - 42000,
|
||||
'path' => $params['path'] ?? '/',
|
||||
'domain' => $params['domain'] ?? '',
|
||||
'secure' => (bool) ($params['secure'] ?? false),
|
||||
'httponly' => (bool) ($params['httponly'] ?? true),
|
||||
'samesite' => $params['samesite'] ?? 'Lax',
|
||||
]);
|
||||
|
||||
session_destroy();
|
||||
}
|
||||
redirect_to_login_with_next($requestUri ?? ($_SERVER['REQUEST_URI'] ?? '/'));
|
||||
|
||||
header('Location: /index.php', true, 303);
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* 🔒 Re-check rôle depuis DB (optionnel) + hydrate $_SESSION['role'] si absent.
|
||||
* Retourne le rôle (string) ou '' si introuvable.
|
||||
*/
|
||||
function refresh_role_from_db(PDO $pdo): string {
|
||||
$compteId = (int)($_SESSION['compte_id'] ?? 0);
|
||||
if ($compteId <= 0) return '';
|
||||
function refresh_role_from_db(PDO $pdo): string
|
||||
{
|
||||
$compteId = (int) ($_SESSION['compte_id'] ?? 0);
|
||||
if ($compteId <= 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$stmt = $pdo->prepare("SELECT role FROM compte WHERE id=? LIMIT 1");
|
||||
$stmt->execute([$compteId]);
|
||||
$role = (string)($stmt->fetchColumn() ?: '');
|
||||
$role = (string) ($stmt->fetchColumn() ?: '');
|
||||
if ($role !== '') {
|
||||
$_SESSION['role'] = $role;
|
||||
}
|
||||
@@ -93,26 +114,27 @@ function refresh_role_from_db(PDO $pdo): string {
|
||||
* - 'recheck_db_role' => true/false
|
||||
* - 'admin_strict_reference' => int|null (ex: 88888888)
|
||||
*/
|
||||
function require_login_or_redirect(?array $allowedRoles = null, array $options = []): void {
|
||||
if (!is_logged_in()) {
|
||||
function require_login_or_redirect(?array $allowedRoles = null, array $options = []): void
|
||||
{
|
||||
if (! is_logged_in()) {
|
||||
redirect_to_login_with_next($_SERVER['REQUEST_URI'] ?? '/');
|
||||
}
|
||||
|
||||
enforce_session_timeout(7200);
|
||||
|
||||
$pdo = $options['pdo'] ?? ($GLOBALS['pdo'] ?? null);
|
||||
$recheck = (bool)($options['recheck_db_role'] ?? false);
|
||||
$pdo = $options['pdo'] ?? ($GLOBALS['pdo'] ?? null);
|
||||
$recheck = (bool) ($options['recheck_db_role'] ?? false);
|
||||
|
||||
// Rôle: session d'abord, DB si demandé (ou si role manquant)
|
||||
$userRole = strtolower((string)($_SESSION['role'] ?? ''));
|
||||
$userRole = strtolower((string) ($_SESSION['role'] ?? ''));
|
||||
if (($userRole === '' || $recheck) && ($pdo instanceof PDO)) {
|
||||
$userRole = refresh_role_from_db($pdo);
|
||||
}
|
||||
|
||||
if ($allowedRoles) {
|
||||
$allowed = array_map(static fn($r) => strtolower((string)$r), $allowedRoles);
|
||||
$allowed = array_map(static fn($r) => strtolower((string) $r), $allowedRoles);
|
||||
|
||||
if (!in_array($userRole, $allowed, true)) {
|
||||
if (! in_array($userRole, $allowed, true)) {
|
||||
redirect_forbidden($_SERVER['REQUEST_URI'] ?? '/');
|
||||
}
|
||||
|
||||
@@ -120,8 +142,8 @@ function require_login_or_redirect(?array $allowedRoles = null, array $options =
|
||||
if (in_array('admin', $allowed, true)) {
|
||||
$strictRef = $options['admin_strict_reference'] ?? null;
|
||||
if ($strictRef !== null) {
|
||||
$refId = (int)($_SESSION['reference_id'] ?? 0);
|
||||
if ($refId !== (int)$strictRef) {
|
||||
$refId = (int) ($_SESSION['reference_id'] ?? 0);
|
||||
if ($refId !== (int) $strictRef) {
|
||||
redirect_forbidden($_SERVER['REQUEST_URI'] ?? '/');
|
||||
}
|
||||
}
|
||||
@@ -134,35 +156,40 @@ function require_login_or_redirect(?array $allowedRoles = null, array $options =
|
||||
========================= */
|
||||
|
||||
/** Token CSRF session */
|
||||
function ensure_csrf_token(): string {
|
||||
function ensure_csrf_token(): string
|
||||
{
|
||||
if (empty($_SESSION['csrf_token'])) {
|
||||
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
|
||||
}
|
||||
return (string)$_SESSION['csrf_token'];
|
||||
return (string) $_SESSION['csrf_token'];
|
||||
}
|
||||
|
||||
/** Exige POST + CSRF (supporte aussi header X-CSRF-Token si tu veux fetch/AJAX) */
|
||||
function require_post_csrf(): void {
|
||||
function require_post_csrf(): void
|
||||
{
|
||||
if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') {
|
||||
http_response_code(405);
|
||||
exit('Méthode non autorisée');
|
||||
}
|
||||
|
||||
$token = $_POST['csrf_token'] ?? '';
|
||||
if ($token === '' && !empty($_SERVER['HTTP_X_CSRF_TOKEN'])) {
|
||||
$token = (string)$_SERVER['HTTP_X_CSRF_TOKEN'];
|
||||
if ($token === '' && ! empty($_SERVER['HTTP_X_CSRF_TOKEN'])) {
|
||||
$token = (string) $_SERVER['HTTP_X_CSRF_TOKEN'];
|
||||
}
|
||||
|
||||
if ($token === '' || !hash_equals((string)($_SESSION['csrf_token'] ?? ''), (string)$token)) {
|
||||
if ($token === '' || ! hash_equals((string) ($_SESSION['csrf_token'] ?? ''), (string) $token)) {
|
||||
http_response_code(419);
|
||||
exit('CSRF invalide');
|
||||
}
|
||||
}
|
||||
|
||||
/** Log admin minimal */
|
||||
function log_admin_action(PDO $pdo, int $userId, string $action, string $details = ''): void {
|
||||
function log_admin_action(PDO $pdo, int $userId, string $action, string $details = ''): void
|
||||
{
|
||||
// limite simple pour éviter d'exploser la table
|
||||
if (strlen($details) > 2000) $details = substr($details, 0, 2000);
|
||||
if (strlen($details) > 2000) {
|
||||
$details = substr($details, 0, 2000);
|
||||
}
|
||||
|
||||
$pdo->prepare(
|
||||
"INSERT INTO admin_actions_log (user_id, action, details, ip) VALUES (?,?,?,?)"
|
||||
@@ -170,6 +197,6 @@ function log_admin_action(PDO $pdo, int $userId, string $action, string $details
|
||||
$userId,
|
||||
$action,
|
||||
$details,
|
||||
$_SERVER['REMOTE_ADDR'] ?? ''
|
||||
$_SERVER['REMOTE_ADDR'] ?? '',
|
||||
]);
|
||||
}
|
||||
Reference in new issue
Block a user