Динамические страницы в PHP: обработка идентификатора через GET-параметр

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

Динамические страницы на PHP: обработка параметра page

Динамические страницы позволяют отображать разный контент на основе переданных параметров. В типичном сценарии URL вида index.php?page=3 указывает, какую страницу показать. Разберём основные подходы к реализации.

Как организовать загрузку контента по идентификатору page без использования фреймворков?

Самый прямой способ - применить конструкцию match или switch в файле index.php. Параметр $_GET['page'] определяет, какой файл подключить.


<?php
$page = $_GET['page'] ?? '1';
$allowedPages = ['1','2','3','4'];
if (!in_array($page, $allowedPages)) {
    http_response_code(404);
    $page = '404';
}
$content = match($page) {
    '1' => 'pages/home.php',
    '2' => 'pages/about.php',
    '3' => 'pages/services.php',
    '4' => 'pages/contact.php',
    default => 'pages/404.php'
};
include $content;
?>

Index php page id 3 (динамические страницы на php)

В этом примере используется белый список $allowedPages для предотвращения path traversal. Если идентификатор не найден, возвращается 404.

Типичная ошибка:

Прямое включение имени файла из GET-параметра без фильтрации открывает уязвимость Local File Inclusion (LFI). Решение - всегда проверять значение по разрешённому набору.

Как реализовать чистые URL без query-параметров (например, /page/3)?

Используется фронт-контроллер в сочетании с mod_rewrite. В корне размещается .htaccess, перенаправляющий все запросы на index.php.


RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?page=$1 [L,QSA]

В index.php маршрут разбирается через $_GET['page'], где значение может быть, например, 'page/3'. Дополнительно можно использовать регулярные выражения для извлечения id.


$uri = trim($_GET['page'] ?? '', '/');
$parts = explode('/', $uri);
// $parts[0] = 'page', $parts[1] = '3'

Проблема:

Необходимо корректно обрабатывать корневой URL и страницы с несколькими сегментами. Решение - выделить контроллер и действие, либо использовать готовый роутер.

Как динамически формировать страницы на основе данных из базы данных?

Вместо статического набора файлов контент хранится в таблице pages. index.php запрашивает запись по id.


$id = (int)($_GET['page'] ?? 0);
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
$stmt = $pdo->prepare('SELECT title, body FROM pages WHERE id = :id');
$stmt->execute(['id' => $id]);
$pageData = $stmt->fetch();
if (!$pageData) {
    http_response_code(404);
    echo 'Страница не найдена';
    exit;
}
echo '<h1>' . htmlspecialchars($pageData['title']) . '</h1>';
echo '<div>' . $pageData['body'] . '</div>';

Ошибка:

Небезопасное отображение сырого HTML из БД может привести к XSS. Решение - использовать htmlspecialchars для заголовков и, если нужен HTML в теле, применять очистку через библиотеку (HTMLPurifier).

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

Библиотека Twig отделяет логику от представления. После установки через Composer создаются шаблоны .twig.


require_once 'vendor/autoload.php';
$loader = new \Twig\Loader\FilesystemLoader('templates');
$twig = new \Twig\Environment($loader);

$pageId = (int)($_GET['page'] ?? 1);
$context = ['pageId' => $pageId, 'title' => 'Страница ' . $pageId];
echo $twig->render('page.twig', $context);

Шаблон templates/page.twig:

<h1>{{ title }}</h1><p>Контент для страницы {{ pageId }}</p>

Сложность:

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

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

Как создать защищённый роутер с несколькими параметрами?

Пример кода (index.php - фронт-контроллер с белым списком маршрутов):

Пример

<?php
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$uri = rtrim($uri, '/');

$routes = [
    '/' => 'controllers/home.php',
    '/page/3' => 'controllers/page.php',
    '/about' => 'controllers/about.php',
];

if (array_key_exists($uri, $routes)) {
    include $routes[$uri];
} else {
    http_response_code(404);
    include 'controllers/404.php';
}

Результат:

При запросе /page/3 загружается controllers/page.php. При несуществующем URI - 404.

Как передавать динамический id через URL вида /page/3?

Используйте регулярное выражение для извлечения id из маршрута.

Пример

$uri = trim(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH), '/');
if (preg_match('#^page/(\d+)$#', $uri, $matches)) {
    $id = (int)$matches[1];
    // подключение контроллера с id
    include 'controllers/page.php';
} else {
    http_response_code(404);
}

Как кешировать редко изменяемые динамические страницы?

Используйте генерацию статических HTML-файлов при первом запросе.

Пример

$id = (int)($_GET['page'] ?? 0);
$cacheFile = 'cache/page_' . $id . '.html';
if (file_exists($cacheFile) && (time() - filemtime($cacheFile) < 3600)) {
    readfile($cacheFile);
    exit;
}
ob_start();
// генерация контента
$content = '<h1>Page ' . $id . '</h1>';
echo $content;
$html = ob_get_clean();
file_put_contents($cacheFile, $html);
echo $html;

Результат:

Повторные запросы в течение часа отдают статический файл, снижая нагрузку на сервер.

Как обрабатывать страницы с JSON API для SPA?

index.php может возвращать JSON вместо HTML, если заголовок Accept содержит application/json.

Пример

$accept = $_SERVER['HTTP_ACCEPT'] ?? '';
if (strpos($accept, 'application/json') !== false) {
    header('Content-Type: application/json');
    $data = ['id' => $pageId, 'content' => 'Текст страницы'];
    echo json_encode($data);
    exit;
}
// иначе HTML

Результат:

Запрос с заголовком Accept: application/json получит JSON, браузерный запрос - HTML.

Как добавить поддержку постраничной навигации (pagination)?

Параметр page может обозначать номер страницы списка.

Пример

$pageNum = (int)($_GET['page'] ?? 1);
$perPage = 10;
$offset = ($pageNum - 1) * $perPage;
$stmt = $pdo->prepare('SELECT * FROM articles LIMIT :limit OFFSET :offset');
$stmt->bindValue('limit', $perPage, PDO::PARAM_INT);
$stmt->bindValue('offset', $offset, PDO::PARAM_INT);
$stmt->execute();
// вывод статей
$totalRows = $pdo->query('SELECT COUNT(*) FROM articles')->fetchColumn();
$totalPages = ceil($totalRows / $perPage);
for ($i = 1; $i <= $totalPages; $i++) {
    echo '<a href="?page=' . $i . '">' . $i . '</a> ';
}

Результат:

URL ?page=3 выводит статьи с 21 по 30 (если perPage=10), и ссылки на другие страницы.

Динамические страницы на PHP - comments

En
Index php page id 3 (php)