Реализация просмотра статьи с помощью index.php

Раздел: Управление контентом -> Контент

Основное решение: получение статьи из базы данных через PDO

Наиболее эффективный и безопасный способ просмотра статьи в PHP - использование базы данных (MySQL) с расширением PDO и подготовленными запросами. Это обеспечивает защиту от SQL-инъекций и гибкость выборки данных.

Цель: отобразить полное содержимое статьи по её уникальному идентификатору (ID). Случаи использования: любой сайт или блог, где статьи хранятся в БД.

// index.php
$id = (int)$_GET['id'] ?? 0;
if (!$id) { http_response_code(400); exit('Неверный запрос'); }
$pdo = new PDO('mysql:host=localhost;dbname=blog;charset=utf8', 'user', 'pass');
$stmt = $pdo->prepare('SELECT title, content, date FROM articles WHERE id = ?');
$stmt->execute([$id]);
$article = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$article) { http_response_code(404); exit('Статья не найдена'); }
?>
<!DOCTYPE html>
<html><head><title><?= htmlspecialchars($article['title']) ?></title></head>
<body><h1><?= htmlspecialchars($article['title']) ?></h1>
<div><?= nl2br(htmlspecialchars($article['content'])) ?></div>
<p>Дата: <?= $article['date'] ?></p></body></html>

Article php page (статья на php)

Типичные проблемы:

  • Отсутствие проверки наличия GET-параметра id - ведёт к ошибкам. Решение: использовать оператор ?? с приведением к int.
  • Вывод данных без экранирования - XSS-уязвимости. Решение: всегда применять htmlspecialchars() с флагом ENT_QUOTES.
  • Ошибки соединения с БД - обрабатывать через try-catch и логирование.

Варианты решений

Как сделать просмотр статьи по символьному идентификатору (slug)?

Slug (человеко-понятный URL) улучшает SEO и читаемость адреса. В БД добавляется поле slug. Запрос выполняется по нему.

$slug = $_GET['slug'] ?? '';
$slug = trim($slug);
if (!preg_match('/^[a-z0-9-]+$/', $slug)) { http_response_code(400); exit; }
$stmt = $pdo->prepare('SELECT * FROM articles WHERE slug = ?');
$stmt->execute([$slug]);
$article = $stmt->fetch();

Index php view article (индекс php просмотр статьи)

Проблема: ненадёжная валидация slug - может быть пустым или содержать недопустимые символы. Решение: использовать регулярное выражение или готовый фильтр.

Как реализовать просмотр статьи при хранении в файловой системе?

Если контент хранится в текстовых файлах (например, .md или .txt), index.php читает файл по имени.

$filename = basename($_GET['file'] ?? '');
$path = __DIR__ . '/articles/' . $filename . '.txt';
if (!file_exists($path)) { http_response_code(404); exit('Файл не найден'); }
$content = file_get_contents($path);
$lines = explode("\n", $content, 2);
$title = $lines[0];
$body = $lines[1] ?? '';
Проблема: path traversal - злоумышленник может указать ../etc/passwd. Решение: использовать basename() и запретить слеши. Также проверять расширение.

Как использовать простую маршрутизацию без фреймворка?

Маршрутизация позволяет обрабатывать URL вида /article/42 или /article/my-slug. index.php анализирует REQUEST_URI.

$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$path = trim($uri, '/');
$parts = explode('/', $path);
if ($parts[0] === 'article' && isset($parts[1])) {
    $id = (int)$parts[1];
    // далее получение статьи из БД
}
Проблема: неправильное разбиение URL, если есть другие маршруты. Решение: использовать switch или массив маршрутов с регулярными выражениями.

Как отобразить статью с помощью шаблонизатора Twig?

Twig отделяет логику от представления. Устанавливается через Composer. В index.php подключается шаблон.

require 'vendor/autoload.php';
$loader = new \Twig\Loader\FilesystemLoader('templates');
$twig = new \Twig\Environment($loader);
echo $twig->render('article.html', ['article' => $article]);
Проблема: отсутствие автозагрузчика - классы не найдены. Решение: установить Twig через Composer с корректным autoload.

Расширенные примеры реализации просмотра статьи

1. Класс Article с обработкой ошибок

Пример
class Article {
    private PDO $pdo;
    public function __construct(PDO $pdo) { $this->pdo = $pdo; }
    
    public function getById(int $id): ?array {
        $stmt = $this->pdo->prepare('SELECT * FROM articles WHERE id = ?');
        $stmt->execute([$id]);
        $article = $stmt->fetch(PDO::FETCH_ASSOC);
        return $article ?: null;
    }
    
    public function getBySlug(string $slug): ?array {
        $stmt = $this->pdo->prepare('SELECT * FROM articles WHERE slug = ?');
        $stmt->execute([$slug]);
        return $stmt->fetch(PDO::FETCH_ASSOC) ?: null;
    }
}

// index.php
$article = new Article($pdo);
$data = $article->getById((int)($_GET['id'] ?? 0));
if (!$data) { http_response_code(404); exit; }
Результат: объект класса Article инкапсулирует логику получения данных, код становится более читаемым и тестируемым.

2. Отправка заголовка 404 при отсутствии статьи

Пример
if (!$article) {
    http_response_code(404);
    header('Location: /404.php'); // или вывод кастомной страницы
    exit;
}
Браузер получает статус 404, что важно для SEO и аналитики.

3. Использование подготовленных запросов с именованными параметрами

Пример
$stmt = $pdo->prepare('SELECT * FROM articles WHERE id = :id');
$stmt->execute([':id' => $id]);
$article = $stmt->fetch();
Удобно при множестве параметров - код легче читать.

4. Вывод статьи с Markdown (через Parsedown)

Пример
$parsedown = new Parsedown();
echo $parsedown->text(htmlspecialchars($article['content']));
Контент преобразуется из Markdown в HTML, при этом экранирование предотвращает XSS.

5. Кэширование результата запроса (файловый кэш)

Пример
$cacheFile = __DIR__ . '/cache/article_' . $id . '.html';
if (file_exists($cacheFile) && (time() - filemtime($cacheFile) < 3600)) {
    echo file_get_contents($cacheFile);
    exit;
}
ob_start();
// ... вывод статьи ...
$html = ob_get_clean();
file_put_contents($cacheFile, $html);
echo $html;
Снижает нагрузку на базу данных при частых запросах. Время жизни кэша настраивается.

6. Обработка ошибок PDO с try-catch

Пример
try {
    $pdo = new PDO(...);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $stmt = $pdo->prepare(...);
    $stmt->execute(...);
} catch (PDOException $e) {
    error_log('DB error: ' . $e->getMessage());
    http_response_code(500);
    exit('Внутренняя ошибка сервера');
}
Безопасный способ обработки ошибок без раскрытия деталей пользователю.

7. Использование ORM RedBeanPHP для простоты

Пример
require 'rb.php';
R::setup('mysql:host=localhost;dbname=blog', 'user', 'pass');
$article = R::load('articles', $id);
if ($article->id === 0) { /* не найдена */ }
Сокращает объём кода, но требует установки библиотеки. Подходит для небольших проектов.

Индекс PHP просмотр статьи - comments

En
Index php view article (php)