Реализация публичной страницы PHP используя идентификатор

Раздел: Веб-разработка на PHP -> Страницы сайта

При разработке веб-приложений на PHP часто возникает задача отображения информации на отдельной странице в зависимости от переданного идентификатора (ID). Например, страница статьи, товара или пользователя. В данной статье рассматриваются различные способы реализации такой страницы, начиная от простейших и заканчивая профессиональными подходами с использованием маршрутизации и безопасности.

Основные подходы к созданию публичной страницы по ID

Наиболее эффективное решение: использование единого точки входа (front controller) с обработкой параметра ID через подготовленные запросы PDO. Этот подход обеспечивает безопасность, гибкость и поддержку.

Пример реализации:

// index.php - точка входа
require 'config.php';
$id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
if ($id === false || $id === null) {
    http_response_code(400);
    exit('Некорректный ID');
}
$stmt = $pdo->prepare('SELECT * FROM pages WHERE id = :id');
$stmt->execute(['id' => $id]);
$page = $stmt->fetch();
if (!$page) {
    http_response_code(404);
    exit('Страница не найдена');
}
echo '

' . htmlspecialchars($page['title']) . '

'; echo '
' . htmlspecialchars($page['content']) . '
';

Public php id (публичная страница php по id)

(Вывод: заголовок и содержимое страницы из базы данных, экранированные для защиты от XSS)

Пояснение: filter_input проверяет, что ID является целым числом. Используется подготовленный запрос для защиты от SQL-инъекций. htmlspecialchars предотвращает XSS-атаки. Код обрабатывает случаи отсутствия ID (400) и отсутствия записи (404).

Частые проблемы: неправильная настройка PDO (отсутствие исключений), забывают экранировать вывод, передача нечисловых ID. Решение: использовать режим ошибок PDO: $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);.

Как сделать чистые URL (ЧПУ) для страниц по ID?

Для создания ссылок вида /page/123 используется Apache mod_rewrite. В файле .htaccess правила преобразуют ЧПУ в параметры GET.

RewriteEngine On
RewriteRule ^page/(\d+)$ index.php?id=$1 [L,QSA]
// index.php
$id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
// ... остальная логика как в основном примере

Пояснение: правило RewriteRule захватывает числовую часть URL и передаёт её в index.php как параметр id. Флаг L останавливает обработку, QSA добавляет существующие параметры.

Проблемы: .htaccess не работает если модуль rewrite не включён, или сервер не разрешает .htaccess. Альтернатива: настроить в конфигурации виртуального хоста.

Как использовать готовый роутер для обработки ID?

Библиотека FastRoute позволяет гибко определять маршруты. Устанавливается через Composer.

// index.php
require 'vendor/autoload.php';
$dispatcher = FastRoute\simpleDispatcher(function(FastRoute\RouteCollector $r) {
    $r->addRoute('GET', '/page/{id:\d+}', 'pageHandler');
});
$httpMethod = $_SERVER['REQUEST_METHOD'];
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$routeInfo = $dispatcher->dispatch($httpMethod, $uri);
switch ($routeInfo[0]) {
    case FastRoute\Dispatcher::FOUND:
        $handler = $routeInfo[1];
        $vars = $routeInfo[2];
        $handler($vars['id']);
        break;
    case FastRoute\Dispatcher::NOT_FOUND:
        http_response_code(404);
        break;
}
function pageHandler($id) {
    // аналогичная логика с БД
}

Пояснение: роутер избавляет от ручного разбора URL, поддерживает REST и различные методы HTTP. Номер ID валидируется регулярным выражением \d+.

Возможные сложности: неверная установка Composer, конфликт версий, сложность отладки. Решение: пошаговая проверка автозагрузки и кэширования маршрутов.

Как обработать страницы разных типов (новости, товары) через один скрипт?

Можно добавить параметр типа: page.php?type=news&id=5 и использовать switch.

$type = filter_input(INPUT_GET, 'type', FILTER_SANITIZE_STRING);
$id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
if (!$id) { /* 400 */ }
switch ($type) {
    case 'news':
        $table = 'news';
        break;
    case 'product':
        $table = 'products';
        break;
    default:
        http_response_code(404);
        exit;
}
$stmt = $pdo->prepare("SELECT * FROM $table WHERE id = :id");
$stmt->execute(['id' => $id]);

Пояснение: использование switch с белым списком таблиц предотвращает SQL-инъекции. Нельзя подставлять переменную напрямую в запрос, но в данном случае таблица выбирается из ограниченного набора.

Проблема: возможен path traversal, если злоумышленник передаст 'news; DROP TABLE'. Хотя здесь switch защищает, но лучше использовать ассоциативный массив.

Далее представлены расширенные примеры реализации публичной страницы по ID с полным кодом и отображением результатов.

Пример 1: Полный скрипт с обработкой ошибок

Пример
<?php
// config.php
$dsn = 'mysql:host=localhost;dbname=test;charset=utf8mb4';
$user = 'root';
$pass = '';
$options = [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
];
try {
    $pdo = new PDO($dsn, $user, $pass, $options);
} catch (PDOException $e) {
    http_response_code(500);
    exit('Ошибка подключения к БД');
}

// index.php
require 'config.php';
$id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT, ['options' => ['min_range' => 1]]);
if ($id === false || $id === null) {
    http_response_code(400);
    exit('Неверный ID. Используйте положительное целое число.');
}

try {
    $stmt = $pdo->prepare('SELECT * FROM pages WHERE id = ?');
    $stmt->execute([$id]);
    $page = $stmt->fetch();
} catch (PDOException $e) {
    http_response_code(500);
    exit('Ошибка запроса к БД');
}

if (!$page) {
    http_response_code(404);
    exit('Страница не найдена');
}
?>
<!DOCTYPE html>
<html>
<head><title><?= htmlspecialchars($page['title']) ?></title></head>
<body>
<h1><?= htmlspecialchars($page['title']) ?></h1>
<div><?= nl2br(htmlspecialchars($page['content'])) ?></div>
</body>
</html>
При вызове index.php?id=1 (существующий ID) выводится HTML страница с заголовком и содержимым.
При вызове index.php?id=abc - возвращается 400 с сообщением об ошибке.
При вызове index.php?id=999 - возвращается 404 с сообщением.

Пример 2: Использование .htaccess для ЧПУ и обработка в index.php

Пример
# .htaccess в корне
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^page/(\d+)$ index.php?id=$1 [L,QSA]

# index.php (сокращённо)
$id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
if (!$id) {
    http_response_code(404);
    exit('Страница не найдена');
}
// ... запрос к БД
URL: /page/5  -> index.php?id=5 -> отображается страница с ID=5.
URL: /page/text -> не соответствует правилу (только цифры) и может привести к 404.

Пример 3: Использование FastRoute с разделением на контроллеры

Пример
// index.php
require 'vendor/autoload.php';
$dispatcher = FastRoute\simpleDispatcher(function(FastRoute\RouteCollector $r) {
    $r->addRoute('GET', '/', 'HomeController@index');
    $r->addRoute('GET', '/page/{id:\d+}', 'PageController@show');
});
$routeInfo = $dispatcher->dispatch($_SERVER['REQUEST_METHOD'], parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH));
switch ($routeInfo[0]) {
    case FastRoute\Dispatcher::FOUND:
        $handler = $routeInfo[1];
        $vars = $routeInfo[2];
        list($class, $method) = explode('@', $handler, 2);
        $controller = new $class($pdo);
        echo $controller->$method($vars['id']);
        break;
    case FastRoute\Dispatcher::NOT_FOUND:
        http_response_code(404);
        echo '404 Not Found';
        break;
}
При запросе /page/42 вызывается метод show контроллера PageController с параметром id=42. Возвращается сгенерированный HTML.

Пример 4: Обработка пагинации и дополнительных параметров

Пример
// URL: /page?category=news&id=123&page=2
$category = filter_input(INPUT_GET, 'category', FILTER_SANITIZE_STRING);
$id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
$pageNum = filter_input(INPUT_GET, 'page', FILTER_VALIDATE_INT, ['options' => ['default' => 1, 'min_range' => 1]]);
$allowedCategories = ['news', 'blog', 'article'];
if (!in_array($category, $allowedCategories)) {
    http_response_code(404);
    exit('Неверная категория');
}
// запрос с LIMIT и OFFSET, используя $pageNum
Тот же принцип, но с дополнительными параметрами для фильтрации и пагинации.

Публичная страница PHP по ID - comments

En
Public php id (php)