View file adred.ru/admin/blog.php

File size: 19.34Kb
<?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).'">&laquo;</a></li>';
    } else {
        echo '<li class="page-item disabled"><span class="page-link">&laquo;</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).'">&raquo;</a></li>';
    } else {
        echo '<li class="page-item disabled"><span class="page-link">&raquo;</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';
?>