Этот документ описывает, как обрабатываются HTTP-запросы в XC_VM, охватывая полный жизненный цикл от первоначального ввода до маршрутизации и отправки. В зависимости от типа запроса существует несколько путей выполнения.
---
## Обзор
Уровень HTTP построен из этих основных компонентов:
|Компонент|Файл|Роль|
| --- | --- | --- |
| `RequestGuard` | `src/Core/Http/RequestGuard.php` |Безопасность перед маршрутизацией: защита от наводнений, проверка хоста, запуск регистратора|
| `Request` | `src/Core/Http/Request.php` |Объектно-ориентированная оболочка запроса (существует, но не используется в основном производственном потоке)|
| `Router` | `src/Core/Http/Router.php` |Регистрация и отправка маршрута по странице и API|
| `Response` | `src/Core/Http/Response.php` |Помощники по статическому ответу (JSON, redirect, CORS и т.д.)|
| `LegacyInitializer` | `src/Core/Init/LegacyInitializer.php` |Устаревший bootstrap, который подключает очистку к `RequestManager`|
В процессе производственного администрирования не используется `Request::capture()`. Вместо этого `LegacyInitializer::initCore()` управляет обработкой входных данных:
1.`InputValidator::cleanGlobals()` вызывается при `$_GET`, `$_POST`, `$_SESSION`, и `$_COOKIE` на месте, удаляя нулевые байты, последовательности обхода пути (`../`) и символы переопределения RTL.
2.`InputValidator::parseIncomingRecursively()` очищает ключи и значения (HTML-объекты, теги сценариев, разделители комментариев, окончания строк) и возвращает чистый массив.
3. Результат (объединяется с сообщением, сообщение имеет приоритет) сохраняется через `RequestManager::set()`.
Во всей кодовой базе доступ к данным запроса осуществляется через `RequestManager::get($key)` и `RequestManager::getAll()`, а не через объект `Request`.
---
## Поток запросов: REST API
Точка входа: `src/Public/index.php` (короткое замыкание перед маршрутизатором)
Когда `XC_SCOPE` равно `includes/api/admin` или `includes/api/reseller`:
Путь потоковой передачи намеренно упрощен. Он не загружает маршрутизатор, EventDispatcher, транслятор или полный сервисный контейнер. Диспетчеризация маршрутов отсутствует; каждая конечная точка потоковой передачи имеет выделенную точку входа.
Процедурный защитный скрипт, включенный ранее в устаревший bootstrap. Выполняется только для HTTP-запросов (пропускается, если установлено значение `$_SERVER['argc']`, указывающее на CLI).
3.**Проверка хостинга** -- Если `$rSettings['verify_host']` имеет значение true, проверяется, отображается ли `HOST` в кэшированном списке `allowed_domains`. Исключения: имя хоста `xc_vm` и любой допустимый IP-адрес всегда разрешены.
5.**Инициализация регистратора** -- Вызывает `Logger::init(PHP_ERRORS, LOGS_TMP_PATH . 'error_log.log')`.
Примечание: В современном bootstrap (`XC_Bootstrap::boot()`) эти обязанности выполняются методами `floodProtection()` и `hostVerification()` напрямую, а не путем включения `RequestGuard.php`.
---
## `InputValidator`
Файл: `src/Core/Validation/InputValidator.php`
Предоставляет статические методы для очистки входных данных и проверки на уровне действий.
| `cleanGlobals(&$data, $iteration)` |Удаление нулевых байтов на месте, обход пути (`../`) и символы переопределения RTL. Максимум 10 уровней рекурсии.|
| `parseIncomingRecursively(&$data, $input, $iteration)` |Возвращает новый обработанный массив. Очищаются как ключи, так и значения. Максимальное количество уровней рекурсии - 20.|
| `validate($action, $data)` |Возвращает `true`/`false` для определения того, соответствует ли `$data` минимальным требованиям для данного действия API.|
| `validateOrFail($action, $data)` |Возвращает `null`, если допустимо, или `['status' => STATUS_INVALID_INPUT, 'data' => $data]`, если недопустимо.|
| `confirmIDs($ids)` |Фильтрует массив только по целочисленным положительным идентификаторам.|
---
## `RequestManager`
Файл: `src/Core/Http/RequestManager.php`
Статический интерфейс, в котором хранятся объединенные данные запроса GET+POST. Это основной шаблон доступа к данным запроса, используемый во всей базе кода.
Объектно-ориентированная оболочка запроса. Содержит статическую фабрику `capture()` и методы экземпляра для доступа к обработанным входным данным. Хотя класс существует и полностью функционален, в основном производственном потоке вместо него используются `InputValidator` + `RequestManager`. Методы статической очистки класса `Request` (`cleanGlobals`, `parseIncomingRecursively`) используются `LegacyInitializer::initStreaming()` для обеспечения обратной совместимости.
| `any` | `any($route, $handler, $options = [])` |Зарегистрируйте как GET, так и POST для одного и того же маршрута|
| `api` | `api($action, $handler, $options = [])` |Зарегистрируйте маршрут API (JSON, отправляемый по имени действия)|
| `group` | `group($prefix, $callback, $options = [])` |Группируйте маршруты под общим префиксом с общим промежуточным программным обеспечением/разрешениями|
Параметр `$handler` принимает:
-`[ClassName::class, 'method']` -- создается через ServiceContainer (с возможностью возврата к `new`)
- Завершающий или вызываемый
-`[object, 'method']`
Массив `$options` поддерживает:
-`'permission' => ['type', 'key']` -- проверяется с помощью `Authorization::check()` перед запуском обработчика
-`'middleware' => [callable, ...]` -- массив вызываемых объектов, выполняемых после проверки прав доступа, перед обработчиком
Эта нормализация применяется как во время регистрации (`buildRoute`), так и во время отправки (`normalizePage`), поэтому маршруты, зарегистрированные как `watch/add`, соответствуют названиям страниц, подобным `watch_add`.
4.**Выполнение промежуточного программного обеспечения**. Вызывается каждый вызываемый объект в массиве `middleware`. Если какой-либо из них возвращает значение `false`, выполнение прекращается.
Конечные точки в формате JSON на панели администратора `?action=` регистрируются таким образом и обрабатываются выделенными контроллерами в соответствии с `XcVm\Public\Controllers\Admin\Ajax`. Шаблон контроллера и контракт структурированного поиска смотрите в [Admin AJAX API](admin-ajax-api.md).
И `dispatch()`, и `dispatchApi()` возвращают `false`, если маршрут не совпадает. `Public/index.php` затем выдает `http_response_code(404); echo '404 Not Found';` — есть **нет** универсальный контроллер. (Неправильно введенный путь к ресурсу, который достигает главного контроллера, вместо того, чтобы обслуживаться nginx, попадает на тот же 404.)
> **Pitfall — two sanitization APIs + a global.** Input can be reached three ways: `InputValidator` (the global request-sanitization layer), the `Request` class's static `sanitize*()` methods (kept for backward compatibility), and the global-static `RequestManager`. They are not interchangeable and the sanitization one applies depends on the bootstrap path — pick the layer the surrounding code already uses rather than mixing them, and remember `RequestManager`'s static state makes it order-dependent and awkward to isolate in tests (set it explicitly in a test rather than relying on prior request state).
Модули регистрируют маршруты с помощью `ModuleInterface::registerRoutes()`. Маршрутизатор поддерживает безопасный режим регистрации, предотвращающий перезапись модулями основных маршрутов:
// Module routes registered here -- duplicates are silently skipped
$moduleLoader->bootAll($container,$router);
$router->endModuleRegistration();
// Check for collisions (logged in development mode)
$collisions=$router->drainRouteCollisions();
```
В режиме регистрации модуля (`preserveExistingRoutes = true`), если модуль пытается зарегистрировать маршрут, который уже существует, существующий маршрут сохраняется и регистрируется коллизия. `drainRouteCollisions()` возвращает и очищает собранные коллизии в виде массива `['type' => 'get'|'post'|'api', 'key' => 'route/path']`.
### Самоанализ
|Метод|Описание|
| --- | --- |
| `hasRoute($page)` |Проверьте, существует ли маршрут страницы (GET или POST).|
| `hasApiRoute($action)` |Проверьте, существует ли маршрут API|
| `BootContext::Minimal` |Автозагрузка + константы + конфигурация + регистратор. Нет подключения к базе данных.|
| `BootContext::Cli` |+ База данных + `LegacyInitializer::initCore()` (очистка входных данных, настройки, пути FFmpeg). Необязательно Redis.|
| `BootContext::Stream` |+ Только база данных (упрощенная, без `LegacyInitializer`). Конечные точки потоковой передачи используют вместо этого `StreamingRequestBootstrap`.|
| `BootContext::Admin` |+ Сессия + База данных + `LegacyInitializer::initCore()` + Redis + API администратора + Переводчик + глобальные настройки администратора. Полная инициализация.|
> `boot()` принимает перечисление `BootContext` (предпочтительно). Устаревшая строка