PHP с нуля: основы веб-разработки и практика

Курс поможет освоить PHP с самого начала: синтаксис, работу с данными, формами и базами данных. Вы научитесь писать серверную логику, подключать БД и создавать простые веб-приложения с правильной структурой и базовой безопасностью.

1. Подготовка среды и запуск первого PHP-скрипта

Подготовка среды и запуск первого PHP-скрипта

PHP — это язык программирования, который чаще всего выполняется на сервере и генерирует HTML (или JSON, файлы и многое другое) в ответ на запросы пользователя. Чтобы начать практику, вам нужно настроить среду разработки: редактор кода, установленный PHP и способ запускать скрипты.

В этой статье вы:

  • Поймёте, как PHP запускается в браузере и в терминале
  • Установите инструменты (несколько вариантов на выбор)
  • Запустите первый PHP-скрипт двумя способами
  • Как PHP «работает»: браузер и терминал

    Важно различать два сценария.

  • Запуск через веб-сервер: вы открываете страницу в браузере, запрос попадает на сервер, PHP выполняется и отдаёт результат.
  • Запуск через командную строку (CLI): вы запускаете PHP-файл напрямую командой php file.php, без браузера.
  • !Схема пути запроса: браузер → сервер → PHP → ответ

    Для старта достаточно уметь запускать PHP обоими способами: через CLI удобно проверять небольшие примеры, а через веб-сервер — делать веб-страницы.

    Что установить

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

  • Редактор кода: Visual Studio Code
  • PHP: либо отдельной установкой, либо в составе готового набора (XAMPP/MAMP/Laragon)
  • (Опционально) Composer — менеджер зависимостей, пригодится позже
  • Вариант A: самый простой старт через готовый набор (рекомендуется)

    Готовые наборы ставят PHP и веб-сервер автоматически.

  • Windows: XAMPP или Laragon
  • macOS: MAMP
  • Плюсы:

  • Быстро, почти без настройки
  • В комплекте есть Apache и PHP
  • Минусы:

  • Не всегда очевидно, где лежит php.ini и как устроены пути
  • Вариант B: установить только PHP и использовать встроенный сервер

    Если вы хотите более «чистую» настройку, можно поставить PHP отдельно и запускать встроенный веб-сервер.

    Официальные источники:

  • Документация и скачивание PHP: PHP: Downloads
  • О встроенном сервере: Built-in web server
  • Плюсы:

  • Минимум лишнего
  • Понятно, что именно вы запускаете
  • Минусы:

  • Иногда нужно вручную настроить переменную PATH (чтобы команда php работала в терминале)
  • Редактор кода

    Установите Visual Studio Code:

  • Visual Studio Code
  • Дальше (в следующих уроках) мы подключим расширения для PHP, но сейчас достаточно базовой установки.

    Проверка установки PHP

    После установки откройте терминал (PowerShell/Terminal) и выполните:

    Если PHP установлен и доступен, вы увидите версию, например PHP 8.x.x.

    Если команда не найдена:

  • Вы выбрали набор вроде XAMPP/MAMP/Laragon — убедитесь, что PHP установлен внутри набора, и запускайте через их терминал/настройки.
  • Или добавьте путь к папке с php в переменную окружения PATH (это зависит от ОС и способа установки).
  • Создаём проект и первый файл

  • Создайте папку проекта, например php-course.
  • Внутри создайте файл index.php.
  • Добавьте в index.php код:
  • Разберём, что здесь происходит:

  • <?php — начало PHP-кода внутри файла.
  • echo — команда, которая выводит текст.
  • Точка с запятой ; завершает инструкцию.
  • Способ 1: запуск в терминале (CLI)

    Перейдите в папку проекта и выполните:

    Ожидаемый результат:

  • В терминале появится текст Привет, PHP!.
  • Этот способ полезен для быстрых проверок, но для веб-разработки нам нужно уметь открывать результат в браузере.

    Способ 2: запуск в браузере через встроенный сервер PHP

    Внутри папки проекта выполните команду:

    После этого:

  • Откройте браузер.
  • Перейдите по адресу http://localhost:8000.
  • Вы должны увидеть Привет, PHP! в браузере.

    Чтобы остановить сервер, вернитесь в терминал и нажмите Ctrl + C.

    Почему просто открыть файл двойным кликом — не то же самое

    Если открыть index.php как обычный файл (например, file:///.../index.php), браузер не «выполнит PHP». Он либо покажет исходный текст, либо предложит скачать файл. PHP выполняется на стороне сервера, поэтому нужен веб-сервер (встроенный или Apache/Nginx).

    Если вы используете XAMPP/MAMP/Laragon

    Логика такая:

  • Вы запускаете Apache (через панель управления набора).
  • Кладёте проект в папку, из которой Apache раздаёт сайты (у набора она своя).
  • Открываете http://localhost/... в браузере.
  • Поскольку у разных наборов разные пути и интерфейсы, самое надёжное правило для новичка:

  • Ориентируйтесь на стартовую страницу набора (обычно доступна по http://localhost) и раздел про папку проекта (часто называется htdocs, www или похоже).
  • Частые ошибки и как их быстро диагностировать

  • Ошибка: php не найден
  • - PHP не установлен или не добавлен в PATH.
  • В браузере скачивается index.php вместо выполнения
  • - Вы открыли файл напрямую, а не через сервер, или сервер не настроен на обработку PHP.
  • Порт занят (например, 8000)
  • - Запустите так: php -S localhost:8001.
  • Опечатки и пропущенные ;
  • - PHP часто сообщает строку с ошибкой: внимательно читайте текст ошибки в терминале.

    Итог

    Вы подготовили среду и запустили первый PHP-скрипт:

  • В терминале командой php index.php
  • В браузере через встроенный сервер php -S localhost:8000
  • Дальше мы начнём изучать базовый синтаксис PHP: переменные, типы данных и простые операции — и будем закреплять всё практикой.

    2. Синтаксис PHP: переменные, типы, операторы, управление потоком

    Синтаксис PHP: переменные, типы, операторы, управление потоком

    В прошлой статье вы настроили среду и научились запускать PHP-скрипты: через CLI командой php index.php и через встроенный сервер php -S localhost:8000. Теперь пора освоить базовый синтаксис: как хранить данные в переменных, какие бывают типы, как выполнять операции и как управлять логикой программы.

    Эта статья построена так, чтобы вы могли сразу писать и запускать примеры в файле index.php.

    Как устроен PHP-файл

    Минимальный PHP-скрипт выглядит так:

    Важные правила:

  • PHP-код начинается с <?php
  • Каждая инструкция обычно заканчивается ;
  • Комментарии бывают однострочные // и многострочные / ... /
  • Пример с комментариями:

    Переменные

    Переменная — это имя, под которым вы храните значение (текст, число, список и так далее).

    Правила:

  • Переменная в PHP всегда начинается со знака name и name = "Аня";
  • name; php <?php

    name . "!"; php <?php

    name!"; php <?php

    name!'; php <?php

    price = 19.99; // float isAdmin = false; // bool nothing = null; // null php <?php

    value);

    Присваивание с операцией

    Сравнение

    В PHP важно различать сравнение по значению и сравнение по значению и типу.

  • == сравнивает значения и может приводить типы
  • === сравнивает и значение, и тип (строгое сравнение)
  • Пример:

    Другие операторы сравнения:

  • != и !== — не равно (нестрого / строго)
  • <, >, <=, >=
  • Официальная справка:

  • PHP Manual: Comparison Operators
  • Логические операторы

    Используются в условиях:

  • && — И
  • || — ИЛИ
  • ! — НЕ
  • Пример:

    Тернарный оператор

    Тернарный оператор — короткая форма if/else:

    Управление потоком выполнения

    Управление потоком — это конструкции, которые позволяют выполнять код по условию или повторять его.

    !Базовая логика ветвления if/else

    Условие if / else / elseif

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

    Частые ошибки новичков

  • Путают = и ==: = присваивает, == сравнивает
  • Используют == там, где нужна строгость: для предсказуемости чаще выбирайте ===
  • Забывают ; в конце инструкции
  • Пишут условия, которые всегда истинны из-за ошибок логики
  • Делают бесконечный цикл, забыв изменять счётчик
  • Итог

    Вы освоили базовые кирпичики языка:

  • Переменные и присваивание
  • Основные типы данных и отладочный вывод через var_dump()
  • Операторы: арифметические, сравнения, логические
  • Управление потоком: if/elseif/else, switch, циклы while, for, foreach`
  • Дальше эти конструкции станут основой для работы с массивами и функциями, а затем — для обработки данных из форм и запросов в веб-приложениях.

    3. Функции, массивы и работа со строками

    Функции, массивы и работа со строками

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

  • Массивы для хранения наборов данных
  • Функции для переиспользования кода
  • Строковые операции для обработки текста (что в веб-разработке встречается постоянно)
  • Все примеры можно запускать в одном файле index.php через CLI (php index.php) или во встроенном сервере (php -S localhost:8000).

    Массивы

    Массив в PHP — это структура данных, которая хранит набор значений. В PHP массивы бывают двух основных видов:

  • Индексные (ключи — числа 0, 1, 2, ...)
  • Ассоциативные (ключи — строки, например "name", "email")
  • Официальная справка: PHP Manual: Arrays

    Индексный массив

    Частые операции:

  • Получить количество элементов: count(names[] = "Глеб";
  • Важно понимать разницу:

  • isset(arr) вернёт true, если ключ есть, даже если значение null
  • Официальная справка: PHP Manual: isset, PHP Manual: array_key_exists

    Вложенные массивы

    Массивы могут содержать массивы — так часто хранят списки товаров в заказе.

    !Схема показывает, как выглядит заказ с вложенными данными

    php <?php

    pricesWithTax = array_map(function (p * 1.2; }, pricesWithTax);

    Здесь array text, text = text; }

    title, "Изучаем ");

    echo name = "Аня";

    echo "Привет, name!'; // Привет, firstName = "Аня"; firstName . " " . s) — длина в байтах

  • mb_strlen(text = "Привет";
  • echo strlen(text); // 6 php <?php

    email = trim(email, "@") === false) { echo "Некорректный email"; }

    echo str_replace("example.com", "site.ru", delimiter, glue, csv = "php,js,html"; csv);

    var_dump(parts); // php | js | html php <?php

    function calcOrderTotal(array total = 0;

    foreach (item) { item["price"] * total; }

    function buildOrderSummary(array lines = [];

    foreach (item) { item["title"] . ": " . item["price"]; line; }

    return implode("\n", items = [ ["title" => "Книга", "price" => 500, "qty" => 2], ["title" => "Чехол", "price" => 300, "qty" => 1], ];

    items); items);

    echo total . "\n"; `

    Что здесь важно:

  • $items — массив товаров, каждый товар — ассоциативный массив
  • calcOrderTotal возвращает число (итог)
  • buildOrderSummary возвращает строку из нескольких строк, используя implode
  • Частые ошибки и как их избегать

  • Путают echo и return: вывод не возвращает значение
  • Проверяют strpos(...) == false вместо strpos(...) === false
  • Используют strlen для русских строк и получают неожиданные значения
  • В массиве обращаются к ключу, которого нет, и получают предупреждения: используйте isset или array_key_exists
  • Слишком большой код пишут “в лоб”, не вынося повторяющиеся части в функции
  • Итог

    Теперь у вас есть базовый набор инструментов для большинства учебных задач:

  • Массивы: индексные, ассоциативные, вложенные
  • Перебор данных через foreach
  • Функции: параметры, значения по умолчанию, return, область видимости
  • Строковые операции: конкатенация, поиск, замена, explode и implode`
  • Дальше эти навыки станут основой для работы с данными из форм и запросов, а также для более структурного кода в небольших веб-приложениях.

    4. HTTP и веб-формы: GET/POST, валидация и обработка данных

    HTTP и веб-формы: GET/POST, валидация и обработка данных

    До этого вы писали PHP-скрипты, работали с переменными, условиями, массивами, функциями и строками. Следующий шаг к веб-разработке — научиться получать данные от пользователя через HTTP-запросы и обрабатывать их безопасно.

    В этой статье вы:

  • Поймёте, что такое HTTP-запрос и HTTP-ответ на практике
  • Разберёте различия GET и POST
  • Научитесь читать данные из _POST
  • Освоите базовую валидацию и санитизацию (очистку) входных данных
  • Соберёте мини-обработчик формы и сделаете корректный сценарий после отправки данных
  • Что такое HTTP простыми словами

    HTTP — это протокол, по которому клиент (браузер, мобильное приложение, curl) общается с сервером.

    Обычно цикл выглядит так:

  • Клиент отправляет запрос на URL.
  • Сервер выполняет код (в нашем случае PHP).
  • Сервер возвращает ответ.
  • !Диаграмма показывает из чего состоит запрос и ответ и где в этом месте работает PHP

    Из чего состоит HTTP-запрос

  • Метод: чаще всего GET или POST
  • URL: адрес ресурса
  • Заголовки: служебные параметры (например, тип данных)
  • Тело запроса: данные, которые отправляются на сервер (обычно в POST)
  • Из чего состоит HTTP-ответ

  • Код статуса: например, 200 (успех), 302 (редирект), 404 (не найдено)
  • Заголовки: например, куда перенаправить при редиректе
  • Тело ответа: HTML, JSON или просто текст
  • Почитать подробнее:

  • MDN: Обзор HTTP
  • GET и POST: в чём разница

    Оба метода доставляют данные на сервер, но делают это по-разному и для разных задач.

    | Критерий | GET | POST | |---|---|---| | Где лежат данные | В URL (query string) | В теле запроса (body) | | Видны ли данные в адресной строке | Да | Нет | | Типичные задачи | Поиск, фильтры, пагинация | Отправка форм, создание сущностей, авторизация | | Можно ли безопасно отправлять пароль | Нет | Тоже не гарантирует безопасность, но стандартно используют POST вместе с HTTPS | | Повторная отправка при обновлении страницы | Обычно безопаснее | Может предложить повторно отправить данные |

    Ключевая мысль для новичка:

  • GET — когда вы запрашиваете данные и хотите, чтобы URL можно было скопировать и повторить.
  • POST — когда вы отправляете данные и меняете состояние на сервере (создание заказа, регистрация).
  • Справка PHP по внешним данным:

  • PHP Manual: Variables from external sources
  • Как PHP получает данные: _POST, _GET — параметры из query string
  • _SERVER — информация о запросе и окружении (метод, путь, хост)
  • Документация:

  • PHP Manual: _POST
  • PHP Manual: _GET);
  • php <?php

    _GET["query"]) ? trim(level = isset(_GET["level"]) : "";

    if (query . "\n";

    echo "Уровень: " . (level : "любой") . "\n"; bash php -S localhost:8000 php <?php

    params);

    Мини-обработчик POST

    Создайте файл submit.php:

    Отправьте POST-запрос из терминала через curl:

    Если хотите сравнить с GET, можно выполнить:

    Валидация и санитизация: две разные задачи

    Когда пользователь отправляет данные, нельзя считать их корректными.

  • Валидация отвечает на вопрос: подходит ли значение под правила?
  • Санитизация отвечает на вопрос: как привести значение к безопасному и удобному виду для обработки?
  • Примеры:

  • Санитизация: trim убрал пробелы по краям
  • Валидация: проверка, что строка не пустая и длина не превышает лимит
  • Базовый шаблон обработки данных

  • Забрать данные из _POST.
  • Санитизировать: trim, приведение типов.
  • Провалидировать: обязательность, длина, формат, диапазон.
  • Если есть ошибки — вернуть понятный ответ.
  • Если всё ок — выполнить действие.
  • Практический пример: обработчик “регистрации” с ошибками

    Сделаем один файл register.php, который:

  • Принимает только POST
  • Проверяет email, name, age
  • Собирает ошибки в массив
  • Документация:

  • PHP Manual: header
  • Частые ошибки новичков при обработке данных

  • Доверяют входным данным без проверок
  • Не проверяют метод запроса и случайно обрабатывают GET как POST
  • Проверяют значения нестрого и получают неожиданные результаты
  • Не используют trim, из-за чего строка выглядит непустой, хотя там только пробелы
  • Делают редирект, но забывают exit, и скрипт продолжает выполняться
  • Итог

    Теперь вы умеете связывать PHP с реальными HTTP-запросами:

  • Понимаете разницу между GET и POST и где лежат данные
  • Читаете параметры из _POST
  • Проверяете метод через $_SERVER["REQUEST_METHOD"]
  • Делаете валидацию и санитизацию данных
  • Знаете, зачем нужен редирект после POST
  • Дальше эти навыки станут основой для работы с формами в браузере, обработкой файлов, а также для подключения базы данных и создания полноценной логики веб-приложений.

    5. Файлы и сессии: загрузки, cookies, авторизация

    Файлы и сессии: загрузки, cookies, авторизация

    В прошлой статье вы научились принимать данные через HTTP (GET/POST), валидировать их и делать редирект после POST. Теперь перейдём к тому, что почти всегда встречается в реальных веб-приложениях:

  • загрузка файлов (аватар, документ, фото)
  • cookies (хранение небольших данных на стороне браузера)
  • сессии (хранение состояния пользователя на стороне сервера)
  • простая авторизация на базе сессии
  • Ключевая идея: формы и файлы приходят с клиента, но состояние пользователя и доступ обычно контролируются на сервере через сессию.

    !Как cookies и сессии участвуют в каждом HTTP-запросе

    Загрузка файлов в PHP

    Как браузер отправляет файл

    Для загрузки файла HTML-форма должна:

  • иметь метод POST
  • иметь атрибут enctype="multipart/form-data"
  • содержать поле <input type="file" name="...">
  • В PHP загруженные файлы появляются не в _FILES.

    Документация: PHP Manual: Handling file uploads

    Минимальная форма загрузки

    Создайте файл upload_form.php:

    Для работы в браузере добавьте ниже закрывающего PHP-тега не нужно, поэтому сделаем отдельный файл, который будет только HTML мы не можем. Вместо этого сделаем форму прямо через echo.

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

    Обработчик загрузки

    Создайте файл upload.php:

    php <?php

    _COOKIE['theme']) ? theme; php <?php

    session_start();

    _SESSION['counter']) ? _SESSION['counter'];

    Документация: PHP Manual: session_destroy

    Защита от фиксации сессии

    После успешного входа полезно сменить идентификатор сессии:

    Документация: PHP Manual: session_regenerate_id

    Простая авторизация на сессиях

    Соберём минимальный рабочий сценарий:

  • login.php принимает email и пароль
  • если данные верны, записывает в _SERVER['REQUEST_METHOD'] !== 'POST') {
  • echo 'Ожидается POST'; exit; }

    _POST['email']) ? trim(password = isset(_POST['password'] : '';

    if (password === '') { echo 'Email и пароль обязательны'; exit; }

    foundUser = null; foreach (u) { if (email) { u; break; } }

    if (password, _SESSION['user'] = [ 'id' => foundUser['email'], 'name' => _SESSION['user'])) { header('Location: /login_form.php'); exit; }

    _SESSION['user'];

    echo 'Вы вошли как: ' . user['email'] . ')';

    echo "\n";

    echo '<a href="/logout.php">Выйти</a>'; php <?php

    session_start();

    _FILES пустой

  • Пытаются взять файл из _FILES
  • Доверяют _FILES, валидировать и сохранять их через move_uploaded_file
  • понимаете, что cookies живут в браузере и устанавливаются через setcookie
  • умеете включать сессии через session_start() и хранить состояние в $_SESSION
  • собрали простую авторизацию: логин, защищённая страница, логаут и редиректы
  • Дальше эти темы обычно развиваются в сторону хранения пользователей и файлов в базе данных, прав доступа и более аккуратной архитектуры (роутинг, контроллеры, шаблоны).

    6. Базы данных: SQL и PDO, CRUD-операции

    Базы данных: SQL и PDO, CRUD-операции

    До этого вы научились писать PHP-код, работать с массивами и функциями, принимать данные через HTTP (GET/POST), валидировать их, а также использовать cookies и сессии для «памяти» между запросами. Следующий логичный шаг — научиться хранить данные постоянно: не в переменных (они исчезают после запроса), а в базе данных.

    В этой статье вы:

  • Поймёте, зачем нужна база данных и что такое SQL
  • Освоите CRUD-операции: создание, чтение, обновление, удаление
  • Научитесь подключаться к базе через PDO
  • Научитесь выполнять запросы безопасно через подготовленные выражения
  • Соберёте минимальный CRUD-набор скриптов на PHP
  • !Как запрос проходит путь от клиента до базы данных и обратно

    Что такое база данных и почему без неё сложно

    Когда вы делаете веб-приложение, вам почти всегда нужно хранить:

  • пользователей (email, хеш пароля, роль)
  • товары и заказы
  • заметки, комментарии, сообщения
  • результаты форм
  • Если хранить это в массиве внутри PHP-файла, данные пропадут после перезапуска сервера или будут неудобны для поиска и изменений. Реляционная база данных решает это через таблицы и язык запросов SQL.

    SQL простыми словами

    SQL — язык, на котором вы говорите базе данных, что нужно сделать.

    Основные действия (CRUD):

  • Create: создать запись
  • Read: прочитать записи
  • Update: обновить запись
  • Delete: удалить запись
  • Этим действиям обычно соответствуют SQL-команды:

  • INSERT — Create
  • SELECT — Read
  • UPDATE — Update
  • DELETE — Delete
  • Справка по SQL (SQLite): SQLite SQL Syntax

    Какую базу выбрать на старте

    Для обучения удобно начать с SQLite:

  • база лежит в одном файле
  • не нужен отдельный сервер
  • отлично подходит для маленьких проектов и прототипов
  • Позже те же навыки переносятся на MySQL/MariaDB почти без изменений, потому что в PHP мы будем использовать PDO.

    Справка:

  • PHP Manual: PDO
  • PDO: единый интерфейс работы с базами

    PDO (PHP Data Objects) — это стандартный способ подключаться к разным базам данных и выполнять запросы.

    Почему в этом курсе выбираем PDO:

  • один и тот же подход для SQLite и MySQL
  • поддержка подготовленных выражений
  • удобная работа с выборками
  • Подготовка проекта для примеров

    Сделаем маленький учебный проект “Задачи”. Храним задачи в таблице tasks.

    Структура файлов:

  • db.php — подключение к базе
  • migrate.php — создание таблицы
  • create_task.php — создание задачи
  • list_tasks.php — список задач
  • update_task.php — обновление задачи
  • delete_task.php — удаление задачи
  • Все примеры ниже рассчитаны на запуск через встроенный сервер:

    И тестирование через curl.

    Подключение к SQLite через PDO

    Создайте файл db.php:

    Документация:

  • PHP Manual: PDO::setAttribute
  • PHP Manual: Errors and error handling
  • Если вы хотите MySQL вместо SQLite

    Подключение будет выглядеть так же, меняется только DSN:

    Документация:

  • PHP Manual: PDO::lastInsertId
  • Проверка через curl:

    Read: выводим список задач

    Создайте list_tasks.php:

    Документация:

  • PHP Manual: PDO::query
  • PHP Manual: PDOStatement::fetchAll
  • Проверка:

    Важное правило

    query удобно для запросов без пользовательских данных. Если есть ввод пользователя, почти всегда выбирайте prepare.

    Update: отмечаем задачу выполненной или меняем заголовок

    Сделаем обновление по id и двум полям: title и is_done. Создайте update_task.php:

    Проверка:

    Транзакции: когда нужно «либо всё, либо ничего»

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

  • списать деньги и создать заказ
  • обновить склад и записать историю
  • Для этого используют транзакции:

  • beginTransaction
  • выполняем несколько запросов
  • commit если всё хорошо
  • rollBack если случилась ошибка
  • Документация:

  • PHP Manual: Transactions and auto-commit
  • Мини-пример (файл transaction_demo.php):

    Типовые ошибки и правила безопасности

  • Не склеивайте SQL со строками ввода пользователя: используйте prepare и execute.
  • Валидируйте данные до запросов: как вы делали для _SESSION['user']), как в прошлой статье.
  • Полезная база по рискам:

  • OWASP: SQL Injection
  • Итог

    Теперь у вас есть практический фундамент для хранения данных:

  • вы понимаете, что такое SQL и какие запросы соответствуют CRUD
  • умеете подключаться к SQLite (или MySQL) через PDO
  • умеете безопасно выполнять запросы через prepare и execute
  • собрали минимальный CRUD-набор скриптов и протестировали их через curl
  • Следующий шаг в реальных приложениях обычно такой:

  • разнести код на слои (например, отдельно функции-репозитории для БД)
  • добавить нормальные страницы и формы (в рамках этого курса мы пока держим ответы простыми)
  • связать CRUD с авторизацией из сессии
  • 7. Структура проекта и безопасность: MVC-основы, ошибки, защита

    Структура проекта и безопасность: MVC-основы, ошибки, защита

    До этого в курсе вы писали отдельные PHP-скрипты, принимали данные через HTTP (GET/POST), работали с сессиями и сохраняли данные в базе через PDO. Следующий шаг, который делает код похожим на реальное веб-приложение — навести порядок в структуре проекта и добавить базовую безопасность как системное правило, а не как набор разрозненных проверок.

    В этой статье вы:

  • Поймёте, зачем нужен единый вход в приложение и структура папок
  • Освоите MVC на уровне практического смысла: кто за что отвечает
  • Научитесь централизованно обрабатывать ошибки и исключения
  • Соберёте базовый набор защит: SQL-инъекции, XSS, CSRF, безопасные сессии и загрузки
  • !Путь HTTP-запроса через MVC-слои

    Зачем нужна структура проекта

    Когда вы учитесь, удобно иметь файлы вроде register.php, upload.php, create_task.php. Но по мере роста приложения появляются проблемы:

  • трудно найти, где логика получения данных, где логика работы с БД, где вывод
  • повторяется код подключения к БД, запуска сессии, валидации
  • ошибки обрабатываются по-разному в каждом файле
  • безопасность держится на дисциплине: легко забыть одну проверку
  • Решение на старте — договориться о структуре и едином месте входа в приложение.

    Минимальная структура проекта

    Ниже — учебная структура без фреймворков, но уже похожая на продакшен.

    | Путь | Назначение | |---|---| | public/ | Публичная папка, доступная из браузера | | public/index.php | Единая точка входа (front controller) | | src/ | Код приложения (контроллеры, модели, сервисы) | | src/Controller/ | Контроллеры: принимают запрос, вызывают бизнес-логику | | src/Model/ | Модели или репозитории: работа с данными и БД | | src/View/ | Представления: формирование ответа | | storage/ | Файлы приложения: логи, загрузки (не в public) | | config/ | Конфигурация (DSN, режим окружения) |

    Ключевое правило:

  • в public/ должен быть минимум кода
  • загрузки и база данных не должны лежать в public/
  • MVC простыми словами

    MVC — это способ разделить код по ответственности.

  • Model (модель): отвечает за данные и операции с ними (часто: PDO-запросы, репозитории, валидация доменных правил)
  • View (представление): отвечает за формат ответа (HTML/JSON/текст)
  • Controller (контроллер): связывает запрос с нужными действиями, вызывает модель, выбирает представление
  • Важно: MVC не делает приложение автоматически безопасным, но помогает встроить безопасность в правильные места.

    Front controller и роутинг

    Front controller — это один файл (обычно public/index.php), который принимает все запросы и сам решает, какой код выполнить.

    Плюсы:

  • единая инициализация: сессии, конфиг, обработка ошибок
  • единые правила безопасности
  • проще масштабировать приложение
  • Роутинг на старте можно сделать очень простым: по пути и методу.

    Справка:

  • PHP Manual: parse_url
  • PHP Manual: method = path = parse_url(method === 'GET' && method === 'GET' && controller = new \App\Controller\TaskController();
  • echo method === 'POST' && controller = new \App\Controller\TaskController(); echo _POST); exit; }

    http_response_code(404); echo "404 Not Found\n"; } catch (Throwable e); echo "500 Server Error\n"; } php <?php

    declare(strict_types=1);

    // Простейшая автозагрузка для учебного проекта spl_autoload_register(function (string prefix = 'App\\'; if (strpos(prefix) !== 0) { return; }

    class, strlen(file = __DIR__ . '/' . str_replace('\\', '/', file)) { require pdo) { }

    public function all(): array { this->pdo->query('SELECT id, title, is_done, created_at FROM tasks ORDER BY id DESC'); return title): int { this->pdo->prepare( 'INSERT INTO tasks (title, is_done, created_at) VALUES (:title, 0, :created_at)' );

    title, ':created_at' => date('c'), ]);

    return (int)_POST

  • репозиторий всегда использует prepare для данных пользователя
  • Справка:

  • PHP Manual: PDO::prepare
  • PHP Manual: PDO::query
  • Подключение к БД (как отдельная функция)

    Файл src/db.php:

    Контроллер задач (Controller)

    Файл src/Controller/TaskController.php:

    Так у вас появляются понятные границы:

  • контроллер работает с HTTP-входом
  • репозиторий работает с БД
  • public/index.php отвечает за маршрутизацию и обработку ошибок
  • Ошибки и исключения: как делать правильно

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

    Режим разработки и режим продакшена

    В разработке:

  • display_errors = 1
  • error_reporting(E_ALL)
  • В продакшене:

  • display_errors = 0
  • ошибки пишутся в лог
  • пользователю показывается нейтральное сообщение
  • Почему нельзя показывать ошибки в продакшене:

  • сообщения могут раскрыть пути на сервере, структуру БД, куски кода
  • это помогает атакующим
  • Справка:

  • PHP Manual: Error Reporting
  • PHP Manual: error_log
  • Централизованный try/catch

    Идея простая:

  • в public/index.php обернуть выполнение маршрута в try/catch
  • в catch логировать исключение
  • отдавать 500
  • Это лучше, чем ловить ошибки в каждом контроллере.

    Безопасность: базовый набор защит

    Безопасность удобно воспринимать как слои. Если один слой ошибся, другой не даёт приложению упасть полностью.

    Входные данные: не доверяйте ничему

    Источники ввода:

  • _POST
  • _FILES
  • часть URL (REQUEST_URI)
  • Правило:

  • санитизация и валидация делаются на границе контроллера
  • в модельный слой должны попадать уже проверенные значения
  • SQL-инъекции: только prepare

    Вы уже делали это в PDO-уроке, здесь просто закрепим как правило структуры:

  • контроллер получает s): string
  • { return htmlspecialchars(_SESSION
  • требовать токен в каждом POST-запросе, который меняет состояние
  • Пример генерации токена:

    Пример проверки в контроллере:

    Справка:

  • PHP Manual: random_bytes
  • PHP Manual: hash_equals
  • Сессии: безопасная авторизация как правило проекта

    Из прошлой статьи вы уже знаете основу:

  • session_start() перед использованием _SESSION['user'])) {
  • http_response_code(401); echo "Нужно войти\n"; exit; }

    return (array)_POST | Controller | create(array s) при выводе | | CSRF | Controller или Middleware-функция | проверка csrf_token | | Авторизация | Middleware-функция | requireAuth() | | Ошибки и логирование | Front controller | try/catch + error_log |

    Итог

    Вы перешли от набора отдельных скриптов к каркасу приложения:

  • единая точка входа public/index.php и простой роутинг
  • понятные роли MVC: контроллер, модель (репозиторий), представление
  • централизованная обработка ошибок и логирование
  • базовый набор защит, встроенный в структуру: prepare для SQL, экранирование вывода, CSRF-токены, безопасные сессии, хранение загрузок вне public`
  • Дальше такую структуру проще расширять: добавлять новые сущности, формы, страницы, JSON-API, а также постепенно улучшать архитектуру (сервисы, middleware, шаблонизация, Composer).