Структура веб приложений: работа с HTML и PHP
Основные способы интеграции PHP в HTML
Как организовать код, чтобы логика приложения не смешивалась с версткой?
Эффективным решением считается разделение логики и представления с помощью шаблонов. Подготавливаются данные в отдельном PHP-файле, а вывод выполняется через минимальные вставки PHP в HTML. Пример: контроллер подготавливает переменные, включает файл вида, затем подключает общий шаблон.
// controller.php
$title = 'Главная';
$items = ['Пункт 1', 'Пункт 2'];
ob_start();
include 'view.php';
$content = ob_get_clean();
include 'layout.php';
<!-- layout.php -->
<!DOCTYPE html>
<html>
<head><title><?= $title ?></title></head>
<body>
<header>Шапка сайта</header>
<main><?= $content ?></main>
<footer>Подвал</footer>
</body>
</html>
<!-- view.php -->
<h1><?= $title ?></h1>
<ul>
<?php foreach ($items as $item): ?>
<li><?= htmlspecialchars($item) ?></li>
<?php endforeach; ?>
</ul>
Проблемы: неэкранированный вывод приводит к XSS-уязвимостям. Решение: всегда применять htmlspecialchars() к данным, полученным от пользователя. Ошибка: указание неверного пути к файлу – вызовет фатальную ошибку. Для критических файлов рекомендуется require_once.
1. Прямое встраивание PHP в HTML с использованием коротких тегов
Как вывести переменную или выполнить условие внутри HTML-разметки без разделения на несколько файлов?
<?php $name = 'Мир'; ?>
<p>Привет, <?= $name ?>!</p>
<?php if ($time > 12): ?>
<p>Добрый день</p>
<?php endif; ?>
Проблема: при большом объеме PHP-кода читаемость страдает. Короткие теги <? могут быть отключены в конфигурации сервера. Рекомендуется использовать полную форму <?php и <?= (всегда доступен с PHP 5.4+).
2. Подключение повторяющихся частей через include/require
Как избежать копирования одного и того же HTML-кода (хедер, футер) на каждой странице?
<!DOCTYPE html>
<html>
<head><title>Сайт</title></head>
<body>
<?php require 'header.php'; ?>
<main>Основной контент</main>
<?php include 'footer.php'; ?>
</body>
</html>
Проблема: если переменная объявлена в header.php, она доступна во всем файле, что может привести к конфликтам имён. Решение: оборачивать подключаемые файлы в функции или классы. Ошибка: использование include для обязательных частей – при отсутствии файла скрипт продолжит работу с предупреждением. Для критических компонентов лучше require.
3. Использование шаблонизатора (Twig)
Как сделать синтаксис шаблонов более безопасным и удобным, особенно для больших проектов?
// controller.php
require_once 'vendor/autoload.php';
$loader = new \Twig\Loader\FilesystemLoader('templates');
$twig = new \Twig\Environment($loader);
echo $twig->render('page.html', [
'title' => 'Главная',
'items' => ['a', 'b']
]);
<!-- templates/page.html -->
<h1>{{ title }}</h1>
<ul>
{% for item in items %}
<li>{{ item|e }}</li>
{% endfor %}
</ul>
Проблема: требуется установка дополнительной библиотеки. Для простых страниц избыточно. Ошибка: забыть экранирование – Twig по умолчанию экранирует, но для небезопасных данных нужно указывать raw. Решение: придерживаться настроек экранирования по умолчанию.
4. MVC-подход с отдельными файлами контроллера, модели и представления
Как организовать код в крупном приложении, чтобы каждый компонент имел четкую ответственность?
// controller/UserController.php
class UserController {
public function index() {
$users = User::getAll();
include 'views/users/index.php';
}
}
<!-- views/users/index.php -->
<h1>Список пользователей</h1>
<?php foreach ($users as $user): ?>
<p><?= $user->name ?></p>
<?php endforeach; ?>
Проблема: требуется продуманная маршрутизация и автозагрузка классов. Без фреймворка сложно поддерживать. Ошибка: прямой вызов view без контроллера – нарушает архитектуру. Решение: использовать единую точку входа (front controller) и автозагрузку.
Расширенные примеры работы с HTML и PHP
<?php
// Пример использования буферизации вывода с несколькими блоками
$title = 'О нас';
$sidebar = '<p>Боковая панель</p>';
ob_start();
?>
<h1><?= $title ?></h1>
<p>Основной текст страницы.</p>
<?php
$content = ob_get_clean();
?>
<!DOCTYPE html>
<html>
<head><title><?= $title ?></title></head>
<body>
<div id="wrapper">
<div id="content"><?= $content ?></div>
<div id="sidebar"><?= $sidebar ?></div>
</div>
</body>
</html>
<!DOCTYPE html>
<html>
<head><title>О нас</title></head>
<body>
<div id="wrapper">
<div id="content">
<h1>О нас</h1>
<p>Основной текст страницы.</p>
</div>
<div id="sidebar"><p>Боковая панель</p></div>
</div>
</body>
</html>
<?php
// Использование heredoc для генерации HTML-строки
$name = 'Посетитель';
$html = <<<HTML
<div class="greeting">
<p>Здравствуйте, {$name}!</p>
<p>Сегодня <?= date('d.m.Y') ?>.</p>
</div>
HTML;
echo $html;
<div class="greeting"> <p>Здравствуйте, Посетитель!</p> <p>Сегодня 15.03.2025.</p> </div>
<?php
// Пример с Twig: расширение шаблона и блоки
// templates/base.html
?>
<!DOCTYPE html>
<html>
<head><title>{% block title %}Сайт{% endblock %}</title></head>
<body>
{% block content %}{% endblock %}
</body>
</html>
// templates/page.html
{% extends 'base.html' %}
{% block title %}О нас{% endblock %}
{% block content %}
<h1>О компании</h1>
<p>Текст.</p>
{% endblock %}
<!DOCTYPE html> <html> <head><title>О нас</title></head> <body> <h1>О компании</h1> <p>Текст.</p> </body> </html>
<?php
// Пример с автоэкранированием в Twig (raw filter)
$twig->render('page.html', ['script' => '<script>alert(1)</script>']);
// templates/page.html: {{ script }} // будет экранировано
// templates/page.html: {{ script|raw }} // выведет как есть, опасно
?>
При использовании {{ script }}:
<script>alert(1)</script>
При использовании {{ script|raw }}:
<script>alert(1)</script>