版本发布

更新日志

服务器、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

根 span 上自动捕获未处理异常 — 因未捕获异常或致命错误而失败并返回 5xx 的请求,现在会向根 SERVER span 附加一个 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

默认降权 — 在存在 www-data 账户的环境下以 root 启动时,服务器会绑定其监听套接字,并在开始处理任何流量之前降权到 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。

没有 Content-Type 的 QUERY 返回 400,而非 415 — 唯一由服务器生成的 415 已移除;针对此情况的自定义 ERROR_PAGES_DIR/415.html 必须重命名为 400.html。

性能分析器导出信封的判定 — PROFILER_EXPORT_XHGUI=false 现在即使在 /run/import URL 上也会生效,且信封自动检测仅依据每个工具的规范路径(xhgui /run/import、Buggregator /api/profiler/store),不再依据模糊的 "xhgui" 子串。

ADDED

Buggregator 性能分析器导出 — 性能分析器的 HTTP push 会把 xhprof 数据包装进 Buggregator 的 POST /api/profiler/store 所期望的信封中;PROFILER_EXPORT_BUGGREGATOR 用于开关此功能,tags 和 app_name 通过环境变量设置。

通过 TLS 的 OTLP 追踪导出 — https:// 的 OTEL_EXPORTER_OTLP_ENDPOINT 现在在 gRPC 和 http/protobuf 上都会加密导出,并通过 rustls 对照系统信任库进行校验;运行时镜像必须自带 CA 包(官方镜像已包含)。

APM span 上的完整异常数据 — 异常 span 事件现在除了 exception.type 之外还携带 exception.message 和 exception.stacktrace,因此 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 下调,以适配 Kubernetes 的 30 秒宽限期。

TLS_MIN_VERSION — 可接受的最低协议版本:1.2(默认)或 1.3。其他任何值——包括像 "TLSv1.2" 这样的异类语法——都会导致硬性启动错误,即使 TLS 被禁用也会校验,并在 /config 中以 tls_min_version 上报。

CHANGED

低开销的 STATIC_REVALIDATE — 每个文件最多每 3 秒执行一次 stat();静态命中会以最多一次系统调用从内存提供,磁盘上的改动会在 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 拒绝,因此扇出不会死锁。

内部服务器允许列表 — INTERNAL_ALLOW_IPS:用于 /metrics 和 /config 的 CIDR 允许列表;健康检查端点对编排器保持可达。

性能分析器采样排除 — PROFILER_EXCLUDE_PATHS 会把框架自身流量(/_profiler、/_wdt)排除在统计采样之外;显式触发仍会进行性能分析。

FIXED

Channel 发送方唤醒 — 停放在已满 Shared\Channel 上的纤程发送等待者,会在 recv_blocking 腾出一个槽位时被唤醒——sendTimeout 在饱和状态下不再被误触发。

异步边界情况 — 优雅关闭时的崩溃;对已关闭 promise 的 await 卡住而非拒绝;await_all 在提前退出时留下 promise 仍在运行。

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

应用头部优先 — 由 PHP 设置的 X-Content-Type-Options、X-Frame-Options 和 CSP 不再被覆盖——服务器提供的值只是在缺失时才插入的回退。

流式传输与压缩 — 用 flush() 流式输出的响应会以未压缩的形式直接透传,而不再被 brotli 层完整缓冲直到脚本结束。

SECURITY

HTTP/2 DoS 加固 — Rapid Reset(CVE-2023-44487)、HPACK 炸弹和窗口停滞攻击都受到限制;死连接通过 PING/PONG keepalive 回收。

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

访问日志中的 remote_ip — JSON 字段 remote_addr 更名为 remote_ip,且携带不含端口的 IP——与 nginx/Apache/Caddy 保持一致。

ADDED

PHP 风格的 CLI — oxphp run script.php 以 CLI 语义执行一个文件,底层使用完整引擎;#!/usr/bin/env oxphp 脚本可直接运行;接受 -d ini 覆盖。

--user 降权 — 以 root 绑定特权端口,然后在任何请求处理线程创建之前,不可逆地降权到非特权用户。

尊重转发端口 — 在 TRUSTED_PROXIES 之后,SERVER_PORT 会尊重 X-Forwarded-Port;当代理提供时,REMOTE_PORT 会从 RFC 7239 的 for= 填充。

FIXED

装饰器崩溃 — 函数装饰器路径中的两处 SIGSEGV(已释放的实例缓存;跨扩容的悬空 zval)已修复;嵌套溢出现在会抛出 StackOverflowException。

性能分析器属性尊重参数 — #[SlowThreshold(ms:)]、#[MemoryThreshold(kb:)] 和 #[Mark(label:)] 不再退化为共享的默认值;APM span 事件能够抵达 OpenTelemetry。

上传对象 API 已接通 — Request::file() / files() 现在会为每种 $_FILES 形态返回 UploadedFile 对象,而不是 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

SSE 中的 connection_aborted() — 在流中途断开后返回 true,因此 while (!connection_aborted()) 循环能干净地退出。

PERFORMANCE

Shared\* 热路径 — 每次操作的开销落在原始原子加载的 criterion 噪声范围之内;在 8 线程下相比此前的形态几何平均约提升 4.7×。

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

跨请求的分块流式传输 — 桥接层的每请求上下文在多个工作进程请求之间发生泄漏,导致首次 flush 之后丢失分块的 Transfer-Encoding。

用户纤程内的 Shared\* — Fiber::start() 内部的 Channel::recv()/send() 不再走 oxphp-fiber 挂起路径并以 fiber_await rc=1 崩溃。

插件 API 的具名参数 — 插件定义的类和函数现在会公布真实的参数名——具名参数调用可以正常工作。

异步闭包中的 Shared 句柄 — 被 oxphp_async() 闭包捕获的 Channel/Map/Pool 不再在接收线程上以 null 到达。

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

Async 命名空间 — 异步类已移动到 OxPHP\Async\ 之下;这些函数现在随 plugin-async 一起发布。

ADDED

七种 Shared\* 原语 — Counter、Flag、Once、Mutex、Channel、Map、Pool——跨工作进程共享的原子状态,带有注册表可观测性和死锁检测器。

按请求的性能分析器 — xhprof / speedscope / pprof / collapsed 输出;cookie、header、query 和统计触发;带 xhgui 信封的 HTTP push。

APM 自动埋点 — plugin-apm 提供 PHP 追踪 SDK 和错误捕获;异步和 APM 子系统已迁移到 Rust 插件中。

生产集成 — TRUSTED_PROXIES(RFC 7239)、Kubernetes /readyz + /livez、安全头部、按 IP 限流——全部通过环境变量配置。

PERFORMANCE

Pool 热路径 — 在 Docker 中无竞争的获取/释放约 0.9 µs,带有每线程亲和性。

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

纤程多路复用 — 单个工作线程内的并发 I/O;使用 W3C Trace Context 的分布式追踪和 OpenTelemetry 导出。

oxphp_async() promise — 在专用线程池上并行执行 PHP。

HTTP 对象 API — 带惰性访问器的 OxPHP\Http\Request,外加基于属性的装饰器系统。

CHANGED

端口与背压 — 默认端口 8080 → 80(启用 TLS 时为 443);背压响应 503 → 529。

FIXED

CGI 正确性 — SERVER_PROTOCOL 反映真实的 HTTP 版本;REQUEST_TIME 为请求开始时间;IPv6 Host 解析;请求超时返回 408。

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

异步 HTTP 核心 — 一个支持优雅关闭的 Hyper + Tokio 服务器,一个带完整超全局变量的自定义 oxphp SAPI,一个带有界队列和 529 背压的 ZTS 工作进程池。

三种路由模式 — Traditional、Framework 和 SPA;静态文件带内存缓存、ETag/304、brotli、TLS。

工作进程模式 — 通过 oxphp_worker() 实现持久化工作进程、提前响应完成、SSE 流式传输、协作式超时。

可观测性 — /metrics、/health、/config、结构化 JSON 访问日志、请求 ID。

Docker 优先 — 多阶段 Alpine 构建;GHCR 上的 amd64/arm64 镜像。