f3 = Base::instance(); $this->db = $this->f3->get('DB'); } protected function render(string $view, array $data = []): void { $this->f3->mset($data + [ 'view' => $view, 'currentUser' => $this->currentUser(), 'flash' => $this->pullFlash(), 'csrfToken' => $this->csrfToken(), ]); echo Template::instance()->render('layout.html'); } protected function currentUser(): ?array { $userId = (int) ($this->f3->get('SESSION.user_id') ?? 0); return $userId > 0 ? (new User($this->db))->findById($userId) : null; } protected function requireAuth(): void { if ($this->currentUser() !== null) { return; } $this->flash('error', 'Connecte-toi pour continuer.'); $this->f3->reroute($this->f3->alias('login')); } protected function csrfToken(): string { // Génère un token CSRF et le stocke en session au premier appel. $token = (string) ($this->f3->get('SESSION.csrf_token') ?? ''); if ($token === '') { $token = bin2hex(random_bytes(32)); $this->f3->set('SESSION.csrf_token', $token); } return $token; } protected function verifyCsrf(): void { $submitted = (string) ($this->f3->get('POST.csrf_token') ?? ''); $expected = (string) ($this->f3->get('SESSION.csrf_token') ?? ''); if ($submitted !== '' && $expected !== '' && hash_equals($expected, $submitted)) { return; } $this->f3->error(400, 'Jeton CSRF invalide.'); } protected function flash(string $type, string $message): void { $this->f3->set('SESSION.flash', ['type' => $type, 'message' => $message]); } private function pullFlash(): ?array { $flash = $this->f3->get('SESSION.flash'); $this->f3->clear('SESSION.flash'); return is_array($flash) ? $flash : null; } }