↩️ Назад

Категории

Главная страница блога на php

08.04.2026

🗺️ Маршрутизация (роутинг)

Функция Канонический редирект basename($_SERVER['SCRIPT_NAME']) === 'index.php'

301 редирект с /index.php на / для SEO и чистоты URL.

Функция 404 обработчик if ($request_path !== '') { include '404.php'; exit; }

Любой непустой путь (кроме корня) вызывает страницу 404.

🔍 Поиск

GET /?q=текст

Поиск по title, preview_text, content в таблице articles и по title, intro в code_posts.
🔒 Безопасность: htmlspecialchars() + подготовленные запросы PDO.

📄 Пагинация

GET ?page=N

По 10 статей на страницу + 6 код-постов.
Лимиты привязаны через bindValue(PDO::PARAM_INT) — защита от инъекций.

🗂️ Основные таблицы БД

ТаблицаНазначение
articlesСтатьи блога (id, title, preview_text, content, image, category_id, created_at)
code_postsПосты с кодом/примерами (id, title, intro, image, category_id, created_at)
categoriesКатегории (id, name)

🔐 Безопасность (аудит)

🚀 Быстрый старт (для развёртывания)

  1. Импортировать SQL-дамп (пока не выкладывал, если надо пишите в коментах)
  2. Настроить includes/db.php: new PDO("mysql:host=localhost;dbname=...", "user", "pass")
  3. Права на /uploads — 755, запретить выполнение PHP через .htaccess

Код главной страницы блога

mazzick@iot-things:~$ sudo cat /var/www/blog/public_html/index.php
<?php


// === SEO: редирект с /index.php на / ===
if (basename($_SERVER['SCRIPT_NAME']) === 'index.php'
    && parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) === '/index.php') {
    header('HTTP/1.1 301 Moved Permanently');
    header('Location: /');
    exit;
}
// ====================================

// Получаем запрошенный путь (без query string)
$request_uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$request_path = trim($request_uri, '/');

// Любой не-пустой путь — 404
if ($request_path !== '') {
    http_response_code(404);
    include '404.php';
    exit;
}


session_start();
require 'includes/db.php';
$search_query = trim($_GET['q'] ?? '');
$is_search = !empty($search_query);


// Настройки пагинации
$articles_per_page = 10; // сколько статей на одной странице
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
$page = max(1, $page); // минимум — первая страница
$offset = ($page - 1) * $articles_per_page;

// Подсчёт общего количества статей
$total_stmt = $pdo->query("SELECT COUNT(*) FROM articles");
$total_articles = $total_stmt->fetchColumn();
$total_pages = ceil($total_articles / $articles_per_page);

// Основной запрос с пагинацией
if ($is_search) {
    $search_sql = " AND (a.title LIKE :search OR a.preview_text LIKE :search OR a.content LIKE :search)";
} else {
    $search_sql = "";
}

$stmt = $pdo->prepare("SELECT a.id, a.title, a.preview_text, a.image, a.created_at, c.name as category
                       FROM articles a
                       LEFT JOIN categories c ON a.category_id = c.id
                       WHERE 1=1 $search_sql
                       ORDER BY a.created_at DESC
                       LIMIT :limit OFFSET :offset");

// Привязываем limit/offset ВСЕГДА
$stmt->bindValue(':limit', $articles_per_page, PDO::PARAM_INT);
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);

// Привязываем search ТОЛЬКО если нужно
if ($is_search) {
    $stmt->bindValue(':search', '%' . $search_query . '%', PDO::PARAM_STR);
}

$stmt->execute();
?>


<?php include 'includes/header.php'; ?>

 <meta name="viewport" content="width=device-width, initial-scale=1.0">

  <!-- Ключевые мета-теги -->
  <title>IoTProf Blog — Публикации о IoT, промышленной автоматизации и IT</title>
  <meta name="description" content="Технический блог о промышленном IoT, автоматизации, Linux и сетевой инфраструктуре. Практические руководства, разборы оборудования и кейсы.">
  <link rel="canonical" href="https://blog.iotprof.ru" />
<meta name="robots" content="index, follow">
  <!-- OpenGraph (для соцсетей) -->
  <meta property="og:title" content="IoTProf Blog — Публикации о IoT и автоматизации">
  <meta property="og:description" content="Технический блог о промышленном IoT, Linux и сетевых решениях.">
  <meta property="og:url" content="https://blog.iotprof.ru/">
  <meta property="og:type" content="website">

  <link rel="stylesheet" href="/css/style.css">
  <link rel="stylesheet" href="/css/callback.css">

</head>
<body>


<div class="it-logo">
  <div class="it-abbr">iOt</div>
 <div class="it-blog">blog</div>
  <div class="it-slogan">там, где технологии думают за нас</div>
</div>

<div class="container">

<h1>Техноблог pro it и iot</h1>


<!-- ТЕСТОВАЯ ФОРМА -->
<form method="GET" action="/" style="display: flex; gap: 8px; margin: 10px 0; width: 100%;">
    <input type="text" name="q" value="<?= htmlspecialchars($_GET['q'] ?? '') ?>"
           placeholder="Поиск по блогу..." style="width: 70%;">
    <input type="submit" value="🔍 Поиск" style="width: 30%;">
</form>

<?php include 'includes/category_block.php'; ?>




<?php if ($is_search): ?>
    <h2>🔍 Результаты поиска по «<?= htmlspecialchars($search_query) ?>»</h2>
<?php else: ?>
    <h2>📜 Последние статьи</h2>
<?php endif; ?>

        <section class="posts-section">

            <div class="posts-grid">

<?php
$counter = 0;
while ($row = $stmt->fetch()):
$counter++;
?>

<article class="post-card article-card"> <!-- Убрали $image_position_class -->
 <?php if ($row['image']): ?>
                  <img src="/uploads/<?= htmlspecialchars($row['image']) ?>" alt="<?= htmlspecialchars($row['title']) ?>" class="post-image">
           <?php endif; ?>



    <div class="post-content">

 <span class="date_cat_article"><?= $row['category'] ?: 'Без категории' ?> | <?= date('Y-m-d', strtotime($row['created_at'])) ?></span>

<h3><a href="article.php?id=<?= $row['id'] ?>"><?= htmlspecialchars($row['title']) ?></a></h3>

            <p><?= nl2br(htmlspecialchars($row['preview_text'])) ?></p>
    </div>
</article>
<?php endwhile; ?>
                          </div>
        </section>


<!-- ============ БЛОК ПОСЛЕДНИХ КОДОВ С ПАГИНАЦИЕЙ ============ -->
<?php
// Настройки пагинации для кодов
$codes_per_page = 6;
$codes_offset = ($page - 1) * $codes_per_page;

if ($is_search) {
    $search_sql_codes = " AND (cp.title LIKE :search OR cp.intro LIKE :search)";
} else {
    $search_sql_codes = "";
}

$codes_stmt = $pdo->prepare("
    SELECT cp.id, cp.title, cp.intro, cp.image, cp.created_at, c.name as category_name
    FROM code_posts cp
    LEFT JOIN categories c ON cp.category_id = c.id
    WHERE 1=1 $search_sql_codes
    ORDER BY cp.created_at DESC
    LIMIT :limit OFFSET :offset
");

$codes_stmt->bindValue(':limit', $codes_per_page, PDO::PARAM_INT);
$codes_stmt->bindValue(':offset', $codes_offset, PDO::PARAM_INT);

if ($is_search) {
    $codes_stmt->bindValue(':search', '%' . $search_query . '%', PDO::PARAM_STR);
}

$codes_stmt->execute();
?>

<?php if ($is_search): ?>
    <h3>Код-посты</h3>
<?php else: ?>
    <h2>⚡ Последние код-посты</h2>
<?php endif; ?>



<section class="posts-section">
    <div class="posts-grid">
        <?php while ($code = $codes_stmt->fetch()): ?>
        <article class="post-card code-card">
            <?php if ($code['image']): ?>
                <img src="/uploads/<?= htmlspecialchars($code['image']) ?>" alt="<?= htmlspecialchars($code['title']) ?>" class="post-image">
            <?php endif; ?>

            <div class="post-content">
                <span class="category-tag">
                    <?= $code['category_name'] ?: 'Без категории' ?> |
                    <?= date('Y-m-d', strtotime($code['created_at'])) ?>
                </span>
                <h3><a href="code_post.php?id=<?= $code['id'] ?>"><?= htmlspecialchars($code['title']) ?></a></h3>
                <?php if (!empty($code['intro'])): ?>
                    <p><?= nl2br(htmlspecialchars($code['intro'])) ?></p>
                <?php endif; ?>
            </div>
        </article>
        <?php endwhile; ?>
    </div>
</section>
<!-- ============ КОНЕЦ БЛОКА КОДОВ ============ -->


<div class="pagination">
    <?php if ($page > 1): ?>
        <a href="?page=<?= $page - 1 ?>" class="btn">← Назад</a>
    <?php endif; ?>

    <span>Страница <?= $page ?> из <?= $total_pages ?></span>

    <?php if ($page < $total_pages): ?>
        <a href="?page=<?= $page + 1 ?>" class="btn">Вперёд →</a>
    <?php endif; ?>
</div>


<div>












</div>





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

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



Категории:

Категории

Комментарии

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

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

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

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

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