↩️ Назад

Категории

code_post.php — просмотр код-поста

14.04.2026 | коды из категории: php

<p><b>🔐 ЗАЩИТА:</b><br>
- intval() + проверка ID<br>
- htmlspecialchars() для ВСЕГО вывода<br>
- PDO подготовленные запросы<br>
- CSRF-токен для комментариев<br>
- Капча в комментариях<br>
- escapeHtml() в JS
</p>

<p><b>⚙️ ФУНКЦИИ:</b><br>
- Вывод код-поста с блоками<br>
- Поддержка типов: heading, text, code, image, quote<br>
- Вывод тегов<br>
- Комментарии с защитой от XSS<br>
- Адаптивное изображение в hero-блоке
</p>

<?php
session_start();
require 'includes/db.php';
require 'includes/tags_functions.php';

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

if ($id <= 0) {
    http_response_code(404);
    include '404.php';
    exit;
}

$stmt = $pdo->prepare("
    SELECT cp.*, c.name as category_name
    FROM code_posts cp
    LEFT JOIN categories c ON cp.category_id = c.id
    WHERE cp.id = ?
");
$stmt->execute([$id]);
$post = $stmt->fetch();

if (!$post) {
    http_response_code(404);
    include '404.php';
    exit;
}

// Мета-данные (безопасное экранирование)
$meta_title = htmlspecialchars($post['meta_title'] ?? $post['title'], ENT_QUOTES, 'UTF-8');
$meta_description = htmlspecialchars($post['meta_description'] ?? '', ENT_QUOTES, 'UTF-8');
$post_type = 'code';

// CSRF-токен для комментариев
if (empty($_SESSION['csrf_token'])) {
    $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}

include 'includes/header.php';
?>

<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title><?= $meta_title ?> | iot_блог</title>
    <meta name="description" content="<?= $meta_description ?>">
    <meta property="og:title" content="<?= $meta_title ?>">
    <meta property="og:description" content="<?= $meta_description ?>">
    <link rel="canonical" href="https://blog.iotprof.ru/code_post.php?id=<?= $id ?>">
    <link href="/css/cool_comment.css" rel="stylesheet" />
    <link rel="stylesheet" href="/css/style.css">
    <link rel="stylesheet" href="/css/callback.css">
</head>
<body>
<br/>

<div class="container" style="position: relative;">
    <a href="javascript:history.back()" class="back-button" style="text-decoration:none">
        <span class="back-arrow">↩️</span>
        Назад
    </a>
    <br/>
    
    <?php include 'includes/category_block.php'; ?>

    <h1><?= htmlspecialchars($post['title'], ENT_QUOTES, 'UTF-8') ?></h1>

    <small class="category-tag">
        <?= date('d.m.Y', strtotime($post['created_at'])) ?>
        <?php if (!empty($post['category_name'])): ?>
            | коды из категории: <?= htmlspecialchars($post['category_name'], ENT_QUOTES, 'UTF-8') ?>
        <?php endif; ?>
    </small>
    <br/><br/>

    <?php if (!empty($post['intro'])): ?>
        <p><?= nl2br(htmlspecialchars($post['intro'], ENT_QUOTES, 'UTF-8')) ?></p>
    <?php endif; ?>

    <?php if (!empty($post['image'])): ?>
    <div class="content">
        <style>
            #heroo {
                height: 300px;
                width: 100%;
                overflow: hidden;
                position: relative;
                background: #f0f0f0;
                border-bottom: 1px solid #ccc;
            }
            #heroo img {
                width: 100%;
                height: auto;
                display: block;
                position: absolute;
                top: 0;
                left: 0;
            }
        </style>
        <div id="heroo">
            <img src="/uploads/<?= htmlspecialchars($post['image'], ENT_QUOTES, 'UTF-8') ?>" alt="<?= $meta_title ?>">
        </div>
    </div>
    <?php endif; ?>

    <?php
    $stmt = $pdo->prepare("SELECT * FROM code_blocks WHERE post_id = ? ORDER BY position ASC");
    $stmt->execute([$id]);
    $blocks = $stmt->fetchAll(PDO::FETCH_ASSOC);
    ?>

    <?php foreach ($blocks as $block): ?>
        <?php if ($block['type'] === 'heading'): ?>
            <h2><?= htmlspecialchars($block['content'], ENT_QUOTES, 'UTF-8') ?></h2>
        <?php elseif ($block['type'] === 'text'): ?>
            <p><?= nl2br(htmlspecialchars($block['content'], ENT_QUOTES, 'UTF-8')) ?></p>
        <?php elseif ($block['type'] === 'code'): ?>
            <pre><code><?= htmlspecialchars($block['content'], ENT_QUOTES, 'UTF-8') ?></code></pre>
        <?php elseif ($block['type'] === 'image'): ?>
            <img src="/uploads/<?= htmlspecialchars($block['content'], ENT_QUOTES, 'UTF-8') ?>" alt="Изображение" style="max-width: 100%; margin: 1em 0;">
        <?php elseif ($block['type'] === 'quote'): ?>
            <blockquote><?= nl2br(htmlspecialchars($block['content'], ENT_QUOTES, 'UTF-8')) ?></blockquote>
        <?php endif; ?>
    <?php endforeach; ?>

    <?php
    $tags = getCodePostTags($pdo, $id);
    if (!empty($tags)):
    ?>
        <div class="tags">
            Теги: 
            <?php foreach ($tags as $tag): ?>
                <a href="/tag/<?= htmlspecialchars($tag['slug'] ?? strtolower(preg_replace('/[^a-z0-9]+/ui', '-', $tag['name'])), ENT_QUOTES, 'UTF-8') ?>" class="tag">
                    #<?= htmlspecialchars($tag['name'], ENT_QUOTES, 'UTF-8') ?>
                </a>
            <?php endforeach; ?>
        </div>
    <?php endif; ?>

    <br/><hr><br/>
    
    <h3>Категории:</h3>
    <?php include 'includes/category_block.php'; ?>

    <!-- Секция комментариев -->
    <div class="comments-section" id="comments">
        <h3>Комментарии</h3>
        <?php
        $commentStmt = $pdo->prepare("SELECT * FROM comments WHERE post_id = ? AND post_type = 'code' ORDER BY created_at ASC");
        $commentStmt->execute([$id]);
        
        if ($commentStmt->rowCount() > 0):
            while ($comment = $commentStmt->fetch()):
        ?>
            <div class="comment-item">
                <span class="comment-author"><?= htmlspecialchars($comment['author'], ENT_QUOTES, 'UTF-8') ?></span>
                <span class="comment-date"><?= date('d.m.Y H:i', strtotime($comment['created_at'])) ?></span>
                <div class="comment-text"><?= nl2br(htmlspecialchars($comment['text'], ENT_QUOTES, 'UTF-8')) ?></div>
            </div>
        <?php 
            endwhile;
        else: 
        ?>
            <p class="no-comments">Пока нет комментариев. Будьте первым!</p>
        <?php endif; ?>
    </div>

    <!-- Форма добавления комментария -->
    <div class="cool-comment-form">
        <h3 class="form-title">Оставить комментарий</h3>
        <form method="POST" action="/comments/add_comment.php" class="comment-form">
            <input type="hidden" name="csrf_token" value="<?= $_SESSION['csrf_token'] ?>">
            <input type="hidden" name="post_type" value="code">
            <input type="hidden" name="post_id" value="<?= $id ?>">
            
            <div class="form-grid">
                <div class="form-group nickname-group">
                    <label class="input-label">Ваш ник:</label>
                    <input type="text" name="author" required class="cool-input"
                           placeholder="КрутойНик123" maxlength="30"
                           value="<?= htmlspecialchars($_SESSION['comment_author'] ?? '', ENT_QUOTES, 'UTF-8') ?>">
                </div>
                
                <div class="form-group captcha-group">
                    <?php
                    $a = rand(1, 10);
                    $b = rand(1, 10);
                    $_SESSION['captcha_answer'] = $a + $b;
                    ?>
                    <label class="input-label"><?= $a ?> + <?= $b ?> = ?</label>
                    <input type="number" name="captcha" required class="cool-input" placeholder="Ответ" style="width: 100px">
                </div>
                
                <div class="form-group comment-group">
                    <label class="input-label">Ваш комментарий:</label>
                    <textarea name="text" required class="cool-textarea"
                              placeholder="Оставьте комментарий..." maxlength="500"></textarea>
                </div>
            </div>
            
            <button type="submit" class="submit-btn">
                <span class="btn-icon">💬</span> Отправить
            </button>
        </form>
    </div>

    <p><a href="/">← Назад к списку</a></p>
</div>

<script>
document.addEventListener('DOMContentLoaded', function() {
    const commentForm = document.querySelector('.comment-form');
    if (commentForm) {
        commentForm.addEventListener('submit', async function(e) {
            e.preventDefault();
            const submitBtn = commentForm.querySelector('.submit-btn');
            const originalText = submitBtn.innerHTML;
            try {
                submitBtn.innerHTML = '<span class="btn-icon">⏳</span> Отправка...';
                submitBtn.disabled = true;
                const response = await fetch(commentForm.action, {
                    method: 'POST',
                    body: new FormData(commentForm)
                });
                const data = await response.json();
                if (data.success) {
                    const commentsSection = document.querySelector('.comments-section');
                    const noCommentsMsg = commentsSection.querySelector('.no-comments');
                    if (noCommentsMsg) noCommentsMsg.remove();
                    const newComment = document.createElement('div');
                    newComment.className = 'comment-item';
                    newComment.innerHTML = `
                        <span class="comment-author">${escapeHtml(data.comment.author)}</span>
                        <span class="comment-date">${escapeHtml(data.comment.date)}</span>
                        <div class="comment-text">${escapeHtml(data.comment.text)}</div>
                    `;
                    commentsSection.appendChild(newComment);
                    commentForm.reset();
                    alert('Комментарий успешно добавлен!');
                } else {
                    throw new Error(data.message || 'Ошибка при отправке');
                }
            } catch (error) {
                console.error('Error:', error);
                alert(error.message);
            } finally {
                submitBtn.innerHTML = originalText;
                submitBtn.disabled = false;
            }
        });
    }
});

function escapeHtml(str) {
    if (!str) return '';
    return str.replace(/[&<>]/g, function(m) {
        if (m === '&') return '&amp;';
        if (m === '<') return '&lt;';
        if (m === '>') return '&gt;';
        return m;
    });
}
</script>

<script>
const hero = document.getElementById('heroo');
const heroImg = hero ? hero.querySelector('img') : null;
if (heroImg) {
    let currentOffset = 0;
    let maxOffset = 0;
    let isReady = false;
    function initImage() {
        if (!heroImg.complete || !heroImg.naturalWidth) return;
        const heroHeight = hero.clientHeight;
        const heroWidth = hero.clientWidth;
        const imgWidth = heroImg.naturalWidth;
        const imgHeight = heroImg.naturalHeight;
        const scale = heroWidth / imgWidth;
        const scaledHeight = imgHeight * scale;
        heroImg.style.height = `${scaledHeight}px`;
        maxOffset = Math.max(0, scaledHeight - heroHeight);
        currentOffset = maxOffset / 2;
        heroImg.style.transform = `translateY(${-currentOffset}px)`;
        isReady = true;
    }
    initImage();
    if (!isReady) {
        heroImg.addEventListener('load', initImage);
        heroImg.addEventListener('error', () => console.error('Hero image failed to load'));
    }
    heroImg.addEventListener('wheel', (e) => {
        if (!isReady || maxOffset <= 0) return;
        e.preventDefault();
        const step = 50;
        currentOffset = Math.max(0, Math.min(maxOffset, currentOffset + (e.deltaY > 0 ? step : -step)));
        heroImg.style.transform = `translateY(${-currentOffset}px)`;
    }, { passive: false });
}
</script>

<?php include 'includes/callpack.php'; ?>
<?php include 'includes/footer.php'; ?>



Категории:

Категории

Комментарии

Пока нет комментариев. Будьте первым!

Оставить комментарий

← Назад к списку

Посетителей сегодня: 0
о блоге | карта блога

© Digital Specialist | Не являемся сотрудниками Google, Яндекса и NASA