par la page de détails (mini lecteur) et pour le téléchargement direct require_once('../functions/databaseConnection.php'); // Liste blanche des types autorisés : empêche toute injection de nom de table // (le PDF est stocké dans une table associée depuis la migration Juillet 2026 (6), // pour ne plus jamais charger son contenu binaire lors des listes de projets/xp/écoles) $tables = [ 'projet' => ['pdf' => 'project_pdfs', 'colonne' => 'project_id'], 'experience' => ['pdf' => 'experience_pdfs', 'colonne' => 'experience_id'], 'ecole' => ['pdf' => 'school_pdfs', 'colonne' => 'school_id'], ]; $type = $_GET['type'] ?? ''; $id = $_GET['id'] ?? ''; if (!isset($tables[$type]) || !is_numeric($id)) { http_response_code(404); exit; } try { $stmt = $dbh->prepare('SELECT pdf_data, pdf_filename FROM `' . $tables[$type]['pdf'] . '` WHERE `' . $tables[$type]['colonne'] . '` = :id'); $stmt->bindValue(':id', (int) $id, PDO::PARAM_INT); $stmt->execute(); $row = $stmt->fetch(PDO::FETCH_ASSOC); } catch (PDOException $e) { http_response_code(404); exit; } if (!$row || $row['pdf_data'] === null) { http_response_code(404); exit; } $filename = !empty($row['pdf_filename']) ? $row['pdf_filename'] : 'document.pdf'; // ?download=1 force le téléchargement, sinon le PDF s'affiche dans le mini lecteur (iframe) $disposition = (isset($_GET['download']) && $_GET['download'] === '1') ? 'attachment' : 'inline'; header('Content-Type: application/pdf'); header('Content-Disposition: ' . $disposition . '; filename="' . basename($filename) . '"'); header('Content-Length: ' . strlen($row['pdf_data'])); header('Cache-Control: private, max-age=3600'); echo $row['pdf_data']; exit;