From cb045fb9e13a4d43a8d80b40b02b5acb2026d832 Mon Sep 17 00:00:00 2001 From: Abd-El-Raouf Date: Sun, 2 Nov 2025 18:08:53 +0100 Subject: [PATCH] first commit --- .idea/workspace.xml | 72 ++++++++++++++++++++ Dockerfile | 9 +++ README.md | 48 +++++++++++++ admin/add.php | 59 ++++++++++++++++ admin/board.php | 42 ++++++++++++ admin/delete.php | 54 +++++++++++++++ admin/login.php | 38 +++++++++++ admin/logout.php | 19 ++++++ admin/modif.php | 73 ++++++++++++++++++++ article.php | 35 ++++++++++ assets/add.css | 127 +++++++++++++++++++++++++++++++++++ assets/article.css | 81 ++++++++++++++++++++++ assets/board.css | 109 ++++++++++++++++++++++++++++++ assets/delete.css | 75 +++++++++++++++++++++ assets/login.css | 119 +++++++++++++++++++++++++++++++++ assets/modif.css | 127 +++++++++++++++++++++++++++++++++++ assets/style.css | 137 ++++++++++++++++++++++++++++++++++++++ bdd/Dockerfile | 8 +++ bdd/init.sql | 20 ++++++ include/authenticator.php | 32 +++++++++ include/db.php | 12 ++++ index.php | 42 ++++++++++++ launch-dockers.sh | 25 +++++++ 23 files changed, 1363 insertions(+) create mode 100644 .idea/workspace.xml create mode 100644 Dockerfile create mode 100644 README.md create mode 100644 admin/add.php create mode 100644 admin/board.php create mode 100644 admin/delete.php create mode 100644 admin/login.php create mode 100644 admin/logout.php create mode 100644 admin/modif.php create mode 100644 article.php create mode 100644 assets/add.css create mode 100644 assets/article.css create mode 100644 assets/board.css create mode 100644 assets/delete.css create mode 100644 assets/login.css create mode 100644 assets/modif.css create mode 100644 assets/style.css create mode 100644 bdd/Dockerfile create mode 100644 bdd/init.sql create mode 100644 include/authenticator.php create mode 100644 include/db.php create mode 100644 index.php create mode 100644 launch-dockers.sh diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000..e5a0d5c --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1762090649427 + + + + + + \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..49ade17 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,9 @@ +FROM php:8.2-apache +LABEL authors="abdr-cms" + +COPY . /var/www/html +WORKDIR /var/www/html + +RUN docker-php-ext-install pdo pdo_mysql + +EXPOSE 80 \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..0465ca6 --- /dev/null +++ b/README.md @@ -0,0 +1,48 @@ +Pour accéder au site : Lancez les conteneurs depuis la racine du projet avec la commande suivante (Dans un terminal qui accepte le bash par exemple GIT bash) : + +./launch-dockers.sh + +Une fois les conteneurs démarrés, le site sera accessible dans votre navigateur à l'adresse : + +http://localhost:8080/ + +Accès au compte admin : + +Login : user + +Mdp: usecms123 + +Arborescence : + +Projet_CMS/ +│ +├── admin/ +│ ├── add.php +│ ├── board.php +│ ├── delete.php +│ ├── login.php +│ ├── logout.php +│ └── modif.php +│ +├── assets/ +│ ├── add.css +│ ├── article.css +│ ├── board.css +│ ├── delete.css +│ ├── login.css +│ ├── modif.css +│ └── style.css +│ +├── bdd/ +│ ├── Dockerfile +│ └── init.sql +│ +├── include/ +│ ├── authenticator.php +│ └── bd.php +│ +├── article.php +├── Dockerfile +├── index.php +├── launch-dockers.sh +└── README.md \ No newline at end of file diff --git a/admin/add.php b/admin/add.php new file mode 100644 index 0000000..a5c861b --- /dev/null +++ b/admin/add.php @@ -0,0 +1,59 @@ +prepare('INSERT INTO articles (titre, contenu, date_creation) VALUES (:titre, :contenu, :date)'); + $stmt->execute([ + ':titre' => $titre, + ':contenu' => $contenu, + ':date' => date('Y-m-d H:i:s'), + ]); + header('Location:board.php'); + exit; + } +} +?> + + + + + Ajouter un article + + + +
+

Ajouter un article

+
+ +
+ +

+ + +
+ + +
+ + Annuler +
+
+
+ + diff --git a/admin/board.php b/admin/board.php new file mode 100644 index 0000000..678c856 --- /dev/null +++ b/admin/board.php @@ -0,0 +1,42 @@ +query('SELECT * FROM articles ORDER BY date_creation DESC'); +$articles = $stmt->fetchAll(); +?> + + +Admin - Tableau de bord + + +
+

Tableau de bord

+ +
+ +
+ + + + + + + + + +
IDTitreActions
+ Modifier + Supprimer +
+
+ + + + + diff --git a/admin/delete.php b/admin/delete.php new file mode 100644 index 0000000..cbc2d1a --- /dev/null +++ b/admin/delete.php @@ -0,0 +1,54 @@ +prepare('SELECT id, titre FROM articles WHERE id = :id'); +$stmt->execute([':id' => $id]); +$article = $stmt->fetch(); +if (!$article) { + header('Location: board.php'); + exit; +} + +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + if (isset($_POST['confirm']) && $_POST['confirm'] === 'yes') { + $d = $pdo->prepare('DELETE FROM articles WHERE id = :id'); + $d->execute([':id' => $id]); + } + header('Location: board.php'); + exit; +} +?> + + + + + + Supprimer l'article + + + + +
Supprimer l'article
+ +
+

Êtes-vous sûr de vouloir supprimer : ?

+
+
+ + Annuler +
+
+
+ + + + + diff --git a/admin/login.php b/admin/login.php new file mode 100644 index 0000000..13638e1 --- /dev/null +++ b/admin/login.php @@ -0,0 +1,38 @@ + + + + + + Connexion + + + + +
+

Connexion

+
+
+
+ +
+
+

+ + + + diff --git a/admin/logout.php b/admin/logout.php new file mode 100644 index 0000000..9cbb503 --- /dev/null +++ b/admin/logout.php @@ -0,0 +1,19 @@ + + diff --git a/admin/modif.php b/admin/modif.php new file mode 100644 index 0000000..cf9335e --- /dev/null +++ b/admin/modif.php @@ -0,0 +1,73 @@ +prepare('SELECT * FROM articles WHERE id = :id'); +$stmt->execute([':id' => $id]); +$article = $stmt->fetch(); +if (!$article) { + header('Location: board.php'); + exit; +} + +$errors = []; +$titre = $article['titre']; +$contenu = $article['contenu']; + +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $titre = trim($_POST['titre'] ?? ''); + $contenu = trim($_POST['contenu'] ?? ''); + if ($titre === '' || $contenu === '') { + $errors[] = 'Tous les champs sont obligatoires.'; + } else { + $u = $pdo->prepare('UPDATE articles SET titre = :titre, contenu = :contenu WHERE id = :id'); + $u->execute([':titre' => $titre, ':contenu' => $contenu, ':id' => $id]); + header('Location: board.php'); + exit; + } +} +?> + + + + + + Modifier l'article + + + + +
Modifier l'article
+ +
+
+ +

+ + +
+ + +
+ + Annuler +
+
+
+
+ + + + diff --git a/article.php b/article.php new file mode 100644 index 0000000..bf3f9c8 --- /dev/null +++ b/article.php @@ -0,0 +1,35 @@ +prepare('SELECT * FROM articles WHERE id = ?'); +$stmt->execute([$id]); +$article = $stmt->fetch(); +if (!$article) { http_response_code(404); die('

404 - Article introuvable

'); } +?> + + + + + + <?= htmlspecialchars($article['titre']) ?> + + + + +
+ +
+

+
+

+
+ Retour +
+ + + + + + diff --git a/assets/add.css b/assets/add.css new file mode 100644 index 0000000..5209135 --- /dev/null +++ b/assets/add.css @@ -0,0 +1,127 @@ +/* --- Body --- */ +body { + font-family: 'Segoe UI', Roboto, Arial, sans-serif; + background-color: #f3f0f9; + color: #333; + margin: 0; + padding: 0; + min-height: 100vh; + display: flex; + flex-direction: column; +} + +/* --- Bande violette en haut --- */ +header { + background: linear-gradient(135deg, #6a11cb, #8e2de2); + color: #fff; + padding: 12px 0; + display: flex; + justify-content: center; /* titre centré */ + align-items: center; + font-size: 1.3rem; + font-weight: 700; + box-shadow: 0 2px 5px rgba(0,0,0,0.2); +} + +/* --- Espace distinct entre header et formulaire --- */ +section.form-section { + margin-top: 40px; /* espace entre bande et formulaire */ + flex: 1; + display: flex; + justify-content: center; + padding: 20px; +} + +/* --- Formulaire stylé --- */ +form { + display: flex; + flex-direction: column; + gap: 15px; + background: #fff; + padding: 30px 25px; + border-radius: 10px; + border: 1px solid #e0d4f7; + box-shadow: 0 3px 6px rgba(0,0,0,0.08); + width: 90%; + max-width: 600px; +} + +/* --- Labels et Inputs --- */ +form label { + display: flex; + flex-direction: column; + font-weight: 600; + color: #5b1dbb; + text-align: left; +} + +form input[type="text"], +form textarea { + padding: 12px 15px; + border: 1px solid #dcd0f5; + border-radius: 6px; + font-size: 1rem; + resize: vertical; + transition: border-color 0.2s ease, box-shadow 0.2s ease; +} + +form input[type="text"]:focus, +form textarea:focus { + outline: none; + border-color: #8e2de2; + box-shadow: 0 0 5px rgba(142,45,226,0.5); +} + +/* --- Boutons Publier et Annuler --- */ +.form-buttons { + display: flex; + justify-content: center; + gap: 15px; +} + +button, +a.btn { + padding: 12px 25px; + background: linear-gradient(135deg, #6a11cb, #8e2de2); + color: #fff; + border: none; + border-radius: 6px; + font-size: 1rem; + font-weight: 600; + text-decoration: none; + cursor: pointer; + transition: background 0.3s ease, transform 0.2s ease; +} + +button:hover, +a.btn:hover { + background: linear-gradient(135deg, #8e2de2, #6a11cb); + transform: translateY(-2px); +} + +/* --- Messages d'erreur --- */ +.error { + color: #721c24; + background: #f8d7da; + border: 1px solid #f5c6cb; + padding: 12px; + border-radius: 6px; + width: 90%; + max-width: 600px; + margin-bottom: 15px; + text-align: center; + box-shadow: 0 2px 4px rgba(0,0,0,0.05); +} + +/* --- Footer violet --- */ +footer { + background: #6a11cb; + color: #fff; + text-align: center; + padding: 15px 0; + width: 100%; + box-shadow: 0 -2px 5px rgba(0,0,0,0.2); + font-size: 0.95rem; + position: fixed; + bottom: 0; +} diff --git a/assets/article.css b/assets/article.css new file mode 100644 index 0000000..7ee9c46 --- /dev/null +++ b/assets/article.css @@ -0,0 +1,81 @@ +/* --- Body --- */ +body { + font-family: 'Segoe UI', Roboto, Arial, sans-serif; + background-color: #f3f0f9; + color: #333; + margin: 0; + padding: 0; + min-height: 100vh; + display: flex; + flex-direction: column; +} + +/* --- Bande violette en haut --- */ +header { + background: linear-gradient(135deg, #6a11cb, #8e2de2); + height: 50px; /* hauteur réduite */ + box-shadow: 0 2px 5px rgba(0,0,0,0.2); +} + +/* --- Main --- */ +main { + flex: 1; + margin-top: 20px; /* espace sous header */ + display: flex; + flex-direction: column; + align-items: center; + padding: 20px; +} + +/* --- Titre de l'article --- */ +.article-title { + color: #5b1dbb; + font-size: 2rem; + font-weight: 700; + margin-bottom: 20px; + text-align: center; +} + +/* --- Article --- */ +article { + background: #fff; + padding: 25px 20px; + border-radius: 10px; + border: 1px solid #e0d4f7; + box-shadow: 0 3px 6px rgba(0,0,0,0.08); + width: 90%; + max-width: 800px; + margin-bottom: 20px; +} + +/* --- Bouton Retour --- */ +a.btn { + padding: 12px 25px; + background: linear-gradient(135deg, #6a11cb, #8e2de2); + color: #fff; + border: none; + border-radius: 6px; + font-size: 1rem; + font-weight: 600; + text-decoration: none; + cursor: pointer; + transition: background 0.3s ease, transform 0.2s ease; +} + +a.btn:hover { + background: linear-gradient(135deg, #8e2de2, #6a11cb); + transform: translateY(-2px); +} + +/* --- Footer --- */ +footer { + background: #6a11cb; + color: #fff; + text-align: center; + padding: 15px 0; + width: 100%; + font-size: 0.95rem; + box-shadow: 0 -2px 5px rgba(0,0,0,0.2); + position: fixed; + bottom: 0; +} diff --git a/assets/board.css b/assets/board.css new file mode 100644 index 0000000..ee50d05 --- /dev/null +++ b/assets/board.css @@ -0,0 +1,109 @@ +/* --- Body --- */ +body { + font-family: 'Segoe UI', Roboto, Arial, sans-serif; + background-color: #f3f0f9; + color: #333; + margin: 0; + padding: 0; + min-height: 100vh; + display: flex; + flex-direction: column; +} + +/* --- Header violet --- */ +header { + background: linear-gradient(135deg, #6a11cb, #8e2de2); + color: #fff; + padding: 30px 0 15px 0; + display: flex; + flex-direction: column; + align-items: center; + position: fixed; + top: 0; + left: 0; + width: 100%; + box-shadow: 0 2px 5px rgba(0,0,0,0.2); + z-index: 1000; +} + +/* --- Titre Tableau de bord --- */ +header h1 { + margin: 0; + font-size: 2rem; + font-weight: 700; +} + +/* --- Conteneur boutons --- */ +.header-buttons { + margin-top: 10px; + display: flex; + gap: 10px; +} + +/* --- Boutons violet --- */ +.btn { + padding: 10px 20px; + background: linear-gradient(135deg, #6a11cb, #8e2de2); + color: #fff; + border: none; + border-radius: 6px; + font-weight: 600; + text-decoration: none; + cursor: pointer; + transition: background 0.3s ease, transform 0.2s ease; +} + +.btn:hover { + background: linear-gradient(135deg, #8e2de2, #6a11cb); + transform: translateY(-2px); +} + +/* --- Main contenu --- */ +main { + flex: 1; + margin-top: 140px; /* hauteur du header */ + display: flex; + flex-direction: column; + align-items: center; + padding: 20px; +} + +/* --- Tableau stylé --- */ +table { + width: 90%; + max-width: 900px; + border-collapse: collapse; + background: #fff; + border-radius: 8px; + overflow: hidden; + box-shadow: 0 2px 5px rgba(0,0,0,0.1); + margin-top: 20px; +} + +table th, table td { + padding: 12px 15px; + border-bottom: 1px solid #ddd; + text-align: left; +} + +table th { + background-color: #8e2de2; + color: #fff; +} + +table tr:hover { + background-color: #f5e9ff; +} + +/* --- Footer violet --- */ +footer { + background: #6a11cb; + color: #fff; + text-align: center; + padding: 15px 0; + width: 100%; + box-shadow: 0 -2px 5px rgba(0,0,0,0.2); + font-size: 0.95rem; + position: fixed; + bottom: 0; +} diff --git a/assets/delete.css b/assets/delete.css new file mode 100644 index 0000000..ba99fdb --- /dev/null +++ b/assets/delete.css @@ -0,0 +1,75 @@ +/* --- Body --- */ +body { + font-family: 'Segoe UI', Roboto, Arial, sans-serif; + background-color: #f3f0f9; + color: #333; + margin: 0; + padding: 0; + min-height: 100vh; + display: flex; + flex-direction: column; +} + +/* --- Bande violette en haut --- */ +header { + background: linear-gradient(135deg, #6a11cb, #8e2de2); + color: #fff; + padding: 12px 0; + display: flex; + justify-content: center; + align-items: center; + font-size: 1.3rem; + font-weight: 700; + box-shadow: 0 2px 5px rgba(0,0,0,0.2); +} + +/* --- Section principale distincte --- */ +section.form-section { + margin-top: 40px; /* espace sous header */ + flex: 1; + display: flex; + justify-content: center; + padding: 20px; +} + +/* --- Formulaire confirmation --- */ +form { + display: flex; + flex-direction: column; + gap: 20px; + background: #fff; + padding: 25px 20px; + border-radius: 10px; + border: 1px solid #e0d4f7; + box-shadow: 0 3px 6px rgba(0,0,0,0.08); + width: 90%; + max-width: 500px; + text-align: center; +} + +/* --- Boutons Supprimer / Annuler --- */ +.form-buttons { + display: flex; + justify-content: center; + gap: 15px; +} + +button, +a.btn { + padding: 12px 25px; + background: linear-gradient(135deg, #6a11cb, #8e2de2); + color: #fff; + border: none; + border-radius: 6px; + font-size: 1rem; + font-weight: 600; + text-decoration: none; + cursor: pointer; + transition: background 0.3s ease, transform 0.2s ease; +} + +button:hover, +a.btn:hover { + background: linear-gradient(135deg, #8e2de2, #6a11cb); + transform: translateY(-2px); +} \ No newline at end of file diff --git a/assets/login.css b/assets/login.css new file mode 100644 index 0000000..e40fcfe --- /dev/null +++ b/assets/login.css @@ -0,0 +1,119 @@ +/* --- Body --- */ +body { + font-family: 'Segoe UI', Roboto, Arial, sans-serif; + background-color: #f3f0f9; + color: #333; + margin: 0; + padding: 0; + min-height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; /* CENTRAGE VERTICAL */ +} + +/* --- Header fixe violet --- */ +nav { + background: linear-gradient(135deg, #6a11cb, #8e2de2); + color: #fff; + padding: 15px 30px; + display: flex; + justify-content: flex-start; /* Accueil à gauche */ + align-items: center; + position: fixed; + top: 0; + left: 0; + width: 100%; + box-shadow: 0 2px 5px rgba(0,0,0,0.2); + z-index: 1000; +} + +nav a { + color: #fff; + text-decoration: none; + font-weight: 600; + font-size: 1.1rem; +} + +nav a:hover { + opacity: 0.8; +} + +/* --- Conteneur du formulaire et du titre --- */ +.login-container { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + margin-top: 80px; /* espace pour nav fixe */ +} + +/* --- Titre Connexion --- */ +.login-container h1 { + color: #5b1dbb; + margin-bottom: 30px; + text-align: center; +} + +/* --- Formulaire centré --- */ +form { + display: flex; + flex-direction: column; + gap: 15px; + background: #fff; + padding: 40px 30px; + border-radius: 10px; + border: 1px solid #e0d4f7; + box-shadow: 0 3px 6px rgba(0,0,0,0.08); + width: 90%; + max-width: 400px; + text-align: center; +} + +/* --- Inputs --- */ +form input[type="text"], +form input[type="password"] { + padding: 12px 15px; + border: 1px solid #dcd0f5; + border-radius: 6px; + font-size: 1rem; + transition: border-color 0.2s ease, box-shadow 0.2s ease; +} + +form input[type="text"]:focus, +form input[type="password"]:focus { + outline: none; + border-color: #8e2de2; + box-shadow: 0 0 5px rgba(142,45,226,0.5); +} + +/* --- Bouton Se connecter --- */ +form button { + padding: 12px; + background: linear-gradient(135deg, #6a11cb, #8e2de2); + color: #fff; + border: none; + border-radius: 6px; + font-size: 1rem; + font-weight: 600; + cursor: pointer; + transition: background 0.3s ease, transform 0.2s ease; +} + +form button:hover { + background: linear-gradient(135deg, #8e2de2, #6a11cb); + transform: translateY(-2px); +} + +/* --- Footer violet --- */ +footer { + background: #6a11cb; + color: #fff; + text-align: center; + padding: 15px 0; + width: 100%; + box-shadow: 0 -2px 5px rgba(0,0,0,0.2); + font-size: 0.95rem; + position: fixed; + bottom: 0; +} diff --git a/assets/modif.css b/assets/modif.css new file mode 100644 index 0000000..5209135 --- /dev/null +++ b/assets/modif.css @@ -0,0 +1,127 @@ +/* --- Body --- */ +body { + font-family: 'Segoe UI', Roboto, Arial, sans-serif; + background-color: #f3f0f9; + color: #333; + margin: 0; + padding: 0; + min-height: 100vh; + display: flex; + flex-direction: column; +} + +/* --- Bande violette en haut --- */ +header { + background: linear-gradient(135deg, #6a11cb, #8e2de2); + color: #fff; + padding: 12px 0; + display: flex; + justify-content: center; /* titre centré */ + align-items: center; + font-size: 1.3rem; + font-weight: 700; + box-shadow: 0 2px 5px rgba(0,0,0,0.2); +} + +/* --- Espace distinct entre header et formulaire --- */ +section.form-section { + margin-top: 40px; /* espace entre bande et formulaire */ + flex: 1; + display: flex; + justify-content: center; + padding: 20px; +} + +/* --- Formulaire stylé --- */ +form { + display: flex; + flex-direction: column; + gap: 15px; + background: #fff; + padding: 30px 25px; + border-radius: 10px; + border: 1px solid #e0d4f7; + box-shadow: 0 3px 6px rgba(0,0,0,0.08); + width: 90%; + max-width: 600px; +} + +/* --- Labels et Inputs --- */ +form label { + display: flex; + flex-direction: column; + font-weight: 600; + color: #5b1dbb; + text-align: left; +} + +form input[type="text"], +form textarea { + padding: 12px 15px; + border: 1px solid #dcd0f5; + border-radius: 6px; + font-size: 1rem; + resize: vertical; + transition: border-color 0.2s ease, box-shadow 0.2s ease; +} + +form input[type="text"]:focus, +form textarea:focus { + outline: none; + border-color: #8e2de2; + box-shadow: 0 0 5px rgba(142,45,226,0.5); +} + +/* --- Boutons Publier et Annuler --- */ +.form-buttons { + display: flex; + justify-content: center; + gap: 15px; +} + +button, +a.btn { + padding: 12px 25px; + background: linear-gradient(135deg, #6a11cb, #8e2de2); + color: #fff; + border: none; + border-radius: 6px; + font-size: 1rem; + font-weight: 600; + text-decoration: none; + cursor: pointer; + transition: background 0.3s ease, transform 0.2s ease; +} + +button:hover, +a.btn:hover { + background: linear-gradient(135deg, #8e2de2, #6a11cb); + transform: translateY(-2px); +} + +/* --- Messages d'erreur --- */ +.error { + color: #721c24; + background: #f8d7da; + border: 1px solid #f5c6cb; + padding: 12px; + border-radius: 6px; + width: 90%; + max-width: 600px; + margin-bottom: 15px; + text-align: center; + box-shadow: 0 2px 4px rgba(0,0,0,0.05); +} + +/* --- Footer violet --- */ +footer { + background: #6a11cb; + color: #fff; + text-align: center; + padding: 15px 0; + width: 100%; + box-shadow: 0 -2px 5px rgba(0,0,0,0.2); + font-size: 0.95rem; + position: fixed; + bottom: 0; +} diff --git a/assets/style.css b/assets/style.css new file mode 100644 index 0000000..5edd12d --- /dev/null +++ b/assets/style.css @@ -0,0 +1,137 @@ +/* --- Style global --- */ +body { + font-family: 'Segoe UI', Roboto, Arial, sans-serif; + line-height: 1.6; + margin: 0; + padding: 0; + background-color: #f3f0f9; + color: #333; + min-height: 100vh; + display: flex; + flex-direction: column; +} + +/* --- En-tête --- */ +header { + background: linear-gradient(135deg, #6a11cb, #8e2de2); /* Dégradé violet */ + color: #fff; + padding: 15px 30px; + display: flex; + justify-content: space-between; /* Accueil à gauche, Admin à droite */ + align-items: center; + position: fixed; /* Fixé en haut */ + top: 0; + left: 0; + width: 100%; + z-index: 1000; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); +} + +/* --- Liens dans le header --- */ +header a { + color: #fff; + text-decoration: none; + font-weight: 600; + font-size: 1.1rem; + transition: opacity 0.2s ease; +} + +header a:hover { + opacity: 0.8; +} + +/* --- Espace pour éviter que le contenu passe sous le header --- */ +main { + flex: 1; + margin-top: 80px; /* Hauteur du header */ + padding: 20px; +} + +/* --- Titres --- */ +h1, h2, h3 { + color: #5b1dbb; +} + +/* --- Articles --- */ +article { + background: #fff; + padding: 20px; + margin: 15px auto; + width: 90%; + max-width: 800px; + border-radius: 10px; + border: 1px solid #e0d4f7; + box-shadow: 0 3px 6px rgba(0, 0, 0, 0.08); + transition: transform 0.2s ease, box-shadow 0.2s ease; +} + +article:hover { + transform: translateY(-3px); + box-shadow: 0 6px 10px rgba(0, 0, 0, 0.15); +} + +/* --- Liens d’articles --- */ +article h2 a { + color: #8e2de2; + text-decoration: none; + transition: color 0.2s ease; +} + +article h2 a:hover { + color: #5b1dbb; + text-decoration: underline; +} + +/* --- Tableaux --- */ +table { + width: 90%; + margin: 25px auto; + border-collapse: collapse; + background: #fff; + border-radius: 8px; + overflow: hidden; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); +} + +table th, table td { + padding: 12px 15px; + border-bottom: 1px solid #ddd; +} + +table th { + background-color: #8e2de2; + color: #fff; + text-align: left; +} + +table tr:hover { + background-color: #f5e9ff; +} + +/* --- Messages d’erreur --- */ +.error { + color: #721c24; + font-weight: 600; + border: 1px solid #f5c6cb; + background: #f8d7da; + padding: 12px; + border-radius: 6px; + width: 90%; + max-width: 800px; + margin: 10px auto; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); +} + +/* --- Pied de page --- */ +footer { + background: #6a11cb; + color: #fff; + text-align: center; + padding: 15px 0; + position: fixed; /* Collé en bas */ + bottom: 0; + left: 0; + width: 100%; + box-shadow: 0 -2px 5px rgba(0, 0, 0, 0.2); + font-size: 0.95rem; +} \ No newline at end of file diff --git a/bdd/Dockerfile b/bdd/Dockerfile new file mode 100644 index 0000000..41fcec8 --- /dev/null +++ b/bdd/Dockerfile @@ -0,0 +1,8 @@ +FROM mysql +LABEL authors="abdr-cms" + +ENV MYSQL_ROOT_PASSWORD='passwordroot' + +COPY ./init.sql /docker-entrypoint-initdb.d/ + +EXPOSE 3306 \ No newline at end of file diff --git a/bdd/init.sql b/bdd/init.sql new file mode 100644 index 0000000..922b7e3 --- /dev/null +++ b/bdd/init.sql @@ -0,0 +1,20 @@ +CREATE DATABASE IF NOT EXISTS cms_simple CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +USE cms_simple; + +CREATE TABLE utilisateur ( + id INT AUTO_INCREMENT PRIMARY KEY, + login VARCHAR(50) UNIQUE NOT NULL, + password VARCHAR(255) NOT NULL +); + + +CREATE TABLE articles ( + id INT AUTO_INCREMENT PRIMARY KEY, + titre VARCHAR(255) NOT NULL, + contenu TEXT NOT NULL, + date_creation DATETIME DEFAULT CURRENT_TIMESTAMP +); + + +INSERT INTO utilisateur (login, password) VALUES ('user', '$2y$10$W.kLJXFNZPdYcKXQbIyAVO0BGJQcVFc6JGYtsa1Z7SIjRDyUoOIfG'); \ No newline at end of file diff --git a/include/authenticator.php b/include/authenticator.php new file mode 100644 index 0000000..0523b3f --- /dev/null +++ b/include/authenticator.php @@ -0,0 +1,32 @@ +prepare('SELECT * FROM utilisateur WHERE login = ?'); + $stmt->execute([$login]); + $user = $stmt->fetch(); + + + if ($user && password_verify($password, $user['password'])) { + $_SESSION['user'] = $user['login']; + return true; + } + return false; +} + + +function requireLogin() { + if (!isLogged()) { + header('Location: login.php'); + exit; + } +} +?> diff --git a/include/db.php b/include/db.php new file mode 100644 index 0000000..d49cfb5 --- /dev/null +++ b/include/db.php @@ -0,0 +1,12 @@ +setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); +} catch (PDOException $e) { + die('Erreur de connexion : ' . $e->getMessage()); +} \ No newline at end of file diff --git a/index.php b/index.php new file mode 100644 index 0000000..8300ab8 --- /dev/null +++ b/index.php @@ -0,0 +1,42 @@ +query('SELECT * FROM articles ORDER BY date_creation DESC LIMIT 10'); +$articles = $stmt->fetchAll(); +?> + + + + + + Accueil - CMS + + + +
+ +
+ +
+

Articles

+ +

Aucun Article pour le moment

+ + + + + +
+ + + + diff --git a/launch-dockers.sh b/launch-dockers.sh new file mode 100644 index 0000000..b3d4ed1 --- /dev/null +++ b/launch-dockers.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +docker stop CMS_sql + +docker stop CMS_php + +docker rm CMS_sql + +docker rm CMS_php + +docker network rm CMS-bridge + +docker network create -d bridge CMS-bridge + +cd bdd + +docker build -t cms_sql . + +docker run -d --name CMS_sql -p 3307:3306 --network=CMS-bridge cms_sql:latest + +cd .. + +docker build -t cms_php . + +docker run -d --name CMS_php -p 8080:80 --network=CMS-bridge cms_php:latest