first commit
This commit is contained in:
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
8
.idea/ProjetCMS-Noam.iml
generated
Normal file
8
.idea/ProjetCMS-Noam.iml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/ProjetCMS-Noam.iml" filepath="$PROJECT_DIR$/.idea/ProjetCMS-Noam.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
22
.idea/php.xml
generated
Normal file
22
.idea/php.xml
generated
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="MessDetectorOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PHPCSFixerOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PHPCodeSnifferOptionsConfiguration">
|
||||
<option name="highlightLevel" value="WARNING" />
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PhpProjectSharedConfiguration" php_language_level="7.0">
|
||||
<option name="suggestChangeDefaultLanguageLevel" value="false" />
|
||||
</component>
|
||||
<component name="PhpStanOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PsalmOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
</project>
|
||||
9
Dockerfile
Normal file
9
Dockerfile
Normal file
@@ -0,0 +1,9 @@
|
||||
FROM php:8.2-apache
|
||||
LABEL authors="matthieulmr"
|
||||
|
||||
COPY . /var/www/html
|
||||
WORKDIR /var/www/html
|
||||
|
||||
RUN docker-php-ext-install pdo pdo_mysql
|
||||
|
||||
EXPOSE 80
|
||||
48
admin/add.php
Normal file
48
admin/add.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
global $pdo, $pdo;
|
||||
require '../include/db.php';
|
||||
require '../include/authenticator.php';
|
||||
requireLogin();
|
||||
|
||||
$errors = [];
|
||||
$titre = '';
|
||||
$contenu = '';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$titre = trim($_POST['titre'] ?? '');
|
||||
$contenu = trim($_POST['contenu'] ?? '');
|
||||
|
||||
if ($titre === '' || $contenu === '') {
|
||||
$errors[] = 'Tous les champs sont obligatoires.';
|
||||
} else {
|
||||
$stmt = $pdo->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;
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!doctype html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Ajouter un article</title>
|
||||
<link rel="stylesheet" href="/assets/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Ajouter un article</h1>
|
||||
<?php foreach ($errors as $e): ?>
|
||||
<p class="error"><?= htmlspecialchars($e) ?></p>
|
||||
<?php endforeach; ?>
|
||||
<form method="post">
|
||||
<label>Titre<br><input type="text" name="titre" value="<?= htmlspecialchars($titre) ?>" required></label><br>
|
||||
<label>Contenu<br><textarea name="contenu" rows="10" required><?= htmlspecialchars($contenu) ?></textarea></label><br>
|
||||
<button type="submit">Publier</button>
|
||||
<a href="board.php">Annuler</a>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
29
admin/board.php
Normal file
29
admin/board.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
global $pdo;
|
||||
require '../include/db.php';
|
||||
require '../include/authenticator.php';
|
||||
requireLogin();
|
||||
$stmt = $pdo->query('SELECT * FROM articles ORDER BY date_creation DESC');
|
||||
$articles = $stmt->fetchAll();
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head><meta charset="UTF-8"><title>Admin - Tableau de bord</title></head>
|
||||
<body>
|
||||
<h1>Tableau de bord</h1>
|
||||
<a href="add.php">Ajouter un article</a> | <a href="logout.php">Se déconnecter</a>
|
||||
<table border="1">
|
||||
<tr><th>ID</th><th>Titre</th><th>Actions</th></tr>
|
||||
<?php foreach ($articles as $a): ?>
|
||||
<tr>
|
||||
<td><?= $a['id'] ?></td>
|
||||
<td><?= htmlspecialchars($a['titre']) ?></td>
|
||||
<td>
|
||||
<a href="modif.php?id=<?= $a['id'] ?>">Modifier</a> |
|
||||
<a href="delete.php?id=<?= $a['id'] ?>">Supprimer</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
45
admin/delete.php
Normal file
45
admin/delete.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
global $pdo;
|
||||
require '../include/db.php';
|
||||
require '../include/authenticator.php';
|
||||
requireLogin();
|
||||
|
||||
$id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
|
||||
if ($id <= 0) {
|
||||
header('Location:board.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$stmt = $pdo->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;
|
||||
}
|
||||
?>
|
||||
<!doctype html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Supprimer l'article</title>
|
||||
<link rel="stylesheet" href="/assets/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Supprimer l'article</h1>
|
||||
<p>Êtes-vous sûr de vouloir supprimer : <strong><?= htmlspecialchars($article['titre']) ?></strong> ?</p>
|
||||
<form method="post">
|
||||
<button type="submit" name="confirm" value="yes">Oui, supprimer</button>
|
||||
<a href="board.php">Annuler</a>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
28
admin/login.php
Normal file
28
admin/login.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
global $pdo;
|
||||
require '../include/db.php';
|
||||
require '../include/authenticator.php';
|
||||
|
||||
$error = '';
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
if (checkLogin($pdo, $_POST['login'], $_POST['password'])) {
|
||||
header('Location: board.php');
|
||||
exit;
|
||||
} else {
|
||||
$error = 'Identifiants incorrects';
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head><meta charset="UTF-8"><title>Connexion</title></head>
|
||||
<body>
|
||||
<h1>Connexion</h1>
|
||||
<form method="post">
|
||||
<input type="text" name="login" placeholder="Login" required><br>
|
||||
<input type="password" name="password" placeholder="Mot de passe" required><br>
|
||||
<button type="submit">Se connecter</button>
|
||||
</form>
|
||||
<p style="color:red;"><?= $error ?></p>
|
||||
</body>
|
||||
</html>
|
||||
17
admin/logout.php
Normal file
17
admin/logout.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
require '../include/authenticator.php';
|
||||
|
||||
$_SESSION = [];
|
||||
|
||||
if (!function_exists('logout_user')) {
|
||||
$_SESSION = [];
|
||||
if (ini_get('session.use_cookies')) {
|
||||
$params = session_get_cookie_params();
|
||||
setcookie(session_name(), '', time() - 42000,
|
||||
$params['path'], $params['domain'], $params['secure'], $params['httponly']);
|
||||
}
|
||||
session_destroy();
|
||||
}
|
||||
|
||||
header('Location: ../index.php');
|
||||
exit;
|
||||
57
admin/modif.php
Normal file
57
admin/modif.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
global $pdo;
|
||||
require '../include/db.php';
|
||||
require '../include/authenticator.php';
|
||||
requireLogin();
|
||||
|
||||
$id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
|
||||
if ($id <= 0) {
|
||||
header('Location: board.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$stmt = $pdo->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;
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!doctype html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Modifier l'article</title>
|
||||
<link rel="stylesheet" href="/assets/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Modifier l'article</h1>
|
||||
<?php foreach ($errors as $e): ?>
|
||||
<p class="error"><?= htmlspecialchars($e) ?></p>
|
||||
<?php endforeach; ?>
|
||||
<form method="post">
|
||||
<label>Titre<br><input type="text" name="titre" value="<?= htmlspecialchars($titre) ?>" required></label><br>
|
||||
<label>Contenu<br><textarea name="contenu" rows="10" required><?= htmlspecialchars($contenu) ?></textarea></label><br>
|
||||
<button type="submit">Enregistrer</button>
|
||||
<a href="board.php">Annuler</a>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
18
article.php
Normal file
18
article.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
global $pdo;
|
||||
require 'include/db.php';
|
||||
$id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
|
||||
$stmt = $pdo->prepare('SELECT * FROM articles WHERE id = ?');
|
||||
$stmt->execute([$id]);
|
||||
$article = $stmt->fetch();
|
||||
if (!$article) { http_response_code(404); die('<h1>404 - Article introuvable</h1>'); }
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head><meta charset="UTF-8"><title><?= htmlspecialchars($article['titre']) ?></title></head>
|
||||
<body>
|
||||
<h1><?= htmlspecialchars($article['titre']) ?></h1>
|
||||
<p><?= nl2br(htmlspecialchars($article['contenu'])) ?></p>
|
||||
<a href="index.php">Retour</a>
|
||||
</body>
|
||||
</html>
|
||||
68
assets/style.css
Normal file
68
assets/style.css
Normal file
@@ -0,0 +1,68 @@
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
line-height: 1.6;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
background-color: #f4f4f4;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
header {
|
||||
background: #333;
|
||||
color: #fff;
|
||||
padding: 10px 0;
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #444;
|
||||
border-bottom: 2px solid #ccc;
|
||||
padding-bottom: 10px;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
article {
|
||||
background: #fff;
|
||||
padding: 15px;
|
||||
margin-bottom: 15px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
article h2 a {
|
||||
color: #007BFF;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
article h2 a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* Style spécifique pour l'Admin */
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
table th, table td {
|
||||
padding: 10px;
|
||||
border: 1px solid #ccc;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
table th {
|
||||
background-color: #e2e2e2;
|
||||
}
|
||||
|
||||
/* Style pour les messages d'erreur */
|
||||
.error {
|
||||
color: red;
|
||||
font-weight: bold;
|
||||
border: 1px solid red;
|
||||
padding: 10px;
|
||||
background: #ffe6e6;
|
||||
border-radius: 5px;
|
||||
}
|
||||
8
bdd/Dockerfile
Normal file
8
bdd/Dockerfile
Normal file
@@ -0,0 +1,8 @@
|
||||
FROM mysql
|
||||
LABEL authors="matthieulmr"
|
||||
|
||||
ENV MYSQL_ROOT_PASSWORD='passwordRoot'
|
||||
|
||||
COPY ./init.sql /docker-entrypoint-initdb.d/
|
||||
|
||||
EXPOSE 3306
|
||||
20
bdd/init.sql
Normal file
20
bdd/init.sql
Normal file
@@ -0,0 +1,20 @@
|
||||
CREATE DATABASE IF NOT EXISTS cms_simpli CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
USE cms_simpli;
|
||||
|
||||
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 ('admin', '$2y$10$OVqu798zF7FF36HER0nZ9uOJ5tuuTR.kwPK2GTiqlPPYzR2szGzB6');
|
||||
31
include/authenticator.php
Normal file
31
include/authenticator.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
session_start();
|
||||
|
||||
|
||||
function isLogged(): bool
|
||||
{
|
||||
return isset($_SESSION['user']);
|
||||
}
|
||||
|
||||
|
||||
function checkLogin(PDO $pdo, $login, $password): bool
|
||||
{
|
||||
$stmt = $pdo->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;
|
||||
}
|
||||
}
|
||||
13
include/db.php
Normal file
13
include/db.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
$host = 'CMS_mysql'; // nom du conteneur MySQL (dans le réseau Docker)
|
||||
$dbname = 'cms_simpli';
|
||||
$user = 'root';
|
||||
$pass = 'passwordRoot';
|
||||
$charset = 'utf8mb4';
|
||||
|
||||
try {
|
||||
$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8", $user, $pass);
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
} catch (PDOException $e) {
|
||||
die('Erreur de connexion : ' . $e->getMessage());
|
||||
}
|
||||
42
index.php
Normal file
42
index.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
global $pdo;
|
||||
require 'include/db.php';
|
||||
$stmt = $pdo->query('SELECT * FROM articles ORDER BY date_creation DESC LIMIT 10');
|
||||
$articles = $stmt->fetchAll();
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Accueil - CMS Simplifié</title>
|
||||
<link rel="stylesheet" href="assets/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<nav>
|
||||
<a href="index.php">Accueil</a> |
|
||||
<a href="admin/login.php">Administration</a>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<h1>Articles récents</h1>
|
||||
<?php if (empty($articles)): ?>
|
||||
<p>Aucun article n'a encore été publié.</p>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php foreach ($articles as $a): ?>
|
||||
<article>
|
||||
<h2><a href="article.php?id=<?= $a['id'] ?>"><?= htmlspecialchars($a['titre']) ?></a></h2>
|
||||
<small>Publié le <?= date('d/m/Y', strtotime($a['date_creation'])) ?></small>
|
||||
<p><?= substr(htmlspecialchars($a['contenu']), 0, 200) ?>...</p>
|
||||
<p><a href="article.php?id=<?= $a['id'] ?>">Lire la suite...</a></p>
|
||||
</article>
|
||||
<?php endforeach; ?>
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<p>© <?= date('Y') ?> CMS Simplifié. Tous droits réservés.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
25
launch-dockers.sh
Normal file
25
launch-dockers.sh
Normal file
@@ -0,0 +1,25 @@
|
||||
#!/bin/bash
|
||||
|
||||
docker stop CMS_mysql
|
||||
|
||||
docker stop CMS_php
|
||||
|
||||
docker rm CMS_mysql
|
||||
|
||||
docker rm CMS_php
|
||||
|
||||
docker network rm CMS-bridge
|
||||
|
||||
docker network create -d bridge CMS-bridge
|
||||
|
||||
cd bdd
|
||||
|
||||
docker build -t cms_mysql .
|
||||
|
||||
docker run -d --name CMS_mysql -p 3306:3306 --network=CMS-bridge cms_mysql:latest
|
||||
|
||||
cd ..
|
||||
|
||||
docker build -t cms_php .
|
||||
|
||||
docker run -d --name CMS_php -p 8080:80 --network=CMS-bridge cms_php:latest
|
||||
Reference in New Issue
Block a user