This commit is contained in:
Esteban
2026-07-02 15:13:54 +02:00
parent a019dcb00d
commit 07bae3eff3
38 changed files with 2039 additions and 226 deletions
+37 -9
View File
@@ -1,6 +1,8 @@
<?php
session_start();
require_once '../functions/databaseConnection.php';
require_once('../functions/sendLogs.php');
require_once('../functions/pdfUpload.php');
// Pour faire cette fonction l'utilisateur doit être administrateur
if (!isset($_SESSION['role']) || $_SESSION['role'] !== 'admin') {
@@ -8,29 +10,55 @@ if (!isset($_SESSION['role']) || $_SESSION['role'] !== 'admin') {
exit;
}
// Le fichier envoyé dépasse post_max_size : $_POST/$_FILES sont vides, on le détecte
// tout de suite pour éviter un échec silencieux
if (postDepasseLimite()) {
die(messageDepassementPost());
}
// La requête doit être un POST sinon on l'a refuse
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Récupération des données dans la requete POST
$title = $_POST['title'] ?? '';
$status = trim($_POST['status'] ?? '');
$tags = $_POST['tags'] ?? '';
$description = $_POST['description'] ?? '';
$image_url = $_POST['imageurl'] ?? '';
$markdown = trim($_POST['markdown'] ?? '');
$link_url = trim($_POST['linkurl'] ?? '');
// Lecture et validation du PDF envoyé (optionnel)
$pdfResultat = lireUploadPdf('pdf');
if (is_string($pdfResultat)) {
// Le fichier envoyé n'est pas valide : on affiche l'erreur et on s'arrête
echo $pdfResultat;
exit;
}
$pdfData = is_array($pdfResultat) ? $pdfResultat['data'] : null;
$pdfFilename = is_array($pdfResultat) ? $pdfResultat['filename'] : null;
// On vérifie que les champs obligatoires ne sont pas vide
if (!empty($title) && !empty($description) && !empty($image_url)) {
try {
// On prépare la requête SQL pour insérer le nouveau projet
$stmt = $dbh->prepare('INSERT INTO projects (title, tags, description, image_url) VALUES (:title, :tags, :description, :image_url)');
$stmt = $dbh->prepare('INSERT INTO projects (title, status, tags, description, image_url, markdown, link_url, pdf_data, pdf_filename) VALUES (:title, :status, :tags, :description, :image_url, :markdown, :link_url, :pdf_data, :pdf_filename)');
// On execute la requete préparée
$stmt->execute([
':title' => $title,
':tags' => $tags,
':description' => $description,
':image_url' => $image_url
]);
$stmt->bindValue(':title', $title, PDO::PARAM_STR);
$stmt->bindValue(':status', $status, PDO::PARAM_STR);
$stmt->bindValue(':tags', $tags, PDO::PARAM_STR);
$stmt->bindValue(':description', $description, PDO::PARAM_STR);
$stmt->bindValue(':image_url', $image_url, PDO::PARAM_STR);
$stmt->bindValue(':markdown', $markdown, PDO::PARAM_STR);
$stmt->bindValue(':link_url', $link_url, PDO::PARAM_STR);
$stmt->bindValue(':pdf_data', $pdfData, $pdfData === null ? PDO::PARAM_NULL : PDO::PARAM_LOB);
$stmt->bindValue(':pdf_filename', $pdfFilename, $pdfFilename === null ? PDO::PARAM_NULL : PDO::PARAM_STR);
$stmt->execute();
// Log Discord
sendLog("Ajout du projet : " . $title);
// Redirection vers projects.php ds que la requete est executée
header('Location: ../pages/projects.php');
exit;
+35 -8
View File
@@ -1,6 +1,8 @@
<?php
session_start();
require_once '../functions/databaseConnection.php';
require_once('../functions/sendLogs.php');
require_once('../functions/pdfUpload.php');
// Pour faire cette fonction l'utilisateur doit être administrateur
if (!isset($_SESSION['role']) || $_SESSION['role'] !== 'admin') {
@@ -8,30 +10,55 @@ if (!isset($_SESSION['role']) || $_SESSION['role'] !== 'admin') {
exit;
}
// Le fichier envoyé dépasse post_max_size : $_POST/$_FILES sont vides, on le détecte
// tout de suite pour éviter un échec silencieux
if (postDepasseLimite()) {
die(messageDepassementPost());
}
// La requête doit être un POST sinon on l'a refuse
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Récupération des données dans la requete POST
$title = trim($_POST['title'] ?? '');
$status = trim($_POST['status'] ?? '');
$tags = trim($_POST['tags'] ?? '');
$description = trim($_POST['description'] ?? '');
$duration = trim($_POST['duration'] ?? '');
$image_url = trim($_POST['imageurl'] ?? '');
$markdown = trim($_POST['markdown'] ?? '');
$link_url = trim($_POST['linkurl'] ?? '');
// Lecture et validation du PDF envoyé (optionnel)
$pdfResultat = lireUploadPdf('pdf');
if (is_string($pdfResultat)) {
echo $pdfResultat;
exit;
}
$pdfData = is_array($pdfResultat) ? $pdfResultat['data'] : null;
$pdfFilename = is_array($pdfResultat) ? $pdfResultat['filename'] : null;
// On vérifie que les champs obligatoires ne sont pas vide
if (!empty($title) && !empty($description) && !empty($duration) && !empty($image_url)) {
try {
// On prépare la requête SQL pour insérer la nouvelle école
$stmt = $dbh->prepare('INSERT INTO schools (title, tags, description, duration, image_url) VALUES (:title, :tags, :description, :duration, :image_url)');
$stmt = $dbh->prepare('INSERT INTO schools (title, status, tags, description, duration, image_url, markdown, link_url, pdf_data, pdf_filename) VALUES (:title, :status, :tags, :description, :duration, :image_url, :markdown, :link_url, :pdf_data, :pdf_filename)');
// On execute la requete préparée
$stmt->execute([
':title' => $title,
':tags' => $tags,
':description' => $description,
':duration' => $duration,
':image_url' => $image_url
]);
$stmt->bindValue(':title', $title, PDO::PARAM_STR);
$stmt->bindValue(':status', $status, PDO::PARAM_STR);
$stmt->bindValue(':tags', $tags, PDO::PARAM_STR);
$stmt->bindValue(':description', $description, PDO::PARAM_STR);
$stmt->bindValue(':duration', $duration, PDO::PARAM_STR);
$stmt->bindValue(':image_url', $image_url, PDO::PARAM_STR);
$stmt->bindValue(':markdown', $markdown, PDO::PARAM_STR);
$stmt->bindValue(':link_url', $link_url, PDO::PARAM_STR);
$stmt->bindValue(':pdf_data', $pdfData, $pdfData === null ? PDO::PARAM_NULL : PDO::PARAM_LOB);
$stmt->bindValue(':pdf_filename', $pdfFilename, $pdfFilename === null ? PDO::PARAM_NULL : PDO::PARAM_STR);
$stmt->execute();
// Log Discord
sendLog("Ajout de l'école : " . $title);
// Redirection vers xp.php dès que la requete est executée
header('Location: ../pages/xp.php');
+4
View File
@@ -1,6 +1,7 @@
<?php
session_start();
require_once '../functions/databaseConnection.php';
require_once('../functions/sendLogs.php');
// Pour faire cette fonction l'utilisateur doit être administrateur
if (!isset($_SESSION['role']) || $_SESSION['role'] !== 'admin') {
@@ -31,6 +32,9 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
':position' => $position
]);
// Log Discord
sendLog("Ajout de la catégorie de compétences : " . $title);
// Redirection vers skills.php dès que la requete est executée
header('Location: ../pages/skills.php');
exit;
+5
View File
@@ -3,6 +3,8 @@
session_start();
// Ajout de connexion à la BDD
require_once("../functions/databaseConnection.php");
// Ajout des logs Discord
require_once("../functions/sendLogs.php");
// Vérification que l'utilisateur est bien admin
if (!isset($_SESSION["role"]) || $_SESSION["role"] != "admin") {
@@ -58,6 +60,9 @@ if ($_SERVER["REQUEST_METHOD"] == "POST") {
":created_at" => $dateCreation
]);
// Log Discord
sendLog("Création du compte : " . $user . " (rôle : " . $role . ")");
// Redirection vers la page admin après succès
header("Location: ../pages/admin.php");
exit();
+38 -11
View File
@@ -1,6 +1,8 @@
<?php
session_start();
require_once '../functions/databaseConnection.php';
require_once('../functions/sendLogs.php');
require_once('../functions/pdfUpload.php');
// Pour faire cette fonction l'utilisateur doit être administrateur
if (!isset($_SESSION['role']) || $_SESSION['role'] !== 'admin') {
@@ -8,33 +10,58 @@ if (!isset($_SESSION['role']) || $_SESSION['role'] !== 'admin') {
exit;
}
// Le fichier envoyé dépasse post_max_size : $_POST/$_FILES sont vides, on le détecte
// tout de suite pour éviter un échec silencieux
if (postDepasseLimite()) {
die(messageDepassementPost());
}
// La requête doit être un POST sinon on l'a refuse
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Récupération des données dans la requete POST
$title = $_POST['title'] ?? '';
$status = trim($_POST['status'] ?? '');
$xptype = $_POST['xptype'] ?? '';
$tags = $_POST['tags'] ?? '';
$description = $_POST['description'] ?? '';
$duration = $_POST['duration'] ?? '';
$image_url = $_POST['imageurl'] ?? '';
$markdown = trim($_POST['markdown'] ?? '');
$link_url = trim($_POST['linkurl'] ?? '');
// Lecture et validation du PDF envoyé (optionnel)
$pdfResultat = lireUploadPdf('pdf');
if (is_string($pdfResultat)) {
echo $pdfResultat;
exit;
}
$pdfData = is_array($pdfResultat) ? $pdfResultat['data'] : null;
$pdfFilename = is_array($pdfResultat) ? $pdfResultat['filename'] : null;
// On vérifie que les champs obligatoires ne sont pas vide
if (!empty($title) && !empty($description) && !empty($image_url)) {
try {
// On prépare la requête SQL pour insérer la nouvelle experience
$stmt = $dbh->prepare('INSERT INTO experiences (title, xptype, tags, description, duration, image_url) VALUES (:title, :xptype, :tags, :description, :duration, :image_url)');
$stmt = $dbh->prepare('INSERT INTO experiences (title, status, xptype, tags, description, duration, image_url, markdown, link_url, pdf_data, pdf_filename) VALUES (:title, :status, :xptype, :tags, :description, :duration, :image_url, :markdown, :link_url, :pdf_data, :pdf_filename)');
// On execute la requete préparée
$stmt->execute([
':title' => $title,
':xptype' => $xptype,
':tags' => $tags,
':description' => $description,
':duration' => $duration,
':image_url' => $image_url
]);
$stmt->bindValue(':title', $title, PDO::PARAM_STR);
$stmt->bindValue(':status', $status, PDO::PARAM_STR);
$stmt->bindValue(':xptype', $xptype, PDO::PARAM_STR);
$stmt->bindValue(':tags', $tags, PDO::PARAM_STR);
$stmt->bindValue(':description', $description, PDO::PARAM_STR);
$stmt->bindValue(':duration', $duration, PDO::PARAM_STR);
$stmt->bindValue(':image_url', $image_url, PDO::PARAM_STR);
$stmt->bindValue(':markdown', $markdown, PDO::PARAM_STR);
$stmt->bindValue(':link_url', $link_url, PDO::PARAM_STR);
$stmt->bindValue(':pdf_data', $pdfData, $pdfData === null ? PDO::PARAM_NULL : PDO::PARAM_LOB);
$stmt->bindValue(':pdf_filename', $pdfFilename, $pdfFilename === null ? PDO::PARAM_NULL : PDO::PARAM_STR);
$stmt->execute();
// Log Discord
sendLog("Ajout de l'expérience : " . $title);
// Redirection vers xp.php ds que la requete est executée
header('Location: ../pages/xp.php');
exit;
+10 -1
View File
@@ -8,6 +8,9 @@ session_start();
// Ajout de connexion a la bdd
require_once('../functions/databaseConnection.php');
// Ajout des logs Discord
require_once('../functions/sendLogs.php');
// La requête doit être un POST sinon on l'a refuse
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
header('Location: ./../pages/login.php');
@@ -29,6 +32,8 @@ try {
// On regarde si le mdp correspond à celui en bdd
if (!$user || !password_verify($password, $user['password'])) {
// Log Discord : tentative de connexion échouée (utile pour repérer le bruteforce)
sendLog("Tentative de connexion échouée avec l'identifiant : " . $username);
header('Location: ./../pages/login.php');
exit;
}
@@ -46,7 +51,11 @@ try {
error_log('Le serveur WEB ne peut pas modifier la date de dernière connexion : ' . $e->getMessage());
}
// Log Discord : connexion réussie
sendLog("Connexion réussie", $user['username']);
//Redirection vers home.php puisque que l'utilisateur est forcément connecté
header('Location: ./../pages/home.php');
// (?login=1 déclenche la notification "Connexion réussie" sur la page)
header('Location: ./../pages/home.php?login=1');
exit;
?>
+8 -1
View File
@@ -5,6 +5,12 @@
// Démarrage de session
session_start();
// Ajout des logs Discord
require_once('../functions/sendLogs.php');
// Log Discord AVANT la destruction de session (sinon on perd le nom d'utilisateur)
sendLog("Déconnexion");
// On sauvegarde l'état du captcha avant destruction
$captchaAlreadyValid = isset($_SESSION['captcha_valid']) && $_SESSION['captcha_valid'] === true;
@@ -20,5 +26,6 @@ if ($captchaAlreadyValid) {
}
// Redirection de l'utilisateur vers l'accueil
header('Location: ../index.php');
// (?logout=1 déclenche la notification "Vous avez bien été déconnecté" sur la page)
header('Location: ../pages/home.php?logout=1');
exit;
+77
View File
@@ -0,0 +1,77 @@
<?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
session_start();
// 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;
}
// Liste blanche des tables et colonnes exportées (empêche toute injection via noms de colonnes)
$tables = [
'settings' => ['name', 'value'],
'skills' => ['id', 'title', 'icon', 'items', 'position', 'created_at'],
'projects' => ['id', 'title', 'status', 'tags', 'description', 'image_url', 'markdown', 'link_url', 'pdf_data', 'pdf_filename', 'created_at'],
'experiences' => ['id', 'title', 'status', 'xptype', 'tags', 'description', 'duration', 'image_url', 'markdown', 'link_url', 'pdf_data', 'pdf_filename', 'created_at'],
'schools' => ['id', 'title', 'status', 'tags', 'description', 'duration', 'image_url', 'markdown', 'link_url', 'pdf_data', 'pdf_filename', 'created_at'],
'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 = [
'projects' => ['pdf_data'],
'experiences' => ['pdf_data'],
'schools' => ['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;
+117
View File
@@ -0,0 +1,117 @@
<?php
// Import d'une sauvegarde JSON (créée par exportData.php)
// ATTENTION : les données actuelles des tables présentes dans le fichier sont ÉCRASÉES
// On démarre la session
session_start();
// 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;
}
// La requête doit être un POST avec un fichier sinon on refuse
if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !isset($_FILES['jsonfile']) || $_FILES['jsonfile']['error'] !== UPLOAD_ERR_OK) {
header('Location: ../pages/admin.php');
exit;
}
// Lecture et décodage du fichier JSON
$contenu = file_get_contents($_FILES['jsonfile']['tmp_name']);
$donnees = json_decode($contenu, true);
if (!is_array($donnees)) {
die("Erreur : le fichier n'est pas un JSON valide.");
}
// Même liste blanche que l'export : seules ces tables / colonnes peuvent être importées
$tables = [
'settings' => ['name', 'value'],
'skills' => ['id', 'title', 'icon', 'items', 'position', 'created_at'],
'projects' => ['id', 'title', 'status', 'tags', 'description', 'image_url', 'markdown', 'link_url', 'pdf_data', 'pdf_filename', 'created_at'],
'experiences' => ['id', 'title', 'status', 'xptype', 'tags', 'description', 'duration', 'image_url', 'markdown', 'link_url', 'pdf_data', 'pdf_filename', 'created_at'],
'schools' => ['id', 'title', 'status', 'tags', 'description', 'duration', 'image_url', 'markdown', 'link_url', 'pdf_data', 'pdf_filename', 'created_at'],
'users' => ['id', 'username', 'password', 'role', 'created_at', 'last_login'],
];
// Colonnes binaires : encodées en base64 par exportData.php, à redécoder ici
$colonnesBinaires = [
'projects' => ['pdf_data'],
'experiences' => ['pdf_data'],
'schools' => ['pdf_data'],
];
try {
// Transaction : si une erreur survient, TOUT est annulé (la base reste intacte)
$dbh->beginTransaction();
foreach ($tables as $table => $colonnesAutorisees) {
// On ne touche qu'aux tables présentes dans le fichier
if (!isset($donnees[$table]) || !is_array($donnees[$table])) {
continue;
}
// Sécurité : on refuse de vider la table users si la sauvegarde n'en contient aucun
// (sinon l'admin se retrouverait enfermé dehors sans aucun compte)
if ($table === 'users' && count($donnees[$table]) === 0) {
continue;
}
// On écrase les données existantes de la table
$dbh->exec('DELETE FROM `' . $table . '`');
// Colonnes binaires (PDF) de cette table, à redécoder du base64
$binaires = $colonnesBinaires[$table] ?? [];
// Puis on insère chaque ligne de la sauvegarde
foreach ($donnees[$table] as $ligne) {
if (!is_array($ligne)) {
continue;
}
// On ne garde que les colonnes autorisées ET présentes dans la ligne
$colonnes = array_values(array_intersect($colonnesAutorisees, array_keys($ligne)));
if (empty($colonnes)) {
continue;
}
$placeholders = array_map(function ($c) { return ':' . $c; }, $colonnes);
$stmt = $dbh->prepare(
'INSERT INTO `' . $table . '` (`' . implode('`, `', $colonnes) . '`) VALUES (' . implode(', ', $placeholders) . ')'
);
foreach ($colonnes as $colonne) {
$valeur = $ligne[$colonne];
// Les colonnes binaires (pdf_data) sont ré-encodées en base64 par l'export : on les redécode
if (in_array($colonne, $binaires, true) && $valeur !== null) {
$stmt->bindValue(':' . $colonne, base64_decode($valeur), PDO::PARAM_LOB);
} else {
$stmt->bindValue(':' . $colonne, $valeur);
}
}
$stmt->execute();
}
}
// Tout s'est bien passé : on valide définitivement
$dbh->commit();
} catch (Exception $e) {
// En cas d'erreur on annule tout : la base revient à son état d'avant l'import
$dbh->rollBack();
die("Erreur pendant l'import, aucune donnée n'a été modifiée : " . $e->getMessage());
}
// Log Discord
sendLog("Import d'une sauvegarde JSON : données du site écrasées");
// On renvoie l'utilisateur sur admin.php (?import=1 déclenche la notification de succès)
header('Location: ../pages/admin.php?import=1');
exit;
+5
View File
@@ -3,6 +3,8 @@
session_start();
// 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') {
@@ -26,6 +28,9 @@ try { // On essaie d'executer une requête qui est préparée
} catch (PDOException $e) {
die("Erreur lors de la suppression du projet :" . $e->getMessage());
}
// Log Discord
sendLog("Suppression du projet id " . $id);
// On renvoie l'utilisateur sur admin.php
header('Location: ../pages/admin.php');
exit;
+6
View File
@@ -3,6 +3,8 @@
session_start();
// 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') {
@@ -26,6 +28,10 @@ try { // On essaie d'executer une requête qui est préparée
} catch (PDOException $e) {
die("Erreur lors de la suppression de l'école :" . $e->getMessage());
}
// Log Discord
sendLog("Suppression de l'école id " . $id);
// On renvoie l'utilisateur sur admin.php
header('Location: ../pages/admin.php');
exit;
+6
View File
@@ -3,6 +3,8 @@
session_start();
// 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') {
@@ -26,6 +28,10 @@ try { // On essaie d'executer une requête qui est préparée
} catch (PDOException $e) {
die("Erreur lors de la suppression de la compétence :" . $e->getMessage());
}
// Log Discord
sendLog("Suppression de la catégorie de compétences id " . $id);
// On renvoie l'utilisateur sur admin.php
header('Location: ../pages/admin.php');
exit;
+5
View File
@@ -3,6 +3,8 @@
session_start();
// Ajout de connexion à la BDD
require_once("../functions/databaseConnection.php");
// Ajout des logs Discord
require_once("../functions/sendLogs.php");
// Vérification que l'utilisateur est bien admin
if (!isset($_SESSION["role"]) || $_SESSION["role"] != "admin") {
@@ -26,6 +28,9 @@ if ($id == "") {
":id" => $id
]);
// Log Discord
sendLog("Suppression du compte id " . $id);
// Redirection vers la page admin après suppression
header("Location: ../pages/admin.php");
exit();
+6
View File
@@ -3,6 +3,8 @@
session_start();
// 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') {
@@ -26,6 +28,10 @@ try { // On essaie d'executer une requête qui est préparée
} catch (PDOException $e) {
die("Erreur lors de la suppression de l experience :" . $e->getMessage());
}
// Log Discord
sendLog("Suppression de l'expérience id " . $id);
// On renvoie l'utilisateur sur admin.php
header('Location: ../pages/admin.php');
exit;
+7 -2
View File
@@ -2,6 +2,10 @@
// Envoi de message de contact via WebHook discord => Correction de faille de sécurité en cachant le webhook dans un fichier à part
require_once('../../idDiscord.php');
// Ajout des logs Discord
session_start();
require_once('../functions/sendLogs.php');
// Envoi de formulaire de contact via WebHook discord
$webhook = ID_DISCORD2; // URL du webhook Discord
// EXEMPLE de a quoi ressemble idDiscord :
@@ -55,12 +59,13 @@ if ($subject == "" || $name == "" || $mail == "" || $message == "") {
$resultat = curl_exec($ch);
$codeHttp = curl_getinfo($ch, CURLINFO_HTTP_CODE);
// (pas de curl_close : déprécié depuis PHP 8.5, la ressource se libère toute seule)
if ($codeHttp == 204) { // Si ça renvoi 204 alors le message a été correctement envoyé
curl_close($ch); // Fermer la ressource curl lancée
// Log Discord : message de contact envoyé
sendLog("Nouveau message de contact envoyé par : " . $name);
header("Location: ../pages/contact.php?success=1");
exit();
} else { // Sinon c'est que ça n'a pas été envoyé (discord down / webhook expiré / etcc...)
curl_close($ch); // Fermer la ressource curl lancée
echo "Le message n'a pas pu être envoyé sur Discord.";
}
}
+52 -4
View File
@@ -3,6 +3,9 @@
session_start();
// On ajoute la DB
require_once('../functions/databaseConnection.php');
// On ajoute les logs Discord
require_once('../functions/sendLogs.php');
require_once('../functions/pdfUpload.php');
// Si l'utilisateur n'est pas admin il ne peut pas executer le reste du script
if (!isset($_SESSION['role']) || $_SESSION['role'] !== 'admin') {
@@ -10,6 +13,12 @@ if (!isset($_SESSION['role']) || $_SESSION['role'] !== 'admin') {
exit;
}
// Le fichier envoyé dépasse post_max_size : $_POST/$_FILES sont vides, on le détecte
// tout de suite (sinon le script redirige silencieusement vers admin.php sans explication)
if (postDepasseLimite()) {
die(messageDepassementPost());
}
if ( // Si les champs sont vides on renvoie vers admin.php
!isset($_POST['id']) || !is_numeric($_POST['id']) ||
empty($_POST['title']) ||
@@ -23,25 +32,64 @@ if ( // Si les champs sont vides on renvoie vers admin.php
// On récupère les données pour les mettres en variables locales
$id = (int) $_POST['id'];
$title = trim($_POST['title']);
$status = trim($_POST['status'] ?? '');
$tags = trim($_POST['tags'] ?? '');
$description = trim($_POST['description']);
$imageurl = trim($_POST['imageurl']);
$markdown = trim($_POST['markdown'] ?? '');
$link_url = trim($_POST['linkurl'] ?? '');
// Lecture et validation du PDF envoyé (optionnel)
$pdfResultat = lireUploadPdf('pdf');
if (is_string($pdfResultat)) {
// Le fichier envoyé n'est pas valide : on affiche l'erreur et on s'arrête
echo $pdfResultat;
exit;
}
// Le PDF n'est mis à jour que si un nouveau fichier est envoyé OU si la case
// "Supprimer ce PDF" est cochée. Sinon on garde le PDF actuel intact.
$updatePdf = false;
$pdfData = null;
$pdfFilename = null;
if (is_array($pdfResultat)) {
$updatePdf = true;
$pdfData = $pdfResultat['data'];
$pdfFilename = $pdfResultat['filename'];
} elseif (isset($_POST['remove_pdf'])) {
$updatePdf = true;
}
try { // On essaie d'executer une requête qui est préparée
$stmt = $dbh->prepare('
$sql = '
UPDATE projects
SET title = :title, tags = :tags, description = :description, image_url = :image_url
WHERE id = :id
');
SET title = :title, status = :status, tags = :tags, description = :description, image_url = :image_url, markdown = :markdown, link_url = :link_url';
if ($updatePdf) {
$sql .= ', pdf_data = :pdf_data, pdf_filename = :pdf_filename';
}
$sql .= ' WHERE id = :id';
$stmt = $dbh->prepare($sql);
$stmt->bindValue(':title', $title, PDO::PARAM_STR);
$stmt->bindValue(':status', $status, PDO::PARAM_STR);
$stmt->bindValue(':tags', $tags, PDO::PARAM_STR);
$stmt->bindValue(':description', $description, PDO::PARAM_STR);
$stmt->bindValue(':image_url', $imageurl, PDO::PARAM_STR);
$stmt->bindValue(':markdown', $markdown, PDO::PARAM_STR);
$stmt->bindValue(':link_url', $link_url, PDO::PARAM_STR);
if ($updatePdf) {
$stmt->bindValue(':pdf_data', $pdfData, $pdfData === null ? PDO::PARAM_NULL : PDO::PARAM_LOB);
$stmt->bindValue(':pdf_filename', $pdfFilename, $pdfFilename === null ? PDO::PARAM_NULL : PDO::PARAM_STR);
}
$stmt->bindValue(':id', $id, PDO::PARAM_INT);
$stmt->execute(); // Sinon on renvoie l'erreur
} catch (PDOException $e) {
die("Erreur lors de la modification du projet :" . $e->getMessage());
}
// Log Discord
sendLog("Modification du projet : " . $title . " (id " . $id . ")");
// On renvoie l'utilisateur sur admin.php
header('Location: ../pages/admin.php');
exit;
+51 -4
View File
@@ -3,6 +3,9 @@
session_start();
// On ajoute la DB
require_once('../functions/databaseConnection.php');
// On ajoute les logs Discord
require_once('../functions/sendLogs.php');
require_once('../functions/pdfUpload.php');
// Si l'utilisateur n'est pas admin il ne peut pas executer le reste du script
if (!isset($_SESSION['role']) || $_SESSION['role'] !== 'admin') {
@@ -10,6 +13,12 @@ if (!isset($_SESSION['role']) || $_SESSION['role'] !== 'admin') {
exit;
}
// Le fichier envoyé dépasse post_max_size : $_POST/$_FILES sont vides, on le détecte
// tout de suite (sinon le script redirige silencieusement vers admin.php sans explication)
if (postDepasseLimite()) {
die(messageDepassementPost());
}
if ( // Si les champs sont vides on renvoie vers admin.php
!isset($_POST['id']) || !is_numeric($_POST['id']) ||
empty($_POST['title']) ||
@@ -24,27 +33,65 @@ if ( // Si les champs sont vides on renvoie vers admin.php
// On récupère les données pour les mettres en variables locales
$id = (int) $_POST['id'];
$title = trim($_POST['title']);
$status = trim($_POST['status'] ?? '');
$tags = trim($_POST['tags'] ?? '');
$description = trim($_POST['description']);
$duration = trim($_POST['duration']);
$imageurl = trim($_POST['imageurl']);
$markdown = trim($_POST['markdown'] ?? '');
$link_url = trim($_POST['linkurl'] ?? '');
// Lecture et validation du PDF envoyé (optionnel)
$pdfResultat = lireUploadPdf('pdf');
if (is_string($pdfResultat)) {
echo $pdfResultat;
exit;
}
// Le PDF n'est mis à jour que si un nouveau fichier est envoyé OU si la case
// "Supprimer ce PDF" est cochée. Sinon on garde le PDF actuel intact.
$updatePdf = false;
$pdfData = null;
$pdfFilename = null;
if (is_array($pdfResultat)) {
$updatePdf = true;
$pdfData = $pdfResultat['data'];
$pdfFilename = $pdfResultat['filename'];
} elseif (isset($_POST['remove_pdf'])) {
$updatePdf = true;
}
try { // On essaie d'executer une requête qui est préparée
$stmt = $dbh->prepare('
$sql = '
UPDATE schools
SET title = :title, tags = :tags, description = :description, duration = :duration, image_url = :image_url
WHERE id = :id
');
SET title = :title, status = :status, tags = :tags, description = :description, duration = :duration, image_url = :image_url, markdown = :markdown, link_url = :link_url';
if ($updatePdf) {
$sql .= ', pdf_data = :pdf_data, pdf_filename = :pdf_filename';
}
$sql .= ' WHERE id = :id';
$stmt = $dbh->prepare($sql);
$stmt->bindValue(':title', $title, PDO::PARAM_STR);
$stmt->bindValue(':status', $status, PDO::PARAM_STR);
$stmt->bindValue(':tags', $tags, PDO::PARAM_STR);
$stmt->bindValue(':description', $description, PDO::PARAM_STR);
$stmt->bindValue(':duration', $duration, PDO::PARAM_STR);
$stmt->bindValue(':image_url', $imageurl, PDO::PARAM_STR);
$stmt->bindValue(':markdown', $markdown, PDO::PARAM_STR);
$stmt->bindValue(':link_url', $link_url, PDO::PARAM_STR);
if ($updatePdf) {
$stmt->bindValue(':pdf_data', $pdfData, $pdfData === null ? PDO::PARAM_NULL : PDO::PARAM_LOB);
$stmt->bindValue(':pdf_filename', $pdfFilename, $pdfFilename === null ? PDO::PARAM_NULL : PDO::PARAM_STR);
}
$stmt->bindValue(':id', $id, PDO::PARAM_INT);
$stmt->execute(); // Sinon on renvoie l'erreur
} catch (PDOException $e) {
die("Erreur lors de la modification de l'école :" . $e->getMessage());
}
// Log Discord
sendLog("Modification de l'école : " . $title . " (id " . $id . ")");
// On renvoie l'utilisateur sur admin.php
header('Location: ../pages/admin.php');
exit;
+5
View File
@@ -3,6 +3,8 @@
session_start();
// 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') {
@@ -38,6 +40,9 @@ try { // On essaie d'executer une requête qui est préparée pour chaque régla
die("Erreur lors de la modification de la notification :" . $e->getMessage());
}
// Log Discord
sendLog("Modification de la notification de la page d'accueil");
// On renvoie l'utilisateur sur admin.php
header('Location: ../pages/admin.php');
exit;
+6
View File
@@ -3,6 +3,8 @@
session_start();
// 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') {
@@ -41,6 +43,10 @@ try { // On essaie d'executer une requête qui est préparée
} catch (PDOException $e) {
die("Erreur lors de la modification de la compétence :" . $e->getMessage());
}
// Log Discord
sendLog("Modification de la catégorie de compétences : " . $title . " (id " . $id . ")");
// On renvoie l'utilisateur sur admin.php
header('Location: ../pages/admin.php');
exit;
+51 -4
View File
@@ -3,6 +3,9 @@
session_start();
// On ajoute la DB
require_once('../functions/databaseConnection.php');
// On ajoute les logs Discord
require_once('../functions/sendLogs.php');
require_once('../functions/pdfUpload.php');
// Si l'utilisateur n'est pas admin il ne peut pas executer le reste du script
if (!isset($_SESSION['role']) || $_SESSION['role'] !== 'admin') {
@@ -10,6 +13,12 @@ if (!isset($_SESSION['role']) || $_SESSION['role'] !== 'admin') {
exit;
}
// Le fichier envoyé dépasse post_max_size : $_POST/$_FILES sont vides, on le détecte
// tout de suite (sinon le script redirige silencieusement vers admin.php sans explication)
if (postDepasseLimite()) {
die(messageDepassementPost());
}
// Si le formulaire à un champ vide
if (
!isset($_POST['id']) || !is_numeric($_POST['id']) ||
@@ -26,29 +35,67 @@ if (
//On récupère les données pour les mettres en variables locales
$id = (int) $_POST['id'];
$title = trim($_POST['title']);
$status = trim($_POST['status'] ?? '');
$xptype = trim($_POST['xptype']);
$tags = trim($_POST['tags'] ?? '');
$description = trim($_POST['description']);
$duration = trim($_POST['duration']);
$imageurl = trim($_POST['imageurl']);
$markdown = trim($_POST['markdown'] ?? '');
$link_url = trim($_POST['linkurl'] ?? '');
// Lecture et validation du PDF envoyé (optionnel)
$pdfResultat = lireUploadPdf('pdf');
if (is_string($pdfResultat)) {
echo $pdfResultat;
exit;
}
// Le PDF n'est mis à jour que si un nouveau fichier est envoyé OU si la case
// "Supprimer ce PDF" est cochée. Sinon on garde le PDF actuel intact.
$updatePdf = false;
$pdfData = null;
$pdfFilename = null;
if (is_array($pdfResultat)) {
$updatePdf = true;
$pdfData = $pdfResultat['data'];
$pdfFilename = $pdfResultat['filename'];
} elseif (isset($_POST['remove_pdf'])) {
$updatePdf = true;
}
try { // On essaie d'executer une requête qui est préparée
$stmt = $dbh->prepare('
$sql = '
UPDATE experiences
SET title = :title, xptype = :xptype, tags = :tags, description = :description, duration = :duration, image_url = :image_url
WHERE id = :id
');
SET title = :title, status = :status, xptype = :xptype, tags = :tags, description = :description, duration = :duration, image_url = :image_url, markdown = :markdown, link_url = :link_url';
if ($updatePdf) {
$sql .= ', pdf_data = :pdf_data, pdf_filename = :pdf_filename';
}
$sql .= ' WHERE id = :id';
$stmt = $dbh->prepare($sql);
$stmt->bindValue(':title', $title, PDO::PARAM_STR);
$stmt->bindValue(':status', $status, PDO::PARAM_STR);
$stmt->bindValue(':xptype', $xptype, PDO::PARAM_STR);
$stmt->bindValue(':tags', $tags, PDO::PARAM_STR);
$stmt->bindValue(':description', $description, PDO::PARAM_STR);
$stmt->bindValue(':duration', $duration, PDO::PARAM_STR);
$stmt->bindValue(':image_url', $imageurl, PDO::PARAM_STR);
$stmt->bindValue(':markdown', $markdown, PDO::PARAM_STR);
$stmt->bindValue(':link_url', $link_url, PDO::PARAM_STR);
if ($updatePdf) {
$stmt->bindValue(':pdf_data', $pdfData, $pdfData === null ? PDO::PARAM_NULL : PDO::PARAM_LOB);
$stmt->bindValue(':pdf_filename', $pdfFilename, $pdfFilename === null ? PDO::PARAM_NULL : PDO::PARAM_STR);
}
$stmt->bindValue(':id', $id, PDO::PARAM_INT);
$stmt->execute(); // Sinon on renvoie l'erreur
} catch (PDOException $e) {
die("Erreur lors de la modification de l experience :" . $e->getMessage());
}
// Log Discord
sendLog("Modification de l'expérience : " . $title . " (id " . $id . ")");
// On renvoie l'utilisateur sur admin.php
header('Location: ../pages/admin.php');
exit;
+48
View File
@@ -0,0 +1,48 @@
<?php
// Sert le PDF stocké en base pour un projet / une expérience / une école
// Utilisé en <iframe> 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
$tables = [
'projet' => 'projects',
'experience' => 'experiences',
'ecole' => 'schools',
];
$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] . '` WHERE id = :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;