['name', 'value'], 'skills' => ['id', 'title', 'icon', 'items', 'position', 'created_at'], 'projects' => ['id', 'title', 'status', 'tags', 'description', 'image_url', 'markdown', 'link_url', 'created_at'], 'project_pdfs' => ['project_id', 'pdf_filename', 'pdf_data'], 'experiences' => ['id', 'title', 'status', 'xptype', 'tags', 'description', 'duration', 'image_url', 'markdown', 'link_url', 'created_at'], 'experience_pdfs' => ['experience_id', 'pdf_filename', 'pdf_data'], 'schools' => ['id', 'title', 'status', 'tags', 'description', 'duration', 'image_url', 'markdown', 'link_url', 'created_at'], 'school_pdfs' => ['school_id', 'pdf_filename', 'pdf_data'], 'users' => ['id', 'username', 'password', 'role', 'created_at', 'last_login'], ]; // Colonnes binaires : le JSON ne peut pas contenir de binaire brut, on les encode en base64 // (+33% de taille mais nécessaire pour que le PDF survive à un export/import complet) $colonnesBinaires = [ 'project_pdfs' => ['pdf_data'], 'experience_pdfs' => ['pdf_data'], 'school_pdfs' => ['pdf_data'], ]; // Métadonnées de l'export (pratique pour s'y retrouver dans les sauvegardes) $export = [ '_meta' => [ 'site' => 'Portfolio Esteban MOUSSU', 'date_export' => date('Y-m-d H:i:s'), 'version' => 1 ] ]; // Pour chaque table on récupère toutes les lignes foreach ($tables as $table => $colonnes) { try { // SELECT * puis filtrage par liste blanche : fonctionne même si certaines // colonnes optionnelles (markdown, link_url, pdf_data...) n'existent pas encore $stmt = $dbh->query('SELECT * FROM `' . $table . '`'); $lignes = $stmt->fetchAll(PDO::FETCH_ASSOC); $binaires = $colonnesBinaires[$table] ?? []; // On ne garde que les colonnes de la liste blanche, et on encode les colonnes binaires $export[$table] = array_map(function ($ligne) use ($colonnes, $binaires) { $ligne = array_intersect_key($ligne, array_flip($colonnes)); foreach ($binaires as $colonne) { if (isset($ligne[$colonne]) && $ligne[$colonne] !== null) { $ligne[$colonne] = base64_encode($ligne[$colonne]); } } return $ligne; }, $lignes); } catch (PDOException $e) { // Si une table n'existe pas encore on l'exporte vide plutôt que de bloquer l'export $export[$table] = []; } } // Log Discord sendLog("Export des données du site en JSON"); // Envoi du fichier JSON en téléchargement header('Content-Type: application/json; charset=utf-8'); header('Content-Disposition: attachment; filename="portfolio-backup-' . date('Y-m-d-His') . '.json"'); echo json_encode($export, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); exit;