Создание PHP скриптов для динамических страниц
Основные подходы к генерации страниц с помощью PHP
Как организовать единый шаблон для всех страниц сайта?
Наиболее эффективное решение - использование include и require для разделения шапки, контента и подвала. Это позволяет переиспользовать общие блоки и менять их в одном месте.
<!-- layout.php -->
<!DOCTYPE html>
<html>
<head>
<title><?= $title ?></title>
</head>
<body>
<header><?php include 'header.php'; ?></header>
<main><?= $content ?></main>
<footer><?php include 'footer.php'; ?></footer>
</body>
</html>
<!-- page.php -->
<?php
$title = 'Главная';
ob_start();
?>
<h1>Добро пожаловать</h1>
<p>Основной контент страницы.</p>
<?php
$content = ob_get_clean();
include 'layout.php';
?>
Пояснение: в page.php запускается буферизация вывода, затем подключается layout.php, которому нужны переменные $title и $content. Это стандартный способ отделения представления от логики.
Типичная ошибка:
Необъявленные переменные внутри layout.php. Решение - проверять существование переменных через isset() или передавать их в глобальном массиве.
Как использовать буферизацию для динамических вставок?
Буферизация позволяет накапливать вывод и обрабатывать его перед отправкой. Применяется при необходимости модифицировать заголовки или подставлять контент в разных местах шаблона.
<?php
ob_start();
echo '<p>Этот блок будет помещён в основной контент</p>';
$content = ob_get_clean();
ob_start();
echo '<div class="sidebar">Боковая панель</div>';
$sidebar = ob_get_clean();
include 'index_layout.php';
?>
Проблема
Многократная вложенная буферизация может привести к путанице. Рекомендуется использовать один уровень или применять библиотеки.
Как реализовать простой роутинг и генерацию страниц?
Роутинг позволяет сопоставлять URL с конкретными файлами или функциями. Пример на PHP без фреймворка:
<?php
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
switch ($uri) {
case '/':
$page = 'home.php';
break;
case '/about':
$page = 'about.php';
break;
default:
http_response_code(404);
$page = '404.php';
break;
}
if (file_exists($page)) {
include $page;
} else {
echo 'Страница не найдена';
}
?>
Ошибка безопасности
Прямое использование $_SERVER['REQUEST_URI'] без фильтрации может привести к path traversal. Решение - строгое сопоставление по белому списку.
Как применить шаблонизатор (Twig) для генерации страниц?
Шаблонизаторы добавляют наследование, блоки, фильтры и безопасность. Установка через Composer: composer require twig/twig.
<?php
require_once 'vendor/autoload.php';
$loader = new \Twig\Loader\FilesystemLoader('templates');
$twig = new \Twig\Environment($loader);
echo $twig->render('index.html.twig', [
'title' => 'Главная',
'content' => '<p>Контент из Twig</p>'
]);
?>
<!-- templates/index.html.twig -->
{% extends "base.html.twig" %}
{% block content %}
<h1>{{ title }}</h1>
{{ content|raw }}
{% endblock %}
Проблема производительности
Кэширование шаблонов в Twig значительно ускоряет генерацию. Включите кэш в продакшене: new Twig\Environment($loader, ['cache' => 'cache']).
Как генерировать статические HTML страницы из PHP?
Для лучшей производительности и SEO можно сохранять сгенерированные страницы в статические файлы. Простой скрипт генерации:
<?php
$pages = ['index', 'about', 'contact'];
foreach ($pages as $page) {
$_GET['page'] = $page;
ob_start();
include 'dynamic.php';
$html = ob_get_clean();
file_put_contents("public/{$page}.html", $html);
}
echo 'Статические страницы сгенерированы';
?>
Проблема
При изменении шаблона нужно перегенерировать все страницы. Рекомендуется инвалидация кэша при каждом развёртывании.
Расширенные примеры PHP скриптов для генерации страниц
1. Многоуровневое наследование шаблонов с Twig
Создадим базовый шаблон base.html.twig с блоками для meta, стилей, контента, скриптов.
<!-- base.html.twig -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{% block title %}Сайт{% endblock %}</title>
{% block stylesheets %}{% endblock %}
</head>
<body>
<header>{% include 'header.twig' %}</header>
<main>{% block body %}{% endblock %}</main>
<footer>{% include 'footer.twig' %}</footer>
{% block javascripts %}{% endblock %}
</body>
</html>
<!-- page.html.twig -->
{% extends "base.html.twig" %}
{% block title %}Главная страница{% endblock %}
{% block stylesheets %}
<link rel="stylesheet" href="/css/home.css">
{% endblock %}
{% block body %}
<h1>Добро пожаловать!</h1>
<p>Это контент страницы.</p>
{% endblock %}
{% block javascripts %}
<script src="/js/home.js"></script>
{% endblock %}
<?php
// render.php
require_once 'vendor/autoload.php';
$loader = new \Twig\Loader\FilesystemLoader('templates');
$twig = new \Twig\Environment($loader, ['cache' => 'cache']);
echo $twig->render('page.html.twig');
?>
Результат: полностью собранная HTML страница с подключенными стилями и скриптами, заголовком и наследованием блоков.
2. Генерация страниц с динамическими данными из базы данных
Скрипт получает запись по ID и генерирует страницу новости.
<?php
// news.php?id=5
$id = (int)$_GET['id'] ?? 0;
// Подключение к БД (PDO)
$pdo = new PDO('mysql:host=localhost;dbname=site', 'user', 'pass');
$stmt = $pdo->prepare('SELECT title, content, created_at FROM news WHERE id = ?');
$stmt->execute([$id]);
$news = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$news) {
http_response_code(404);
include '404.php';
exit;
}
$title = htmlspecialchars($news['title']);
$content = nl2br(htmlspecialchars($news['content']));
$date = date('d.m.Y', strtotime($news['created_at']));
ob_start();
?>
<h1><?= $title ?></h1>
<time><?= $date ?></time>
<article><?= $content ?></article>
<?php
$body = ob_get_clean();
include 'layout.php';
?>
Результат: отрендеренная страница новости с заголовком, датой и контентом, вставленная в общий layout.
3. Создание простого генератора статических страниц с компиляцией
Скрипт строит sitemap и компилирует все страницы в HTML одним запуском.
<?php
// build.php
$pages = [
['slug' => 'index', 'title' => 'Главная', 'template' => 'home.twig'],
['slug' => 'about', 'title' => 'О компании', 'template' => 'about.twig'],
['slug' => 'services', 'title' => 'Услуги', 'template' => 'services.twig'],
];
$twig = // инициализация Twig с кэшем
foreach ($pages as $page) {
$html = $twig->render($page['template'], ['title' => $page['title']]);
file_put_contents("public/{$page['slug']}.html", $html);
echo "Создана {$page['slug']}.html\n";
}
// Генерация sitemap.xml
$sitemap = '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
$sitemap .= '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' . "\n";
foreach ($pages as $page) {
$sitemap .= " <url><loc>https://example.com/{$page['slug']}.html</loc></url>\n";
}
$sitemap .= '</urlset>';
file_put_contents('public/sitemap.xml', $sitemap);
echo "Sitemap обновлён.\n";
?>
Результат: в папке public появятся index.html, about.html, services.html и sitemap.xml. При каждом запуске скрипта страницы пересоздаются.
4. Использование PHP как шаблонного языка с изолированным контекстом
Функция, которая подключает файл-шаблон и передаёт переменные через extract, избегая глобального загрязнения.
<?php
function render_template(string $__file, array $__data): string {
extract($__data, EXTR_SKIP);
ob_start();
include $__file;
return ob_get_clean();
}
// Использование
$content = render_template('views/home.php', [
'title' => 'Дом',
'items' => ['a', 'b', 'c']
]);
echo $content;
?>
<!-- views/home.php -->
<h1><?= $title ?></h1>
<ul>
<?php foreach ($items as $item): ?>
<li><?= $item ?></li>
<?php endforeach; ?>
</ul>
Результат: HTML с заголовком и списком, без доступа к глобальным переменным.