Files
Portfolio-Esteban/scripts/exportData.php
T
2026-07-03 02:02:13 +02:00

88 lines
3.9 KiB
PHP

<?php
// Export de toutes les données du site en JSON (comme un dbdump mais en JSON)
// Le fichier téléchargé peut ensuite être ré-importé via importData.php
// On démarre la session
require_once(__DIR__ . '/../functions/security.php');
// On ajoute la DB
require_once('../functions/databaseConnection.php');
// On ajoute les logs Discord
require_once('../functions/sendLogs.php');
// Si l'utilisateur n'est pas admin il ne peut pas executer le reste du script
if (!isset($_SESSION['role']) || $_SESSION['role'] !== 'admin') {
header('Location: ../pages/home.php');
exit;
}
// Vérification du jeton CSRF : bloque les requêtes forgées depuis un autre site
requireCsrfToken();
// Liste blanche des tables et colonnes exportées (empêche toute injection via noms de colonnes)
// Depuis la migration Juillet 2026 (6), les PDF vivent dans des tables associées
// (project_pdfs, experience_pdfs, school_pdfs) plutôt que dans projects/experiences/schools :
// elles sont placées juste après leur table parente (l'ordre compte pour l'import, à cause
// des clés étrangères ON DELETE CASCADE)
$tables = [
'settings' => ['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;