<?php
declare(strict_types=1);
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
$title = 'Управление блогом';
require_once '../sys/sys.php';
require_once '../sys/db.php';
require_once '../sys/head.php';
function parseBBCode(string $text): string {
$patterns = [
'/\[b\](.*?)\[\/b\]/is' => '<strong>$1</strong>',
'/\[i\](.*?)\[\/i\]/is' => '<em>$1</em>',
'/\[u\](.*?)\[\/u\]/is' => '<u>$1</u>',
'/\[s\](.*?)\[\/s\]/is' => '<s>$1</s>',
'/\[sup\](.*?)\[\/sup\]/is' => '<sup>$1</sup>',
'/\[sub\](.*?)\[\/sub\]/is' => '<sub>$1</sub>',
'/\[url=(.*?)\](.*?)\[\/url\]/is' => '<a href="$1" target="_blank" rel="nofollow">$2</a>',
'/\[url\](.*?)\[\/url\]/is' => '<a href="$1" target="_blank" rel="nofollow">$1</a>',
'/\[img\](.*?)\[\/img\]/is' => '<img src="$1" alt="" class="img-fluid bb-img">',
'/\[img=(.*?)x(.*?)\](.*?)\[\/img\]/is' => '<img src="$3" width="$1" height="$2" alt="" class="img-fluid bb-img">',
'/\[color=(.*?)\](.*?)\[\/color\]/is' => '<span style="color:$1">$2</span>',
'/\[size=(\d+)\](.*?)\[\/size\]/is' => '<span style="font-size:$1px">$2</span>',
'/\[font=(.*?)\](.*?)\[\/font\]/is' => '<span style="font-family:$1">$2</span>',
'/\[highlight\](.*?)\[\/highlight\]/is' => '<span class="bb-highlight">$1</span>',
'/\[quote\](.*?)\[\/quote\]/is' => '<blockquote class="bb-quote">$1</blockquote>',
'/\[quote=(.*?)\](.*?)\[\/quote\]/is' => '<blockquote class="bb-quote"><cite>$1</cite>$2</blockquote>',
'/\[code\](.*?)\[\/code\]/is' => '<pre class="bb-code"><code>$1</code></pre>',
'/\[code=(.*?)\](.*?)\[\/code\]/is' => '<pre class="bb-code"><code class="language-$1">$2</code></pre>',
'/\[list\](.*?)\[\/list\]/is' => '<ul class="bb-list">$1</ul>',
'/\[list=1\](.*?)\[\/list\]/is' => '<ol class="bb-list">$1</ol>',
'/\[\*\](.*?)(\n|$)/is' => '<li>$1</li>',
'/\[center\](.*?)\[\/center\]/is' => '<div style="text-align:center">$1</div>',
'/\[right\](.*?)\[\/right\]/is' => '<div style="text-align:right">$1</div>',
'/\[left\](.*?)\[\/left\]/is' => '<div style="text-align:left">$1</div>',
'/\[justify\](.*?)\[\/justify\]/is' => '<div style="text-align:justify">$1</div>',
'/\[youtube\](.*?)\[\/youtube\]/is' => '<div class="bb-video-container"><iframe src="https://www.youtube.com/embed/$1" frameborder="0" allowfullscreen class="bb-video"></iframe></div>',
'/\[video\](.*?)\[\/video\]/is' => '<div class="bb-video-container"><video src="$1" controls class="bb-video"></video></div>',
'/\[audio\](.*?)\[\/audio\]/is' => '<div class="bb-audio-container"><audio src="$1" controls class="bb-audio"></audio></div>',
'/\[table\](.*?)\[\/table\]/is' => '<table class="bb-table">$1</table>',
'/\[tr\](.*?)\[\/tr\]/is' => '<tr>$1</tr>',
'/\[td\](.*?)\[\/td\]/is' => '<td>$1</td>',
'/\[th\](.*?)\[\/th\]/is' => '<th>$1</th>',
'/\[spoiler\](.*?)\[\/spoiler\]/is' => '<div class="bb-spoiler"><button class="bb-spoiler-btn" onclick="toggleSpoiler(this)">Спойлер ▼</button><div class="bb-spoiler-content">$1</div></div>',
'/\[spoiler=(.*?)\](.*?)\[\/spoiler\]/is' => '<div class="bb-spoiler"><button class="bb-spoiler-btn" onclick="toggleSpoiler(this)">$1 ▼</button><div class="bb-spoiler-content">$2</div></div>',
'/\[accordion=(.*?)\](.*?)\[\/accordion\]/is' => '<div class="bb-accordion"><button class="bb-accordion-btn" onclick="toggleAccordion(this)">$1 ▼</button><div class="bb-accordion-content">$2</div></div>',
'/\[hr\]/is' => '<hr class="bb-hr">',
'/\[br\]/is' => '<br>',
'/\[pagebreak\]/is' => '<div class="bb-pagebreak"></div>',
'/\[tag\](.*?)\[\/tag\]/is' => '<span class="badge badge-info mr-1 mb-1">$1</span>'
];
$text = htmlspecialchars($text);
foreach ($patterns as $pattern => $replacement) {
$text = preg_replace($pattern, $replacement, $text);
}
$text = nl2br($text);
$blockElements = ['table', 'tr', 'td', 'th', 'ul', 'ol', 'li', 'blockquote', 'pre', 'div', 'hr'];
foreach ($blockElements as $tag) {
$text = preg_replace('/<br\s?\/?>\s*<(\\/' . $tag . '|' . $tag . ')/i', '<$1', $text);
}
return $text;
}
if (!isset($_SESSION['admin'])) {
echo '<div class="container"><div class="alert alert-danger">Ошибка! Доступ запрещен!</div></div>';
require_once '../sys/foot.php';
exit;
}
$max = 5;
echo '<div class="bg-index"><br/>
<div class="title-page">
<h2 style="color: #fff;">Управление блогом</h2>
</div>
<div class="container">
<center>
<p class="text-light" style="position: relative; z-index: 99; font-size: 120%;">
Управление записями блога <b>' . htmlspecialchars($_SERVER['HTTP_HOST']) . '</b>
</p>
</center>
</div><br/>
</div><br/><br/>';
if (isset($_GET['action'])) {
$action = $_GET['action'];
$id = isset($_GET['id']) ? intval($_GET['id']) : 0;
switch ($action) {
case 'add':
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$title = htmlspecialchars($_POST['title']);
$content = $_POST['content'];
$published = isset($_POST['published']) ? 1 : 0;
$tags = isset($_POST['tags']) ? implode(',', array_map('trim', explode(',', $_POST['tags']))) : '';
$query = "INSERT INTO `blog` (`title`, `content`, `published`, `tags`) VALUES (?, ?, ?, ?)";
$stmt = $mysqli->prepare($query);
$stmt->bind_param('ssis', $title, $content, $published, $tags);
if ($stmt->execute()) {
$_SESSION['message'] = 'Запись успешно добавлена!';
header("Location: /admin/blog");
exit();
} else {
$_SESSION['message'] = 'Ошибка при добавлении записи: ' . $stmt->error;
}
}
break;
case 'edit':
if ($id > 0 && $_SERVER['REQUEST_METHOD'] === 'POST') {
$title = htmlspecialchars($_POST['title']);
$content = $_POST['content'];
$published = isset($_POST['published']) ? 1 : 0;
$tags = isset($_POST['tags']) ? implode(',', array_map('trim', explode(',', $_POST['tags']))) : '';
$query = "UPDATE `blog` SET `title` = ?, `content` = ?, `published` = ?, `tags` = ? WHERE `id` = ?";
$stmt = $mysqli->prepare($query);
$stmt->bind_param('ssisi', $title, $content, $published, $tags, $id);
if ($stmt->execute()) {
$_SESSION['message'] = 'Запись успешно обновлена!';
header("Location: /admin/blog");
exit();
} else {
$_SESSION['message'] = 'Ошибка при обновлении записи: ' . $stmt->error;
}
}
break;
case 'delete':
if ($id > 0) {
$query = "DELETE FROM `blog` WHERE `id` = ?";
$stmt = $mysqli->prepare($query);
$stmt->bind_param('i', $id);
if ($stmt->execute()) {
$_SESSION['message'] = 'Запись успешно удалена!';
} else {
$_SESSION['message'] = 'Ошибка при удалении записи: ' . $stmt->error;
}
header("Location: /admin/blog");
exit();
}
break;
case 'toggle_publish':
if ($id > 0) {
$query = "UPDATE `blog` SET `published` = NOT `published` WHERE `id` = ?";
$stmt = $mysqli->prepare($query);
$stmt->bind_param('i', $id);
if ($stmt->execute()) {
$_SESSION['message'] = 'Статус публикации изменен!';
} else {
$_SESSION['message'] = 'Ошибка при изменении статуса: ' . $stmt->error;
}
header("Location: /admin/blog");
exit();
}
break;
}
}
if (isset($_SESSION['message'])) {
echo '<div class="container"><div class="alert alert-info">' . htmlspecialchars($_SESSION['message']) . '</div></div>';
unset($_SESSION['message']);
}
echo '<div class="container">
<div class="d-flex justify-content-between mb-4">
<a href="/admin/" class="btn btn-secondary">
Назад в админ-панель
</a>
<a href="/admin/blog?action=add" class="btn btn-primary">
Добавить запись
</a>
</div>';
$count = $pdo->query('SELECT COUNT(*) FROM `blog`')->fetchColumn();
$pages = ceil($count / $max);
$page = !empty($_GET['page']) ? intval($_GET['page']) : 1;
if ($page > $pages && $pages > 0) $page = $pages;
if ($page < 1) $page = 1;
$start = ($page - 1) * $max;
$query = $pdo->prepare('SELECT * FROM `blog` ORDER BY `created_at` DESC LIMIT :limit OFFSET :offset');
$query->bindValue(':limit', $max, PDO::PARAM_INT);
$query->bindValue(':offset', $start, PDO::PARAM_INT);
$query->execute();
$postsList = $query->fetchAll();
if (!empty($postsList)) {
echo '<div class="row">';
foreach ($postsList as $post) {
$statusBadge = $post['published'] ?
'<span class="badge badge-success">Опубликовано</span>' :
'<span class="badge badge-warning">Черновик</span>';
$tagsHtml = '';
if (!empty($post['tags'])) {
$tags = explode(',', $post['tags']);
$tagLinks = [];
foreach ($tags as $tag) {
$tag = trim($tag);
if (!empty($tag)) {
$tagLinks[] = '<span class="badge badge-info mr-1">' . htmlspecialchars($tag) . '</span>';
}
}
if (!empty($tagLinks)) {
$tagsHtml = '<div class="mb-3"><small class="text-muted"></i> Теги: ' . implode(' ', $tagLinks) . '</small></div>';
}
}
echo '<div class="col-md-12 mb-4">
<div class="card">
<div class="card-header bg-light d-flex justify-content-between align-items-center">
<h4 class="card-title mb-0">' . htmlspecialchars($post['title']) . ' ' . $statusBadge . '</h4>
<div>
<a href="/admin/blog?action=toggle_publish&id=' . $post['id'] . '" class="btn btn-sm ' . ($post['published'] ? 'btn-warning' : 'btn-success') . '">
' . ($post['published'] ? 'Снять с публикации' : 'Опубликовать') . '
</a>
</div>
</div>
<div class="card-body">
<div class="card-text bb-content">' . parseBBCode($post['content']) . '</div>
' . $tagsHtml . '
<div class="text-muted small mt-2">
</i> Опубликовано: ' . htmlspecialchars($post['created_at']) . '
</div>
</div>
<div class="card-footer bg-white">
<div class="btn-group">
<a href="/admin/blog?action=edit&id=' . $post['id'] . '" class="btn btn-sm btn-outline-warning ">
Редактировать
</a>
<a href="/admin/blog?action=delete&id=' . $post['id'] . '"
class="btn btn-sm btn-outline-danger"
onclick="return confirm(\'Вы уверены, что хотите удалить эту запись?\')">
Удалить
</a>
</div>
</div>
</div>
</div>';
}
echo '</div>';
echo '<div class="container mt-4">
<div class="row">
<div class="col-md-12">
<nav aria-label="Page navigation">
<ul class="pagination justify-content-center">';
if ($page > 1) {
echo '<li class="page-item"><a class="page-link" href="/admin/blog?page='.($page-1).'">«</a></li>';
} else {
echo '<li class="page-item disabled"><span class="page-link">«</span></li>';
}
$startPage = max(1, $page - 2);
$endPage = min($pages, $page + 2);
if ($startPage > 1) {
echo '<li class="page-item"><a class="page-link" href="/admin/blog?page=1">1</a></li>';
if ($startPage > 2) {
echo '<li class="page-item disabled"><span class="page-link">...</span></li>';
}
}
for ($i = $startPage; $i <= $endPage; $i++) {
if ($i == $page) {
echo '<li class="page-item active"><span class="page-link">'.$i.'</span></li>';
} else {
echo '<li class="page-item"><a class="page-link" href="/admin/blog?page='.$i.'">'.$i.'</a></li>';
}
}
if ($endPage < $pages) {
if ($endPage < $pages - 1) {
echo '<li class="page-item disabled"><span class="page-link">...</span></li>';
}
echo '<li class="page-item"><a class="page-link" href="/admin/blog?page='.$pages.'">'.$pages.'</a></li>';
}
if ($page < $pages) {
echo '<li class="page-item"><a class="page-link" href="/admin/blog?page='.($page+1).'">»</a></li>';
} else {
echo '<li class="page-item disabled"><span class="page-link">»</span></li>';
}
echo '</ul>
</nav>
</div>
</div>
</div>';
echo '<div class="container">
<div class="row">
<div class="col-lg-4 col-md-3"></div>
<div class="col-lg-4 col-md-6">
<div class="alert bg-light stat">
<center><a href="/admin/" class="btn btn-secondary">Админ панель</a></center>
</div>
</div>
</div>
</div>';
} else {
echo '<div class="alert alert-warning">Записей в блоге пока нет. <a href="/admin/blog?action=add" class="alert-link">Добавить первую запись</a></div>';
}
echo '</div>';
if (isset($_GET['action']) && ($_GET['action'] === 'add' || $_GET['action'] === 'edit')) {
$id = isset($_GET['id']) ? intval($_GET['id']) : 0;
$title = '';
$content = '';
$published = 0;
$tags = '';
if ($_GET['action'] === 'edit' && $id > 0) {
$query = $pdo->prepare('SELECT * FROM `blog` WHERE `id` = ?');
$query->execute([$id]);
$post = $query->fetch();
if ($post) {
$title = $post['title'] ?? '';
$content = $post['content'] ?? '';
$published = $post['published'] ?? 0;
$tags = $post['tags'] ?? '';
}
}
echo '<div class="container mt-4 mb-5">
<div class="row justify-content-center">
<div class="col-md-10">
<div class="card">
<div class="card-header bg-primary text-white">
' . ($_GET['action'] === 'add' ? 'Добавление записи' : 'Редактирование записи') . '
</div>
<div class="card-body">
<form action="/admin/blog?action=' . $_GET['action'] . ($id > 0 ? '&id=' . $id : '') . '" method="POST">
<div class="form-group">
<label for="title">Заголовок</label>
<input type="text" name="title" id="title" class="form-control" value="' . htmlspecialchars($title) . '" required>
</div>
<div class="form-group">
<label for="content">Содержание</label>
<textarea name="content" id="content" class="form-control" rows="12" required>' . htmlspecialchars($content) . '</textarea>
<small class="form-text text-muted">
Поддерживаются BB-коды:
[b], [i], [u], [s], [sup], [sub],
[url], [img], [color], [size], [font],
[quote], [code], [list], [table],
[youtube], [video], [audio],
[spoiler], [accordion], [hr], [br], [tag]
</small>
</div>
<div class="form-group">
<label for="tags">Теги (через запятую)</label>
<input type="text" name="tags" id="tags" class="form-control" value="' . htmlspecialchars($tags) . '" placeholder="iframe,раскрутка,продвижение,SEO,трафик,AdRed">
</div>
<div class="form-group form-check">
<input type="checkbox" name="published" id="published" class="form-check-input" ' . ($published ? 'checked' : '') . '>
<label class="form-check-label" for="published">Опубликовать</label>
</div>
<div class="form-group text-right">
<button type="submit" class="btn btn-success">
Сохранить
</button>
<a href="/admin/blog" class="btn btn-secondary">Отмена</a>
</div>
</form>
</div>
</div>
</div>
</div>
</div>';
echo '<script>
function toggleSpoiler(btn) {
const content = btn.nextElementSibling;
content.style.display = content.style.display === "none" ? "block" : "none";
btn.innerHTML = btn.innerHTML.includes("▲") ? btn.innerHTML.replace("▲", "▼") : btn.innerHTML.replace("▼", "▲");
}
function toggleAccordion(btn) {
const content = btn.nextElementSibling;
content.style.display = content.style.display === "none" ? "block" : "none";
btn.innerHTML = btn.innerHTML.includes("▲") ? btn.innerHTML.replace("▲", "▼") : btn.innerHTML.replace("▼", "▲");
}
document.addEventListener("DOMContentLoaded", function() {
document.querySelectorAll(".bb-spoiler-content").forEach(el => {
el.style.display = "none";
});
document.querySelectorAll(".bb-accordion-content").forEach(el => {
el.style.display = "none";
});
});
</script>';
}
require_once '../sys/foot.php';
?>