Гид по технологиям

Как создать простой сайт на PHP: структура, шаблоны и полезные приёмы

9 min read Веб-разработка Обновлено 31 Dec 2025
Простой сайт на PHP: структура и приёмы
Простой сайт на PHP: структура и приёмы

Важно: кодовые примеры сохраняют поведение оригинального проекта. Убедитесь, что корневая папка веб‑сервера указывает на каталог site.

php логотип на тёмном фоне

Если вы получите базовое понимание того, как строить сайт на PHP, вы освоите включение файлов и генерацию вывода — самые простые способы кастомизировать веб‑страницу. Возможно, вы пока не знаете, с чего начать, или какие шаги предпринять для добавления новой функциональности. В этом руководстве я предлагаю компактную, понятную структуру проекта и описываю полезные PHP‑функции, которые приносят реальную пользу.

Что вы будете строить

Образец сайта (есть в репозитории GitHub) — простой сайт о птицах. Там несколько разделов, информационные страницы и главная страница. Главное не конечный дизайн, а подходы и идеи, которые вы сможете применить к своим проектам.

Скриншот главной страницы сайта о птицах

Если можно, скачайте репозиторий с GitHub и установите сайт локально, прежде чем продолжать — так вы сможете экспериментировать с кодом и видеть изменения сразу.

Краткое определение терминов

  • Markdown: лёгкий формат разметки текста, читаемый человеком и легко конвертируемый в HTML.
  • Шаблон (template): файл с общей HTML‑структурой, который повторно используют несколько страниц.
  • DOCROOT: корневой каталог веб‑сервера, откуда отдаются файлы сайта.

Общая структура сайта

Ключевые файлы и каталоги проекта:

composer.json
data/
funcs.php
md/
site/
  index.php
tpl/
  • Каждая страница представлена PHP‑скриптом в каталоге site. Это даёт небольшую избыточность, но упрощает логику и маршрутизацию. При настройке сервера укажите DOCROOT на каталог site.
  • Каталог md содержит исходники в формате Markdown для отдельных страниц.
  • Каталог tpl хранит шаблоны и файлы, определяющие общую HTML‑структуру, которую используют несколько страниц.
  • Основная PHP‑логика сосредоточена в funcs.php.

Связанные материалы: как настроить локальный стек WAMP/LAMP/Valet.

Как работает сайт — пошагово

Ниже разберём главные компоненты и объясним, как они взаимодействуют.

Bootstrap: зачем и как подключать

Bootstrap — фронтенд‑фреймворк с набором CSS и JS для быстрого создания адаптивного интерфейса. Можно хранить файлы локально, но чаще проще подключать их через CDN, чтобы сократить объём раздачи и воспользоваться кешем браузера.

Откройте файл tpl/head.php и вы увидите пример подключения:

Совет: для продакшна иногда лучше зафиксировать версию и хранить CSS на своём сервере, если политика безопасности запрещает внешние источники.

Базовое шаблонирование

Файл site/index.php — это домашняя страница. В начале он подключает funcs.php и шаблон TPL_DIR.”/home.php”. В funcs.php константа TPL_DIR определяется как абсолютный путь к каталогу tpl.

Посмотрите tpl/home.php: это самый внешний каркас HTML — она содержит doctype и HTML‑элемент и подключает head и body через include.



    
    

Шаблон для раздела birds использует другой body: tpl/birds/body.tpl. В нём другой макет с боковой панелью.

Важно: такой подход оставляет заголовки, меню и футер общими, уменьшая повторение кода.

Разбор Markdown в HTML

В composer.json подключена библиотека erusev/parsedown. Это библиотека для преобразования Markdown в HTML.

Пример функции show_content() в funcs.php:

function show_content() {
    $file = MD_DIR.PAGE.'.md';

    if (file_exists($file)) {
        $Parsedown = new Parsedown();
        echo $Parsedown->text(file_get_contents($file));
    } else if (function_exists("content")) {
        echo content();
    }
}

Логика простая: если существует Markdown‑файл для текущей страницы, Parsedown конвертирует его в HTML и выводит. Если файла нет, ищется функция content(), которую может определить конкретная страница для динамического вывода.

Преимущества такого подхода:

  • Авторство контента проще (Markdown читается лучше, чем HTML).
  • Лёгкость версионирования — просто коммитим .md в Git.
  • Быстрая разработка контента без админ‑панели.

Ограничения:

  • Markdown не покрывает все случаи, где нужен сложный динамический вывод.
  • Формат файлов должен быть согласован командой, иначе парсинг даст неконсистентный результат.

Загрузка и парсинг метаданных

Функция get_json в funcs.php читает JSON‑файл и возвращает ассоциативный массив:

function get_json($file) {
    $data_file = DATA_DIR."/".$file;

    if (!file_exists($data_file)) {
        return array();
    }

    if (($json = file_get_contents($data_file)) === false) {
        return array();
    }

    if (($out = json_decode($json, true)) === null) {
        return array();
    }

    return $out;
}

Такой код аккуратно оборачивает чтение/декодирование и возвращает пустой массив при ошибке. Для простых сайтов это часто удобнее, чем подключение СУБД.

На сайте есть два файла метаданных: data/titles.json и data/featured.json. Пример titles.json:

{
    "/": "Home",
    "/about": "About",
    "/birds": "Bird profiles",
    ...
}

Это позволяет хранить все заголовки в одном месте и использовать их в навигации, хлебных крошках и сайдбаре.

Функция page_title использует get_titles():

function page_title($page = PAGE) {
    $titles = get_titles();
    return array_key_exists($page, $titles) ? $titles[$page] : basename($page);
}

Хлебные крошки

Функция breadcrumbs() строит список заголовков для каждой части URL. Пример: для /birds/blue-tit она сформирует массив с заголовками для “/“, “/birds” и “/birds/blue-tit”.

function breadcrumbs() {
    $items = array();
    $titles = get_titles();
    $parts = explode("/", PAGE);
    $href = "";

    foreach ($parts as $part) {
        $href .= ($href == "/" ? "" : "/").$part;
        $items[$href] = $titles[$href];
    }
    ...
}

Хлебные крошки повышают удобство навигации и SEO, показывая иерархию страниц.

Страница с профилем птицы и фото в правой части

Получение информации о времени изменения контента

В футере (tpl/footer.php) выводится сообщение «Last updated» с помощью filemtime:

if (file_exists($file = MD_DIR.PAGE.'.md')) {
    echo 'Last updated: '.date('r', filemtime(MD_DIR.PAGE.'.md'));
}

Это простой способ получить дату последнего изменения содержимого. Минусы: если вы редактируете файл вне Git, timestamp изменится; если вы хотите больше контроля, храните дату отдельно в метаданных.

Извлечение данных с помощью регулярных выражений

Иногда нужно пересобирать данные из сырого Markdown, например — взять заголовок, изображение и первое предложение для списка новостей. В news/index.php парсятся файлы в md/news и регулярными выражениями извлекаются нужные части.

Пример извлечения заголовка (строка, начинающаяся с #):

if (preg_match("/^#\s+(.+)/", $contents, $matches)) {
    $title = $matches[1];
}

Внимание: регулярные выражения удобны, но требуют дисциплины в оформлении Markdown. Альтернативы — фронтматтер (YAML metadata в начале файла) или явные JSON‑данные.

Список новостей с фотографиями птиц

Выбор случайного контента

На странице /birds для разнообразия показывают случайное изображение. Это реализовано так:

function content() {
    $files = scandir(SITE_DIR."/img");
    $files = array_filter($files, function($file) { return $file[0] != '.'; });
    $file = $files[array_rand($files)];

    echo '

Birds

'; echo ''; }

Идея простая: поместите все нужные изображения в отдельный каталог, прочитайте список и выберите случайный файл.

Практические рекомендации и шаблоны принятия решений

Когда такой подход работает хорошо

  • Небольшие сайты с ограниченным количеством страниц.
  • Блоги и справочники, где контент управляется Markdown и версионируется в Git.
  • Проекты, где простота важнее гибкости админ‑панели.

Когда лучше выбрать другое решение

  • Если нужно сложное моделирование данных с отношениями, выбор в пользу СУБД и CMS (например, WordPress, Drupal) чаще оправдан.
  • Для больших проектов с множественными редакторами и правами доступа удобнее использовать CMS или headless CMS.

Альтернативные подходы

  • Статические генераторы сайтов (Jekyll, Hugo, Eleventy) — генерируют HTML на этапе сборки и идеально подходят для простых сайтов, где нет сервера и PHP.
  • Headless CMS + фронтенд (например, Strapi + React) — если нужен гибкий API и современный фронтенд.
  • Полноценная CMS (WordPress) — если нужна админка, плагины и развитая экосистема.

Модель мышления и эвристики при разработке

  • Разделяй вид и логику: шаблоны отвечают за HTML, funcs.php — за работу с данными.
  • Принцип единой ответственности: каждая функция делает одно действие.
  • Минимизируй состояние: храните конфигурацию в JSON или константах, а не в глобальных переменных.
  • Предпочитайте простоту и явность перед сложной магией автоматического поведения.

Безопасность и надёжность (харднинг)

  • Всегда проверяйте входные данные: используйте фильтры для GET/POST и экранирование при выводе.
  • Для вывода Markdown используйте безопасные опции Parsedown (или ParsedownExtra с безопасной конфигурацией). Не выводите сырой HTML из неподтверждённых источников.
  • Ограничьте доступ к каталогу md и data по правам файловой системы, если сервер отдаёт файлы напрямую.
  • Не доверяйте filemtime для важных аудитов; используйте метаданные в файлах, если нужен точный контроль.

Примечание: Этот раздел даёт общие рекомендации. Для продакшн‑сайта проведите полноценный аудит безопасности.

Практическая методология внедрения (мини‑SOP)

  1. Клонируйте репозиторий и установите зависимости Composer.
  2. Настройте DOCROOT на каталог site.
  3. Проверьте права доступа для каталогов md, data и img.
  4. Запустите локальный сервер и откройте главную страницу.
  5. Внесите тестовые изменения в md/home.md и проверьте show_content().
  6. Добавьте новую страницу — создайте site/newpage.php и md/newpage.md.
  7. Протестируйте хлебные крошки, заголовки и футер.
  8. Перенесите изменения в Git и задеплойте.

Ролевые чек‑листы

Разработчик:

  • Настроить среду разработки.
  • Провести unit‑тесты для функций в funcs.php.
  • Проверить обработку ошибок в get_json.

Девопс:

  • Настроить права файлов и владельцев.
  • Обеспечить резервное копирование md и data.
  • Настроить автоматический деплой (CI).

Контент‑менеджер:

  • Соблюдать формат Markdown.
  • Поддерживать единообразие frontmatter (если используется).
  • Проверять дату обновления и метаданные.

Тестовые сценарии и критерии приёмки

Критерии приёмки

  • Главная страница загружается (HTTP 200).
  • show_content выводит HTML для существующих .md файлов.
  • breadcrumbs строит корректную цепочку для вложенных страниц.
  • get_json возвращает массив для валидного JSON и пустой массив при ошибке.
  • Функция content на странице /birds выводит изображение из каталога img.

Тестовые кейсы

  • Удалить titles.json и проверить, что page_title возвращает basename.
  • Переименовать один .md файл и проверить вывод Last updated.
  • Создать некорректный JSON в data и убедиться, что сайт не падает.

Матричная таблица совместимости и миграция

  • Платформы: любой веб‑сервер с поддержкой PHP 7.4+; для безопасности и производительности рекомендуем PHP 8.
  • Зависимости: Composer для Parsedown.
  • Миграция на СУБД: перенести data/*.json в таблицы, заменить get_json вызовами к БД.

Частые ошибки и способы их устранения

  1. DOCROOT указывает не на site — решение: перепривязать корень виртуального хоста.
  2. Права файлов мешают чтению — проверить chmod/chown.
  3. Неправильный формат Markdown — задать стиль и добавить линтер для .md.
  4. Подключение внешних ресурсов блокируется CSP — обновить политику CSP или хранить ресурсы локально.

Краткая галерея edge‑кейсов

  • Если Parsedown конвертирует HTML внутри Markdown, и вы хотите его убрать, включите безопасный режим или предварительно фильтруйте содержимое.
  • Если вам нужно хранить структурированные данные (например, характеристики птицы), используйте JSON рядом с Markdown или frontmatter в начале файла.

Небольшая справка (глоссарий)

  • DOCROOT — корень веб‑сервера.
  • Parsedown — PHP‑библиотека для конвертации Markdown в HTML.
  • filemtime — функция PHP для получения времени последней модификации файла.

План развития и масштабирования

  1. Добавить CI, запускающий линтеры и unit‑тесты.
  2. Ввести frontmatter в Markdown для структурированных полей.
  3. При росте трафика перенести статические ресурсы на CDN и кешировать HTML.
  4. Если появится потребность — перенести метаданные в СУБД.

Примеры кода и сниппеты (шпаргалка)

Выбор случайного файла в каталоге img:

$files = scandir(SITE_DIR."/img");
$files = array_filter($files, function($file) { return $file[0] != '.'; });
$file = $files[array_rand($files)];

Безопасное чтение JSON:

$json = @file_get_contents($path);
$data = json_decode($json, true);
if (json_last_error() !== JSON_ERROR_NONE) {
    $data = array();
}

Decision tree: как выбрать архитектуру (Mermaid)

flowchart TD
  A[Небольшой сайт, статичный контент?] -->|да| B[Flat‑file + Markdown]
  A -->|нет| C[Нужна админ‑панель?]
  C -->|да| D[CMS 'WordPress/Drupal']
  C -->|нет| E[Headless CMS + frontend]
  B --> F[Использовать Parsedown + JSON]
  D --> G[Использовать существующие плагины]
  E --> H[API + SPA]

Примечания по локализации и GDPR

  • Если вы собираете персональные данные посетителей (комментарии, подписки), храните их в соответствии с законодательством и добавьте страницу политики конфиденциальности.
  • Для целевых стран учтите локальные требования к хранению данных и cookie‑баннеры.

Резюме

  • Простая архитектура с каталогом site и шаблонами tpl упрощает разработку.
  • Markdown + Parsedown ускоряют публикацию контента.
  • JSON‑файлы удобны для метаданных, но имеют ограничения при масштабировании.
  • Регулярные выражения дают гибкость, но требуют согласованного формата файлов.

Итог: этот подход позволяет быстро собирать и поддерживать небольшие веб‑проекты. Когда потребности вырастут, у вас уже будут понятные места для миграции на более сложные системы.

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Защита смарт‑телевизора от слежки
Безопасность

Защита смарт‑телевизора от слежки

Как включить тёмную тему в популярных приложениях
Мобильные приложения

Как включить тёмную тему в популярных приложениях

Резервное копирование в облако: дублирование
Облачное хранение

Резервное копирование в облако: дублирование

Pages для Mac — полное руководство по шаблонам
Обзор ПО

Pages для Mac — полное руководство по шаблонам

Как управлять доступом к местоположению на iPhone
Конфиденциальность

Как управлять доступом к местоположению на iPhone

Как освободить внутреннюю память Android
Android.

Как освободить внутреннюю память Android