Files
XC_VM/docs/ru/development/http-request-handling.md
T
Divarion-D 788ec37637 refactor: replace DEVELOPMENT flag, fix bootstrap and logging
- Remove DEVELOPMENT constant from AppConfig.php; introduce DB_ACCESS_ENABLED
  (controls phpMiniAdmin access in admin panel only, not core DB connections)
- Detach bootstrap.php from www/constants.php: load core/Config/* and
  core/Logging/Logger directly; define PHP_ERRORS fallback
- Switch Logger::init() to PHP_ERRORS in bootstrap.php, stream/init.php,
  RequestGuard.php; remove leftover TODO comment
- Logger: always set error_reporting(E_ALL); UI visibility controlled
  separately via display_errors; rename $development -> $showErrors
- MigrationRunner: track applied/failed counts separately; failed migrations
  are not marked as applied
- Replace DEVELOPMENT with DB_ACCESS_ENABLED in admin settings.php and
  database.php (phpMiniAdmin gate)
- Replace DEVELOPMENT with PHP_ERRORS in CertbotCronJob
- Docs (en/ru): add DB_ACCESS_ENABLED flag description; update feature-flags,
  updates_checklist, http-request-handling; remove DEVELOPMENT references
- MIGRATION.md: mark L-1 as done, remove from backlog and wave A;
  unblock L-2; renumber steps
2026-04-19 18:13:56 +03:00

7.8 KiB
Raw Blame History

Обработка HTTP-запросов и middleware

Слой обработки HTTP-запросов в XC_VM состоит из трёх компонентов: RequestGuard (безопасность входящих запросов), Request (обёртка над суперглобальными переменными) и Router (маршрутизация к обработчикам).


Обзор потока запроса

Входящий HTTP-запрос
        │
        ▼
[RequestGuard]
  ├── Flood-protection (блокировка по IP-файлу)
  ├── Host verification (проверка домена)
  ├── Загрузка $rSettings из кеша
  └── Инициализация Logger
        │
        ▼
[Request::capture()]
  ├── Санитизация $_GET, $_POST, $_COOKIE
  └── Создание объекта запроса
        │
        ▼
[Router::dispatch()]
  ├── Определение маршрута по URL
  ├── Проверка метода (GET / POST)
  └── Вызов обработчика [Controller::method]

RequestGuard

src/core/Http/RequestGuard.php

Выполняется автоматически при загрузке www/constants.php в контекстах HTTP (STREAM, ADMIN).

Flood-protection

Блокирует IP, если существует файл FLOOD_TMP_PATH/block_{IP}.

/tmp/xc_vm/flood/block_1.2.3.4  →  HTTP 403 + exit()

Файлы блокировки создаются отдельной защитной логикой при превышении лимита запросов.

Host verification

Если в настройках включена проверка хоста (verify_host = true) и загружен кеш разрешённых доменов (allowed_domains):

  • Запрос с не зарегистрированного домена → generateError('INVALID_HOST')
  • IP-адреса как хост всегда разрешены
  • Служебный хост xc_vm всегда разрешён

Загрузка настроек

$rSettings загружается из файлового кеша (CACHE_TMP_PATH/settings) через igbinary_unserialize(). Это позволяет избежать обращения к БД на каждом запросе.

Инициализация Logger

Logger::init(PHP_ERRORS, LOGS_TMP_PATH . 'error_log.log');

После RequestGuard Logger доступен во всех последующих компонентах.


Request

src/core/Http/Request.php

Обёртка над $_GET, $_POST, $_SERVER, $_COOKIE с санитизацией входных данных.

Создание объекта

// Захватить текущий HTTP-запрос
$request = Request::capture();

// Или создать вручную
$request = new Request($_GET, $_POST, $_SERVER, $_COOKIE);

При создании все данные из $_GET, $_POST, $_COOKIE проходят санитизацию через cleanGlobals() и parseIncomingRecursively().

Получение данных

$request->get('key');           // из $_GET
$request->post('key');          // из $_POST
$request->input('key');         // из POST или GET (POST имеет приоритет)
$request->cookie('key');        // из $_COOKIE
$request->server('key');        // из $_SERVER (без санитизации)

// С дефолтным значением
$request->get('page', 1);
$request->input('action', '');

Вспомогательные методы

$request->method();             // 'GET' или 'POST'
$request->isPost(): bool
$request->isGet(): bool
$request->ip(): string          // IP клиента
$request->all(): array          // Весь merged input
$request->has('key'): bool
$request->only(['a', 'b']): array
$request->except(['x']): array

Санитизация

  • Ключи: очищаются через parseCleanKey() — удаляются все символы кроме a-z, A-Z, 0-9, _, -
  • Значения: очищаются через parseCleanValue() — strip_tags() + обрезка пробелов
  • $_SERVER намеренно не санитизируется (содержит пути и бинарные данные)

Router

src/core/Http/Router.php

Маршрутизатор для администраторской панели. Заменяет паттерн switch($rAction) и прямые include в admin-страницах.

Регистрация маршрутов

$router = new Router();

// GET-маршруты (страницы)
$router->get('streams', [StreamController::class, 'index']);
$router->get('stream/add', [StreamController::class, 'add']);

// POST-маршруты (формы)
$router->post('stream/save', [StreamController::class, 'save']);

// API-маршруты (JSON-ответ)
$router->api('getStreams', [StreamController::class, 'apiList']);
$router->api('deleteStream', [StreamController::class, 'apiDelete']);

Группировка маршрутов

$router->group('plex', function(Router $r) {
    $r->get('', [PlexController::class, 'index']);
    $r->get('add', [PlexController::class, 'add']);
    $r->post('save', [PlexController::class, 'save']);
    $r->api('enable', [PlexController::class, 'apiEnable']);
});
// Результат: 'plex', 'plex/add', 'plex/save', 'plex/enable'

Диспетчеризация

// Страница по URL
$router->dispatch($page, $method);

// API-вызов
$router->dispatchApi($action);

Модульная регистрация маршрутов

Каждый модуль регистрирует свои маршруты через ModuleInterface::registerRoutes():

class WatchModule implements ModuleInterface {
    public function registerRoutes(Router $router): void {
        $router->group('watch', function(Router $r) {
            $r->get('', [WatchController::class, 'index']);
            $r->get('add', [WatchController::class, 'add']);
            $r->post('settings', [WatchController::class, 'saveSettings']);
            $r->api('enable', [WatchController::class, 'apiEnable']);
        });
    }
}

Обратная совместимость

Пока admin/api.php использует switch($rAction), Router используется как fallback в конце switch-цепочки:

// В конце switch($rAction):
default:
    $router->dispatchApi($rAction);

RequestManager

src/core/Http/RequestManager.php

Статический фасад для доступа к параметрам запроса без создания объекта Request.

RequestManager::get('key');
RequestManager::post('key');
RequestManager::getAll(): array
RequestManager::postAll(): array

Используется в компонентах, которые не получают Request через инъекцию.


Связанные файлы

Файл Назначение
src/core/Http/RequestGuard.php Flood-protection, host check, settings
src/core/Http/Request.php Обёртка над суперглобальными
src/core/Http/Router.php Маршрутизация GET/POST/API
src/core/Http/RequestManager.php Статический фасад для запросов
src/core/Http/Response.php Формирование HTTP-ответов
src/www/constants.php Загружает RequestGuard