Релизы

История изменений

Каждое значимое изменение сервера, PHP API и образов — избранные моменты по каждому релизу. Полная, неурезанная история — в CHANGELOG.md.

последняя v0.10.0 · 2026-07-12 · 10 релизов · AGPL-3.0 CHANGELOG.md →
oxphp — releases bash
$ docker pull ghcr.io/oxphp/oxphp:0.10.0
0.10.0: Pulling from oxphp/oxphp
Status: Image is up to date
# opt-in PHP 8.5 preview:
$ docker pull ghcr.io/oxphp/oxphp:php8.5
unreleased
git: main
UNRELEASED
CHANGELOG.md →
ADDED

Автоматический захват необработанных исключений в корневом спане — Запрос, который завершается неперехваченным исключением или фатальной ошибкой и возвращает 5xx, теперь прикрепляет к корневому спану SERVER событие исключения OpenTelemetry (type, message, stacktrace, file, line) без атрибута #[OxPHP\Apm\Trace] и без вызова oxphp_apm_error(), так что 500 сам себя описывает в бэкендах ошибок. Приложения на фреймворках, которые отрисовывают собственную страницу ошибки, по-прежнему записывают его явно.

CHANGED

FRAME_OPTIONS теперь по умолчанию SAMEORIGIN, а не DENY — Встраивание во фреймы в рамках того же источника (превью админки, виджеты дашборда, платёжные компоненты того же источника) работает из коробки, тогда как межсайтовый кликджекинг остаётся заблокированным, как в nginx и Rails; задайте FRAME_OPTIONS=DENY, чтобы запретить любое встраивание во фреймы.

v0.10.0
2026-07-12
LATEST
⚠ breaking changes
Release notes →
BREAKING

Сброс привилегий по умолчанию — Запущенный от root при наличии учётной записи www-data, сервер привязывает свои слушающие сокеты и сбрасывает привилегии до www-data перед тем, как начать обслуживать трафик; официальный образ больше не работает от root. Передайте --user=root, чтобы сохранить прежнее поведение.

Fail-closed конфигурация TLS — Наполовину настроенная пара (TLS_CERT без TLS_KEY или наоборот) либо значение сертификата/ключа не в UTF-8 теперь прерывает запуск вместо того, чтобы молча обслуживать обычный HTTP, называя проблемную переменную.

Строгий разбор ASYNC_* / SUPERGLOBALS — Мусор в ASYNC_WORKERS, ASYNC_QUEUE_CAPACITY или ASYNC_MAX_FIBERS теперь приводит к ошибке запуска вместо молчаливого значения по умолчанию, а oxphp run больше не игнорирует некорректный SUPERGLOBALS_ENABLED.

QUERY без Content-Type возвращает 400, а не 415 — Единственный генерируемый сервером 415 исчез; пользовательский ERROR_PAGES_DIR/415.html для этого случая нужно переименовать в 400.html.

Определение конверта экспорта профилировщика — PROFILER_EXPORT_XHGUI=false теперь имеет приоритет даже на URL /run/import, а автоопределение конверта опирается только на канонический путь каждого инструмента (xhgui /run/import, Buggregator /api/profiler/store), а не на нечёткое вхождение подстроки "xhgui".

ADDED

Экспорт профилировщика в Buggregator — HTTP-push профилировщика оборачивает данные xhprof в конверт, который ожидает POST /api/profiler/store в Buggregator; PROFILER_EXPORT_BUGGREGATOR включает это, а tags и app_name задаются через переменные окружения.

Экспорт трассировки OTLP по TLS — https:// OTEL_EXPORTER_OTLP_ENDPOINT теперь экспортируется в зашифрованном виде как по gRPC, так и по http/protobuf, с проверкой по системному хранилищу доверенных сертификатов через rustls; образ среды выполнения должен содержать CA-бандл (официальный содержит).

Полные данные об исключении в спанах APM — Событие исключения в спане теперь несёт exception.message и exception.stacktrace наряду с exception.type, так что New Relic Errors Inbox, Jaeger и Tempo отображают сообщение и стек; ограничивается OTEL_APM_MESSAGE_MAX_BYTES / OTEL_APM_STACKTRACE_MAX_BYTES.

Корректный слив долгоживущих соединений — По SIGTERM сервер отправляет GOAWAY, закрывает простаивающие keep-alive-соединения и оперативно завершает открытые потоки SSE/flush; значение по умолчанию DRAIN_TIMEOUT_SECONDS снижено с 30 → 25, чтобы уложиться в 30-секундный grace-период Kubernetes.

TLS_MIN_VERSION — Минимальная допустимая версия протокола: 1.2 (по умолчанию) или 1.3. Всё остальное — включая чужеродный синтаксис вроде "TLSv1.2" — приводит к жёсткой ошибке запуска, проверяется даже при отключённом TLS и сообщается как tls_min_version в /config.

CHANGED

Дешёвый STATIC_REVALIDATE — stat() не чаще одного раза в 3 секунды на файл; попадание по статике обслуживается из памяти максимум одним системным вызовом, а изменения на диске становятся видны в течение 3 с. По умолчанию остаётся выключенным.

Более понятные ошибки запуска TLS — Путь с опечаткой завершается сообщением "TLS_CERT: cannot read /etc/ssl/cert.pem: No such file or directory" вместо голой ошибки ОС; ошибки разбора PEM и несоответствия ключа снабжаются таким же префиксом.

FIXED

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

finish_request() против мультиплексированных потоков — Как только любой запрос на воркере вызывал oxphp_finish_request(), каждый другой поток, мультиплексированный на этот воркер, молча терял свой последующий вывод oxphp_stream_flush().

v0.9.0
2026-06-25
⚠ breaking changes
Release notes →
BREAKING

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

ADDED

Вложенный oxphp_async() — Асинхронная задача может порождать собственные задачи и приостанавливаться на await_all / await_any / await_race, не блокируя свой поток-воркер. Ограничение «без вложенного async» снято.

Лимит задач в обработке — ASYNC_MAX_FIBERS (по умолчанию 256) ограничивает число задач в очереди + выполняющихся; отправка сверх лимита немедленно отклоняется с AsyncException, так что fan-out не может привести к взаимоблокировке.

Список разрешений для внутреннего сервера — INTERNAL_ALLOW_IPS: список разрешений в формате CIDR для /metrics и /config; эндпоинты проверки работоспособности остаются доступными для оркестраторов.

Исключения для семплирования профилировщика — PROFILER_EXCLUDE_PATHS удерживает собственный трафик фреймворка (/_profiler, /_wdt) вне статистического семплирования; явные триггеры по-прежнему запускают профилирование.

FIXED

Пробуждение отправителя в Channel — Файбер, ожидающий отправки и припаркованный на заполненном Shared\Channel, пробуждается, когда recv_blocking освобождает слот — sendTimeout больше не срабатывает ложно при насыщении.

Крайние случаи async — Падение при корректном завершении работы; await на закрытом промисе зависал вместо отклонения; await_all оставлял промисы выполняться при раннем выходе.

v0.8.0
2026-06-13
⚠ breaking changes
Release notes →
BREAKING

Контракт маршрутизации воркеров — Статические ресурсы с диска, всё остальное — во входной файл воркера ENTRY_FILE; произвольные .php-файлы, индексы каталогов и запасной вариант с корневым index.php больше не разрешаются на каждый запрос.

Честный CGI PATH_INFO — В режиме Framework PATH_INFO задаётся только для явного запроса /index.php/extra; PHP_SELF сообщает фронт-контроллер. Маршрутизируйте по REQUEST_URI.

ADDED

Range-запросы (RFC 9110) — 206 Partial Content для статических файлов: перемотка видео, возобновляемые загрузки, частичная загрузка PDF; If-Range учитывается со строгими валидаторами.

Лимиты соединений HTTP/2 — Пять переменных окружения ограничивают использование ресурсов на соединение; итоговые значения логируются при запуске.

CHANGED

Строгие ETag для статики — "<size>-<mtime>" заменяет W/"…" — этого требует If-Range; сжатые представления сохраняют слабый тег.

FIXED

Заголовки приложения побеждают — X-Content-Type-Options, X-Frame-Options и CSP, заданные из PHP, больше не перезаписываются — значения сервера являются запасными и вставляются, только если заголовок отсутствует.

Стриминг против сжатия — Ответы, передаваемые через flush(), проходят без сжатия, а не буферизуются целиком слоем brotli до конца скрипта.

SECURITY

Усиление защиты HTTP/2 от DoS — Rapid Reset (CVE-2023-44487), HPACK-бомбы и атаки на зависание окна ограничены; мёртвые соединения высвобождаются через keepalive на PING/PONG.

v0.7.0
2026-06-05
⚠ breaking changes
Release notes →
BREAKING

remote_ip в логах доступа — JSON-поле remote_addr переименовано в remote_ip и содержит IP без порта — как в nginx/Apache/Caddy.

ADDED

CLI в стиле PHP — oxphp run script.php выполняет файл с семантикой CLI и полноценным движком под капотом; скрипты с #!/usr/bin/env oxphp запускаются напрямую; переопределения ini через -d принимаются.

Сброс привилегий через --user — Привязать привилегированные порты от root, затем необратимо сбросить привилегии до непривилегированного пользователя до того, как появится любой поток обработки запросов.

Проброшенный порт учитывается — За TRUSTED_PROXIES, SERVER_PORT учитывает X-Forwarded-Port; REMOTE_PORT заполняется из for= в RFC 7239, когда прокси его предоставляет.

FIXED

Падения декораторов — Два SIGSEGV в пути функциональных декораторов (освобождённый кэш экземпляров; висячий zval при изменении размера) устранены; переполнение вложенности теперь бросает StackOverflowException.

Атрибуты профилировщика учитывают аргументы — #[SlowThreshold(ms:)], #[MemoryThreshold(kb:)] и #[Mark(label:)] больше не схлопываются к общим значениям по умолчанию; события спанов APM доходят до OpenTelemetry.

API объектов загрузки подключён — Request::file() / files() возвращают объекты UploadedFile для любой формы $_FILES вместо null.

v0.6.0
2026-05-28
⚠ breaking changes
Release notes →
BREAKING

Трихотомический API ожидания — Channel и Mutex разбивают каждое ожидание на try* / голый глагол / *Timeout(int $ms), возвращая значения типов SendResult / RecvResult вместо mixed|null.

await_any означает Promise.any — Побеждает первый выполненный; при отклонении всех бросается AggregateAsyncException. Прежнее поведение «первый завершившийся» теперь называется oxphp_async_await_race().

Честные статусы отмены — Таймаут → 504, корректный слив → 503 + Retry-After, отключение клиента → 499 (только в лог). Убийства супервизором и отмены из пользовательского кода сохраняют 500.

Переименования без прослоек — Async\Exception → AsyncException, Shared\Exception → SharedException; Worker убирает префиксы get*; Counter становится минимальным (add/set); Flag повторяет Atomic; Once получает getOrInit()/status().

ADDED

Shared\Atomic + Ordering — Обобщённый int64-атомик: load/store/swap/CAS/fetch* с явными упорядочениями памяти, один в один с std::sync::atomic.

Shared\Registry — Процессно-глобальные хендлы с ключом по имени: каждый воркер сходится на одной и той же записи; фабрика выполняется максимум один раз.

REMOVED

Единый источник таймаута — REQUEST_TIMEOUT_SECONDS и oxphp_request_heartbeat() удалены — max_execution_time и set_time_limit() остаются.

FIXED

connection_aborted() в SSE — Возвращает true после разрыва посреди потока, так что циклы while (!connection_aborted()) завершаются корректно.

PERFORMANCE

Горячий путь Shared\* — Накладные расходы на операцию укладываются в шум criterion относительно чистой атомарной загрузки; ≈4.7× среднегеометрического на 8 потоках против прежней формы.

v0.5.0
2026-05-05
⚠ breaking changes
Release notes →
BREAKING

Строгий разбор булевых переменных окружения — Только on/true/1/yes и off/false/0/no; опечатка вроде ture приводит к отказу запуска вместо молчаливого значения по умолчанию.

ADDED

ENTRY_FILE + WORKER_MODE_ENABLED — Одна переменная выбирает режим маршрутизации по расширению; отдельный переключатель включает постоянные воркеры. INDEX_FILE / WORKER_FILE становятся устаревшими псевдонимами.

Класс OxPHP\Server\Worker — Хендл для интроспекции во время выполнения: id, число запросов, память, RSS — плюс управляемое приложением пересоздание через scheduleExit().

CHANGED

Переименования кэша статики — STATIC_CACHE_TTL → STATIC_MAX_AGE; STATIC_CACHE → STATIC_REVALIDATE с инвертированной полярностью. Значения по умолчанию не изменились.

DEPRECATED

WORKER_MAX_REQUESTS — Разбирается и игнорируется с предупреждением WARN при запуске — переходите на WORKER_MAX_MEMORY_MIB или scheduleExit().

v0.4.0
2026-05-02
Release notes →
ADDED

Образы PHP 8.5 — :php8.5, :php8.5-alpine и теги с фиксацией патча поставляются наряду с 8.4; latest остаётся на 8.4, пока не закроется окно обкатки.

FIXED

Чанкованный стриминг между запросами — Контекст моста, привязанный к запросу, утекал между запросами воркера, теряя чанкованный Transfer-Encoding после первого flush.

Shared\* внутри пользовательских файберов — Channel::recv()/send() внутри Fiber::start() больше не идут по пути приостановки oxphp-fiber и не падают с fiber_await rc=1.

Именованные аргументы для API плагинов — Классы и функции, определённые плагинами, теперь объявляют реальные имена параметров — вызовы с именованными аргументами работают.

Разделяемые хендлы в асинхронных замыканиях — Channel/Map/Pool, захваченные замыканием oxphp_async(), больше не приходят как null в принимающий поток.

v0.3.0
2026-04-22
⚠ breaking changes
Release notes →
BREAKING

Пространство имён Async — Async-классы перемещены в OxPHP\Async\; функции теперь поставляются в plugin-async.

ADDED

Семь примитивов Shared\* — Counter, Flag, Once, Mutex, Channel, Map, Pool — атомарное состояние, разделяемое между воркерами, с наблюдаемостью через реестр и детектором взаимоблокировок.

Профилировщик на каждый запрос — Вывод в xhprof / speedscope / pprof / collapsed; триггеры по cookie, заголовку, query-параметру и статистические; HTTP-push с конвертом xhgui.

Автоинструментирование APM — plugin-apm с SDK трассировки для PHP и захватом ошибок; подсистемы async и APM перенесены в плагины на Rust.

Интеграции для продакшена — TRUSTED_PROXIES (RFC 7239), Kubernetes /readyz + /livez, заголовки безопасности, ограничение частоты запросов на IP — всё настраивается через переменные окружения.

PERFORMANCE

Горячий путь Pool — Неконкурентные acquire/release ≈0.9 мкс в Docker, с привязкой к потоку.

v0.2.0
2026-03-27
Release notes →
ADDED

Мультиплексирование файберов — Конкурентный ввод-вывод в рамках одного потока-воркера; распределённая трассировка с W3C Trace Context и экспортом в OpenTelemetry.

Промисы oxphp_async() — Параллельное выполнение PHP на выделенном пуле потоков.

Объектный API HTTP — OxPHP\Http\Request с ленивыми аксессорами, плюс система декораторов на основе атрибутов.

CHANGED

Порт и противодавление (backpressure) — Порт по умолчанию 8080 → 80 (443 при TLS); ответ противодавления 503 → 529.

FIXED

Корректность CGI — SERVER_PROTOCOL отражает реальную версию HTTP; REQUEST_TIME — это начало запроса; разбор IPv6 в Host; 408 при таймауте запроса.

v0.1.0
2026-03-08
Release notes →
ADDED

Асинхронное ядро HTTP — Сервер на Hyper + Tokio с корректным завершением работы, собственный SAPI oxphp с полными суперглобальными переменными, пул воркеров ZTS с ограниченной очередью и противодавлением 529.

Три режима маршрутизации — Traditional, Framework и SPA; статические файлы с кэшем в памяти, ETag/304, brotli, TLS.

Режим воркеров — Постоянные воркеры через oxphp_worker(), раннее завершение ответа, стриминг SSE, кооперативные таймауты.

Наблюдаемость — /metrics, /health, /config, структурированные JSON-логи доступа, идентификаторы запросов.

Docker-first — Многоэтапная сборка на Alpine; образы amd64/arm64 на GHCR.