View file blog/edit_post.php

File size: 8.43Kb
<?php
/**
 * CMS: LaiCMS (v1.0 Edition 2026)
 * File: admin/edit_post.php
 * Description: Редактирование с поддержкой категорий, загрузкой медиа и адаптивным интерфейсом.
 */

require_once '../system/db.php';
require_once '../system/functions.php';

if (!isset($_SESSION['user_id'])) { 
    header("Location: /users/login.php"); 
    exit; 
}

$id = isset($_GET['id']) ? (int)$_GET['id'] : 0;

// Загружаем данные поста
$stmt = $mysqli->prepare("SELECT * FROM posts WHERE id = ? LIMIT 1");
$stmt->bind_param("i", $id);
$stmt->execute();
$post = $stmt->get_result()->fetch_assoc();

// Проверка прав
if (!$post || ($post['author_id'] != $_SESSION['user_id'] && !isAdmin())) {
    die("У вас нет прав для редактирования этой статьи.");
}

/**
 * ОБРАБОТЧИК ЗАГРУЗКИ ИЗОБРАЖЕНИЙ (AJAX для TinyMCE)
 */
if (isset($_FILES['file'])) {
    $img_dir = '../uploads/blog/';
    if (!is_dir($img_dir)) mkdir($img_dir, 0777, true);

    $file = $_FILES['file'];
    $ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
    $allowed = ['jpg', 'jpeg', 'png', 'gif', 'webp'];

    if (in_array($ext, $allowed)) {
        $name = md5(time() . $file['name']) . '.' . $ext;
        $destination = $img_dir . $name;
        
        if (move_uploaded_file($file['tmp_name'], $destination)) {
            header('Content-Type: application/json');
            echo json_encode(['location' => '/uploads/blog/' . $name]);
            exit;
        }
    }
    header("HTTP/1.1 500 Server Error");
    exit;
}

// Получаем категории для выпадающего списка
$categories_res = $mysqli->query("SELECT * FROM categories ORDER BY name ASC");

if ($_SERVER['REQUEST_METHOD'] === 'POST' && !isset($_FILES['file'])) {
    if (!isset($_POST['csrf_token']) || !check_csrf($_POST['csrf_token'])) {
        die("Ошибка безопасности (CSRF)");
    }

    $title = trim($_POST['title']);
    $cat_id = (int)$_POST['category_id'];
    $allowed_tags = '<p><br><b><i><strong><em><ul><ol><li><a><img><iframe><table><thead><tbody><tr><td><th><h1><h2><h3><h4><h5><h6><div><span><blockquote><code><hr>';
    $content = strip_tags($_POST['content'], $allowed_tags);

    if (mb_strlen($title) < 5) {
        set_flash("Заголовок слишком короткий", "error");
    } elseif (mb_strlen($content) < 20) {
        set_flash("Текст слишком мал", "error");
    } else {
        // Обновляем заголовок, контент и КАТЕГОРИЮ
        $update = $mysqli->prepare("UPDATE posts SET title = ?, content = ?, category_id = ? WHERE id = ?");
        $update->bind_param("ssii", $title, $content, $cat_id, $id);
        
        if ($update->execute()) {
            if (file_exists('../seo_gen.php')) {
                ob_start(); include '../seo_gen.php'; ob_end_clean();
            }
            set_flash("Публикация «" . _e($title) . "» обновлена!", "success");
            header("Location: /blog/view.php?slug=" . $post['slug']);
            exit;
        } else {
            set_flash("Ошибка базы данных.", "error");
        }
    }
}

include '../system/header.php';
?>

<script src="https://cdnjs.cloudflare.com/ajax/libs/tinymce/6.8.2/tinymce.min.js"></script>

<style>
    .editor-wrapper { max-width: 1100px; margin: 0 auto; }
    .tox-tinymce { border-radius: 12px !important; border: 1px solid var(--pico-muted-border-color) !important; box-shadow: 0 10px 30px rgba(0,0,0,0.05); }
    .edit-header { background: var(--pico-card-sectioning-background-color); border-radius: 15px 15px 0 0; border-bottom: 1px solid var(--pico-muted-border-color); padding: 1.5rem; }
</style>

<div class="editor-wrapper">
    <article style="padding: 0; border: none; background: transparent;">
        <div class="edit-header">
            <div style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 15px;">
                <hgroup style="margin: 0;">
                    <h2 style="margin:0; font-size: 1.5rem;"><i class="fa-solid fa-pen-to-square" style="color: var(--pico-primary);"></i> Редактор контента</h2>
                    <p class="secondary" style="margin:0;">ID записи: #<?= $id ?></p>
                </hgroup>
                <a href="/blog/view.php?slug=<?= $post['slug'] ?>" target="_blank" class="outline secondary" style="font-size: 0.8rem;">
                    <i class="fa-solid fa-eye"></i> Предпросмотр
                </a>
            </div>
        </div>

        <div style="padding: 1.5rem; background: var(--pico-card-background-color); border-radius: 0 0 15px 15px; border: 1px solid var(--pico-muted-border-color); border-top: none;">
            <?php display_flash(); ?>

            <form method="POST" id="postForm">
                <input type="hidden" name="csrf_token" value="<?= _e($_SESSION['csrf_token']) ?>">
                
                <div class="grid">
                    <div style="flex: 3;">
                        <label for="title">Заголовок</label>
                        <input type="text" id="title" name="title" value="<?= _e($post['title']) ?>" required>
                    </div>
                    <div>
                        <label for="category_id">Категория</label>
                        <select id="category_id" name="category_id">
                            <option value="0">Без категории</option>
                            <?php while($cat = $categories_res->fetch_assoc()): ?>
                                <option value="<?= $cat['id'] ?>" <?= ($post['category_id'] == $cat['id']) ? 'selected' : '' ?>>
                                    <?= _e($cat['name']) ?>
                                </option>
                            <?php endwhile; ?>
                        </select>
                    </div>
                </div>

                <label for="word-editor">Текст публикации</label>
                <textarea id="word-editor" name="content"><?= $post['content'] ?></textarea>
                
                <footer style="margin-top: 2rem; background: transparent; padding: 0;">
                    <div class="grid">
                        <button type="submit" class="primary"><i class="fa-solid fa-floppy-disk"></i> Сохранить изменения</button>
                        <a href="/admin/blog_manage.php" role="button" class="outline secondary">К списку постов</a>
                    </div>
                </footer>
            </form>
        </div>
    </article>
</div>

<script>
    tinymce.init({
        selector: '#word-editor',
        language: 'ru',
        promotion: false,
        branding: false,
        height: 600,
        images_upload_url: 'edit_post.php?id=<?= $id ?>', 
        automatic_uploads: true,
        paste_data_images: true,
        plugins: ['advlist', 'autolink', 'lists', 'link', 'image', 'media', 'table', 'code', 'fullscreen', 'emoticons', 'wordcount', 'autosave'],
        toolbar: 'undo redo | blocks | bold italic underline | forecolor backcolor | alignleft aligncenter alignright | bullist numlist | link image media emoticons | code fullscreen preview',
        
        // Автоматическая адаптация под темную/светлую тему Pico CSS
        skin: (document.documentElement.getAttribute('data-theme') === 'dark' ? 'oxide-dark' : 'oxide'),
        content_css: (document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'default'),
        
        content_style: `
            body { font-family: "Inter", sans-serif; font-size: 16px; max-width: 800px; margin: 20px auto; padding: 20px !important; }
            img { max-width: 100%; height: auto; border-radius: 10px; }
            iframe { width: 100% !important; border-radius: 10px; aspect-ratio: 16/9; }
        `,
        
        setup: function (editor) {
            editor.on('change', function () {
                editor.save();
                window.isChanged = true;
            });
        }
    });

    const form = document.getElementById('postForm');
    window.isChanged = false;
    window.onbeforeunload = () => { if (window.isChanged) return "Вы не сохранили изменения!"; };
    form.onsubmit = () => { window.onbeforeunload = null; };
</script>

<?php include '../system/footer.php'; ?>