Initial commit : CMS Simplifié

This commit is contained in:
Safouane Bazzi
2025-10-21 21:34:20 +02:00
commit 9e0c151fa6
17 changed files with 622 additions and 0 deletions

55
public/add.php Normal file
View File

@@ -0,0 +1,55 @@
<?php
session_start();
if(!isset($_SESSION['user_id'])){ header('Location: login.php'); exit; }
require __DIR__ . '/../inc/db.php';
$error = null;
if($_SERVER['REQUEST_METHOD']==='POST'){
$titre = trim($_POST['titre'] ?? '');
$contenu = trim($_POST['contenu'] ?? '');
if($titre!=='' && $contenu!==''){
$stmt = $pdo->prepare("INSERT INTO articles(titre,contenu) VALUES(?,?)");
$stmt->execute([$titre,$contenu]);
header('Location: admin.php'); exit;
} else { $error = 'Champs obligatoires.'; }
}
?>
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Ajouter un article</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="assets/style.css?v=6" rel="stylesheet">
</head>
<body>
<nav class="navbar">
<div class="container container-narrow d-flex align-items-center gap-3">
<a class="navbar-brand fw-semibold" href="admin.php">Administration</a>
<div class="ms-auto navbar-text">Connecté: <?= htmlspecialchars($_SESSION['user_login']) ?></div>
<a class="btn btn-outline-accent btn-sm" href="logout.php">Se déconnecter</a>
</div>
</nav>
<main class="container container-narrow py-4" style="max-width:820px">
<div class="card p-4">
<h1 class="h4 mb-3">Ajouter un article</h1>
<?php if($error): ?><div class="alert alert-danger"><?= htmlspecialchars($error) ?></div><?php endif; ?>
<form method="post" class="vstack gap-3">
<div>
<label class="form-label">Titre</label>
<input class="form-control" type="text" name="titre" required>
</div>
<div>
<label class="form-label">Contenu</label>
<textarea class="form-control" rows="10" name="contenu" required></textarea>
</div>
<div class="d-flex gap-2">
<button class="btn btn-accent">Enregistrer</button>
<a class="btn btn-outline-accent" href="admin.php">Annuler</a>
</div>
</form>
</div>
</main>
</body>
</html>

54
public/admin.php Normal file
View File

@@ -0,0 +1,54 @@
<?php
session_start();
if(!isset($_SESSION['user_id'])) { header('Location: login.php'); exit; }
require __DIR__ . '/../inc/db.php';
$stmt = $pdo->query("SELECT * FROM articles ORDER BY date_creation DESC");
$articles = $stmt->fetchAll();
?>
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Administration</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="assets/style.css?v=6" rel="stylesheet">
</head>
<body>
<nav class="navbar">
<div class="container container-narrow d-flex align-items-center gap-3">
<a class="navbar-brand fw-semibold" href="/">CMS Simplifié</a>
<div class="ms-auto navbar-text">Connecté: <?= htmlspecialchars($_SESSION['user_login']) ?></div>
<a class="btn btn-outline-accent btn-sm" href="logout.php">Se déconnecter</a>
</div>
</nav>
<main class="container container-narrow py-4">
<div class="d-flex justify-content-between align-items-center mb-3">
<h1 class="h4 m-0">Articles</h1>
<a class="btn btn-accent btn-sm" href="add.php">Ajouter</a>
</div>
<?php if(!$articles): ?>
<div class="alert alert-secondary">Aucun article.</div>
<?php else: ?>
<div class="list-group">
<?php foreach($articles as $a): ?>
<div class="list-group-item d-flex justify-content-between align-items-center">
<div>
<div class="fw-semibold item-title"><?= htmlspecialchars($a['titre']) ?></div>
<small class="text-muted"><?= htmlspecialchars($a['date_creation']) ?></small>
</div>
<div class="d-flex gap-2">
<a class="btn btn-outline-accent btn-sm" href="edit.php?id=<?= (int)$a['id'] ?>">Modifier</a>
<a class="btn btn-danger btn-sm" href="delete.php?id=<?= (int)$a['id'] ?>">Supprimer</a>
</div>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
</main>
</body>
</html>

40
public/article.php Normal file
View File

@@ -0,0 +1,40 @@
<?php
require __DIR__ . '/../inc/db.php';
$id=filter_input(INPUT_GET,'id',FILTER_VALIDATE_INT);
if(!$id){http_response_code(404);exit('404 - Article non trouvé');}
$stmt=$pdo->prepare("SELECT id,titre,contenu,date_creation FROM articles WHERE id=?");
$stmt->execute([$id]);
$article=$stmt->fetch();
if(!$article){http_response_code(404);exit('404 - Article non trouvé');}
?>
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title><?= htmlspecialchars($article['titre']) ?></title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="assets/style.css" rel="stylesheet">
</head>
<body>
<nav class="navbar">
<div class="container container-narrow">
<a class="navbar-brand fw-semibold" href="/">CMS Simplifié</a>
<a class="btn btn-sm btn-light" href="/">Accueil</a>
</div>
</nav>
<main class="container container-narrow py-4">
<div class="card p-4">
<div class="d-flex justify-content-between align-items-start">
<h1 class="h3 mb-2"><?= htmlspecialchars($article['titre']) ?></h1>
<span class="badge badge-date"><?= htmlspecialchars($article['date_creation']) ?></span>
</div>
<div class="mt-3"><?= nl2br(htmlspecialchars($article['contenu'])) ?></div>
</div>
<div class="mt-3">
<a class="btn btn-outline-secondary btn-sm" href="/">← Retour</a>
</div>
</main>
</body>
</html>

119
public/assets/style.css Normal file
View File

@@ -0,0 +1,119 @@
:root{
--bg-dark:#121212;
--bg-card:#1e1e1e;
--text-light:#f5f5f5;
--text-muted:#b3b3b3;
--accent:#d4af37;
}
body{
background:var(--bg-dark);
color:var(--text-light);
font-family:'Inter',sans-serif;
}
.container-narrow{max-width:860px}
.navbar{
background:linear-gradient(90deg,#1a1a1a,#333);
box-shadow:0 2px 15px rgba(0,0,0,.6);
}
.navbar .navbar-brand{
color:var(--accent)!important;
font-weight:600;
letter-spacing:.5px;
}
.navbar .navbar-text{
color:var(--text-light)!important;
}
.navbar a.btn-outline-accent{
border-color:var(--accent)!important;
color:var(--accent)!important;
}
.navbar a.btn-outline-accent:hover{
background:var(--accent);
color:#000!important;
}
h1,h2,h3,h4,h5{color:var(--text-light);margin:0 0 .6rem}
.item-title{color:var(--text-light)}
.text-muted{color:var(--text-muted)!important}
.card{
background:var(--bg-card);
border:1px solid #2d2d2d;
box-shadow:0 8px 25px rgba(0,0,0,.5);
color:var(--text-light);
border-radius:10px;
}
.btn-accent{
background:var(--accent);
color:#000;
border:0;
font-weight:600;
transition:.25s;
}
.btn-accent:hover{
background:#b8952d;
color:#000;
}
.btn-outline-accent{
background:transparent;
border:1px solid var(--accent);
color:var(--accent);
font-weight:600;
transition:.25s;
}
.btn-outline-accent:hover{
background:var(--accent);
color:#000;
}
.btn-danger{
background:#b51c1c;
border:none;
color:#fff;
font-weight:600;
transition:.25s;
}
.btn-danger:hover{
background:#d62828;
color:#fff;
}
.form-control,textarea{
background:#2a2a2a;
border:1px solid #444;
color:var(--text-light);
}
.form-control:focus,textarea:focus{
border-color:var(--accent);
box-shadow:0 0 0 .15rem rgba(212,175,55,.25);
background:#2f2f2f;
color:#fff;
}
.alert{
background:#2d2d2d;
color:#ccc;
border:none;
}
.list-group-item{
background:#1c1c1c;
border:1px solid #333;
}
.list-group-item .text-muted{
color:var(--text-muted)!important;
}
a{
color:var(--accent);
text-decoration:none;
font-weight:500;
}
a:hover{
text-decoration:underline;
color:#f1c94e;
}

46
public/delete.php Normal file
View File

@@ -0,0 +1,46 @@
<?php
session_start();
if(!isset($_SESSION['user_id'])){ header('Location: login.php'); exit; }
require __DIR__ . '/../inc/db.php';
$id = filter_input(INPUT_GET,'id',FILTER_VALIDATE_INT);
if(!$id){ http_response_code(404); exit('404'); }
$stmt = $pdo->prepare("SELECT id,titre FROM articles WHERE id=?");
$stmt->execute([$id]);
$article = $stmt->fetch();
if(!$article){ http_response_code(404); exit('404'); }
if($_SERVER['REQUEST_METHOD']==='POST'){
$del = $pdo->prepare("DELETE FROM articles WHERE id=?");
$del->execute([$id]);
header('Location: admin.php'); exit;
}
?>
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Supprimer un article</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="assets/style.css?v=6" rel="stylesheet">
</head>
<body>
<nav class="navbar">
<div class="container container-narrow d-flex align-items-center gap-3">
<a class="navbar-brand fw-semibold" href="admin.php">Administration</a>
<div class="ms-auto navbar-text">Connecté: <?= htmlspecialchars($_SESSION['user_login']) ?></div>
<a class="btn btn-outline-accent btn-sm" href="logout.php">Se déconnecter</a>
</div>
</nav>
<main class="container container-narrow py-4" style="max-width:700px">
<div class="card p-4">
<h1 class="h4 mb-3">Confirmation</h1>
<div class="alert alert-warning mb-4">Supprimer « <?= htmlspecialchars($article['titre']) ?> » ?</div>
<form method="post" class="d-flex gap-2">
<button class="btn btn-accent">Confirmer</button>
<a class="btn btn-outline-accent" href="admin.php">Annuler</a>
</form>
</div>
</main>
</body>
</html>

61
public/edit.php Normal file
View File

@@ -0,0 +1,61 @@
<?php
session_start();
if(!isset($_SESSION['user_id'])){ header('Location: login.php'); exit; }
require __DIR__ . '/../inc/db.php';
$id = filter_input(INPUT_GET,'id',FILTER_VALIDATE_INT);
if(!$id){ http_response_code(404); exit('404'); }
$stmt = $pdo->prepare("SELECT id,titre,contenu FROM articles WHERE id=?");
$stmt->execute([$id]);
$article = $stmt->fetch();
if(!$article){ http_response_code(404); exit('404'); }
$error = null;
if($_SERVER['REQUEST_METHOD']==='POST'){
$titre = trim($_POST['titre'] ?? '');
$contenu = trim($_POST['contenu'] ?? '');
if($titre!=='' && $contenu!==''){
$upd = $pdo->prepare("UPDATE articles SET titre=?,contenu=? WHERE id=?");
$upd->execute([$titre,$contenu,$id]);
header('Location: admin.php'); exit;
} else { $error = 'Champs obligatoires.'; }
}
?>
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Modifier un article</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="assets/style.css?v=6" rel="stylesheet">
</head>
<body>
<nav class="navbar">
<div class="container container-narrow d-flex align-items-center gap-3">
<a class="navbar-brand fw-semibold" href="admin.php">Administration</a>
<div class="ms-auto navbar-text">Connecté: <?= htmlspecialchars($_SESSION['user_login']) ?></div>
<a class="btn btn-outline-accent btn-sm" href="logout.php">Se déconnecter</a>
</div>
</nav>
<main class="container container-narrow py-4" style="max-width:820px">
<div class="card p-4">
<h1 class="h4 mb-3">Modifier larticle</h1>
<?php if($error): ?><div class="alert alert-danger"><?= htmlspecialchars($error) ?></div><?php endif; ?>
<form method="post" class="vstack gap-3">
<div>
<label class="form-label">Titre</label>
<input class="form-control" type="text" name="titre" required value="<?= htmlspecialchars($article['titre']) ?>">
</div>
<div>
<label class="form-label">Contenu</label>
<textarea class="form-control" rows="10" name="contenu" required><?= htmlspecialchars($article['contenu']) ?></textarea>
</div>
<div class="d-flex gap-2">
<button class="btn btn-accent">Mettre à jour</button>
<a class="btn btn-outline-accent" href="admin.php">Annuler</a>
</div>
</form>
</div>
</main>
</body>
</html>

48
public/index.php Normal file
View File

@@ -0,0 +1,48 @@
<?php
require __DIR__ . '/../inc/db.php';
$stmt=$pdo->prepare("SELECT id,titre,SUBSTRING(contenu,1,180) AS intro,date_creation FROM articles ORDER BY date_creation DESC LIMIT 10");
$stmt->execute();
$articles=$stmt->fetchAll();
?>
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Accueil</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="assets/style.css" rel="stylesheet">
</head>
<body>
<nav class="navbar navbar-expand-lg">
<div class="container container-narrow">
<a class="navbar-brand fw-semibold" href="/">CMS Simplifié</a>
<div class="ms-auto">
<a class="btn btn-sm btn-light" href="login.php">Admin</a>
</div>
</div>
</nav>
<main class="container container-narrow py-4">
<h1 class="mb-4">Derniers articles</h1>
<?php if(!$articles): ?>
<div class="alert alert-secondary">Aucun article pour le moment.</div>
<?php else: ?>
<div class="row g-4">
<?php foreach($articles as $a): ?>
<div class="col-12">
<div class="card p-3">
<div class="d-flex justify-content-between align-items-start">
<h5 class="mb-2"><?= htmlspecialchars($a['titre']) ?></h5>
<span class="badge badge-date"><?= htmlspecialchars($a['date_creation']) ?></span>
</div>
<p class="mb-3"><?= nl2br(htmlspecialchars($a['intro'])) ?>...</p>
<a class="btn btn-accent btn-sm" href="article.php?id=<?= (int)$a['id'] ?>">Lire</a>
</div>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
</main>
</body>
</html>

52
public/login.php Normal file
View File

@@ -0,0 +1,52 @@
<?php
session_start();
require __DIR__ . '/../inc/db.php';
$error=null;
if($_SERVER['REQUEST_METHOD']==='POST'){
$login=isset($_POST['login'])?trim($_POST['login']):'';
$password=$_POST['password']??'';
$stmt=$pdo->prepare("SELECT * FROM utilisateur WHERE login=?");
$stmt->execute([$login]);
$user=$stmt->fetch();
if($user && password_verify($password,$user['password'])){
$_SESSION['user_id']=$user['id'];
$_SESSION['user_login']=$user['login'];
header('Location: admin.php'); exit;
} else { $error='Identifiants incorrects.'; }
}
?>
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Connexion</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="assets/style.css" rel="stylesheet">
</head>
<body>
<nav class="navbar">
<div class="container container-narrow">
<a class="navbar-brand fw-semibold" href="/">CMS Simplifié</a>
</div>
</nav>
<main class="container container-narrow py-5" style="max-width:520px">
<div class="card p-4">
<h1 class="h4 mb-3">Connexion</h1>
<?php if($error): ?><div class="alert alert-danger"><?= htmlspecialchars($error) ?></div><?php endif; ?>
<form method="post" class="vstack gap-3">
<div>
<label class="form-label">Login</label>
<input class="form-control" type="text" name="login" required>
</div>
<div>
<label class="form-label">Mot de passe</label>
<input class="form-control" type="password" name="password" required>
</div>
<button class="btn btn-accent">Se connecter</button>
</form>
</div>
</main>
</body>
</html>

5
public/logout.php Normal file
View File

@@ -0,0 +1,5 @@
<?php
session_start();
session_destroy();
header('Location: login.php');
exit;