Files
DevWeb/index.php
2026-01-10 13:37:25 +00:00

175 lines
5.1 KiB
PHP

<?php
session_start();
require __DIR__ . '/config.php';
$postsFile = __DIR__ . '/data/posts.json';
if (!isset($_SESSION['csrf'])) {
$_SESSION['csrf'] = bin2hex(random_bytes(16));
}
function load_posts($file) {
$raw = @file_get_contents($file);
$arr = json_decode($raw ?: '[]', true);
return is_array($arr) ? $arr : [];
}
function save_posts($file, $posts) {
$tmp = $file . '.tmp';
file_put_contents($tmp, json_encode($posts, JSON_PRETTY_PRINT));
rename($tmp, $file);
}
$msg = '';
$err = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (!hash_equals($_SESSION['csrf'], $_POST['csrf'] ?? '')) {
$err = "Erreur CSRF.";
} else {
// Rate limit par IP
$ip = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
$lastKey = 'last_post_' . md5($ip);
$now = time();
$last = $_SESSION[$lastKey] ?? 0;
if ($now - $last < RATE_LIMIT_SECONDS) {
$err = "Trop rapide : 1 post par minute maximum.";
} else {
$text = trim($_POST['text'] ?? '');
if ($text === '' && empty($_FILES['image']['name'])) {
$err = "Il faut un message ou une image.";
} else {
$imagePath = '';
if (!empty($_FILES['image']['name'])) {
if ($_FILES['image']['error'] !== UPLOAD_ERR_OK) {
$err = "Erreur upload.";
} else if ($_FILES['image']['size'] > MAX_UPLOAD_BYTES) {
$err = "Image trop grosse (max ".MAX_UPLOAD_BYTES." bytes).";
} else {
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime = $finfo->file($_FILES['image']['tmp_name']);
$allowed = [
'image/png' => 'png',
'image/jpeg' => 'jpg',
];
if (!isset($allowed[$mime])) {
$err = "Format interdit. Autorisé: PNG/JPEG.";
} else {
$ext = $allowed[$mime];
$name = bin2hex(random_bytes(8)) . '.' . $ext;
$dest = __DIR__ . '/uploads/' . $name;
if (!move_uploaded_file($_FILES['image']['tmp_name'], $dest)) {
$err = "Impossible de sauvegarder l'image.";
} else {
$imagePath = '/uploads/' . $name;
}
}
}
}
if (!$err) {
$posts = load_posts($postsFile);
$posts[] = [
'time' => date('c'),
'ip' => $ip,
'text' => $text,
'img' => $imagePath
];
// plus récents en haut => on affichera en reverse
save_posts($postsFile, $posts);
$_SESSION[$lastKey] = $now;
$msg = "Post publié.";
}
}
}
}
}
$posts = load_posts($postsFile);
$posts = array_reverse($posts); // plus récents en haut
?>
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>DevWeb Forum</title>
<link rel="stylesheet" href="/style.css">
</head>
<body>
<div class="container">
<div class="nav">
<div class="brand">
<span class="dot"></span>
Mini-forum
</div>
<div>
<a href="/">Accueil</a>
<a href="/login.php">Login</a>
<a href="/flag.php">Flag</a>
<?php if (!empty($_SESSION['is_admin'])): ?>
<a href="/logout.php">Logout</a>
<?php endif; ?>
</div>
</div>
<div class="card header">
<h1>Mini-forum</h1>
<?php if (!empty($msg)): ?>
<div class="alert"><?php echo htmlspecialchars($msg); ?></div>
<?php endif; ?>
<?php if (!empty($err)): ?>
<div class="alert danger"><?php echo htmlspecialchars($err); ?></div>
<?php endif; ?>
<form method="post" enctype="multipart/form-data">
<input type="hidden" name="csrf" value="<?php echo htmlspecialchars($_SESSION['csrf']); ?>">
<div>
<label for="text">Commentaire</label>
<textarea id="text" name="text" placeholder="Ton message..."></textarea>
<div class="helper">Les posts récents apparaissent en premier.</div>
</div>
<div class="file">
<label for="image">Image (PNG/JPEG, max <?php echo (int)(MAX_UPLOAD_BYTES/1024/1024); ?> MB)</label>
<input id="image" type="file" name="image" accept=".png,.jpg,.jpeg,image/png,image/jpeg">
<div class="helper">Taille max côté serveur : <?php echo (int)(MAX_UPLOAD_BYTES/1024/1024); ?> MB.</div>
</div>
<button class="btn primary" type="submit">Publier</button>
</form>
</div>
<h2>Posts</h2>
<div class="posts">
<?php foreach ($posts as $p): ?>
<div class="post">
<div class="meta">
<span class="badge">📅 <?php echo htmlspecialchars($p['time']); ?></span>
<span class="badge">🌐 IP <?php echo htmlspecialchars($p['ip']); ?></span>
</div>
<?php if (!empty($p['text'])): ?>
<div class="content"><?php echo nl2br(htmlspecialchars($p['text'])); ?></div>
<?php endif; ?>
<?php if (!empty($p['img'])): ?>
<img src="<?php echo htmlspecialchars($p['img']); ?>" alt="Upload">
<?php endif; ?>
</div>
<?php endforeach; ?>
</div>
<div class="footer">CTF • dev.h.ctf.arrobe.fr</div>
</div>
</body>
</html>