Динамические страницы в PHP: обработка идентификатора через GET-параметр
Динамические страницы на 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), и ссылки на другие страницы.