☰
深度解读 guzzlehttp/psr7 CHANGELOG:从 1.0 到 3.0 的安全加固、API 演进与升级路径
2026/9/27 8:07:10 网站建设 项目流程
  • 后端

【免费下载链接】psr7

PSR-7 HTTP message library

项目地址:https://gitcode.com/gh_mirrors/ps/psr7
点击查看免费下载

本文以 CHANGELOG.md 为时间主线,系统梳理 PSR-7 HTTP message 库guzzlehttp/psr7从 1.0 到 3.0 的每一次重大演进:包括 3.0.0 的破坏性变更与新能力、2.x 系列的多个安全公告(GHSA)及其修复细节、1.x 时代的基础能力沉淀。通过结合仓库源码(如 src/Utils.php、src/Rfc3986.php、src/UriNormalizer.php)与测试用例,帮助读者理解每个版本"为什么改、改了什么、如何迁移",并为基于 PSR-7 的 HTTP 客户端与服务端开发提供可落地的升级对照表。

版本演进总览:三个时代的交接

从 CHANGELOG 记录看,guzzlehttp/psr7大致经历了三个阶段:

阶段代表版本主题
1.x1.0.0(2015-05-19)→ 1.8.1功能补全:PSR-7 全接口、URI 工具、MIME、流处理
2.x2.0.0(2021-06-30)→ 2.13.0现代化:PSR-17 工厂、类型化、安全加固、弃用铺垫
3.x3.0.0(2026-07-20)严苛化:原生类型、严格校验、非序列化、行为修正

值得注意的是,当前 composer.json 中声明require为psr/http-message:^2.0、psr/http-factory:^1.1,并provide了psr/http-message-implementation: 2.0,与 CHANGELOG 中 3.0.0 的要求完全一致,说明仓库当前代码基线即对应 3.0.0 版本。PHP 版本要求为^7.4 || ^8.0,同时通过symfony/polyfill-php80与symfony/polyfill-php82保持对旧环境的部分兼容。

3.0.0:一次以"严格校验"为核心的破坏性大版本

3.0.0(2026-07-20)是 CHANGELOG 中最浓墨重彩的一笔,其核心思路是:让库的行为更符合 RFC 与 PSR 规范,把"静默容错"改为"显式拒绝"。

Added:新增的公开能力

  • DiagnosticValue::escape():转义诊断信息中的控制字符与畸形 UTF-8。查看 src/DiagnosticValue.php 的实现,它通过 PCRE 回调把 C0、DEL、C1 控制字符统一渲染为大写\xNN序列,当输入为畸形 UTF-8 或 PCRE 失败时退化为逐字节转义(escapeBytes()),并明确"结果仅用于诊断文本,不是可逆编码"。
  • Exception\TimeoutException:为超时的流操作提供专门异常,见 src/Exception/TimeoutException.php,继承自RuntimeException。它在Utils::copyToStream()、copyToString()、hash()以及Stream的读写中被抛出(见 src/Utils.php 中StreamTimeout::read的调用点)。
  • Utils::redactUserInfoInString():在文本中脱敏原始 URI 字符串里的 userinfo,与已有的Utils::redactUserInfo()(src/Utils.php)配合,避免日志或异常信息泄露凭据。
  • Rfc3986升级为公开 API:提供isValid*()系列语法谓词与canonicalizeIpv6()。例如isValidScheme()要求 scheme 以字母开头且仅含[A-Za-z0-9.+-](见 src/Rfc3986.php),isValidHost()会拒绝控制字符、空白、/ ? # @ \、内嵌冒号(端口)、畸形百分号序列等。
  • UriNormalizer::CANONICALIZE_IPV6_HOST(位掩码256)被并入PRESERVING_NORMALIZATIONS默认集合(见 src/UriNormalizer.php),意味着默认归一化也会把 IPv6 主机规范为 RFC 5952 形式。

Changed:行为修正的六大主题

  1. 类型与校验收紧:要求psr/http-message:^2.0、psr/http-factory:^1.1并全面引入原生参数/返回类型;拒绝空数组与非字符串作为 header 值、拒绝非法上传文件树、拒绝缺tmp_name/size/error的上传文件规格、拒绝非整数或负数error值、拒绝负的read()长度、拒绝PumpStream源回调返回空字符串等。
  2. 流处理修正:UploadedFile::moveTo()在复制前会回绕可 seek 的上传流;CachingStream::close()幂等化;FnStream的 close/detach 变为终态且 close 回调至多调用一次;Message::bodySummary()恢复流原始位置,并允许null截断长度走默认值(默认 120,见 src/Message.php)。
  3. URI 与请求行规范化:Uri::getPath()归一化多个前导斜杠;authority-less 的fileURI 序列化不再产出不可解析的file://;host 校验全面加固(分隔符、反斜杠、IPv6、内嵌端口);scheme 必须以字母开头;Uri::fromParts()校验端口而非强制转换。
  4. Host/端口语义:为ws/wss引入默认端口 80/443;UriComparator::isCrossOrigin()的端口比较使用 ws/wss 默认端口;Request::withUri()在 URI 变化或 Host 为空时同步 Host 头;Message::toString()合成 Host 时包含 URI 端口(见 src/Message.php 的hostHeaderFromUri())。
  5. 超时与溢出:流超时统一抛TimeoutException;Utils::copyToStream()在目标流无法前进时抛异常并返回实际复制字节数;字节计数或偏移超过PHP_INT_MAX抛OverflowException。
  6. multipart 与安全:按 RFC 7578 §4.8 停止为multipart/form-data部件添加默认Content-Length;转义Content-Disposition参数并拒绝不安全的 boundary 与部件头;PHP 8.2+ 上对含凭据的 URI、server、cookie 参数进行堆栈脱敏(#[\SensitiveParameter],见 src/Utils.php 中redactUserInfo()的定义)。

Removed:必须注意的破坏点

  • 放弃 PHP 7.2 / 7.3 支持;
  • 移除ralouphie/getallheaders依赖;
  • 删除已废弃的Header::normalize()方法。

对升级者而言,3.0 意味着:方法大小写被保留(ServerRequest::fromGlobals()除外)、header 值必须是字符串、query 构建拒绝非有限浮点数、静态工具类不再可实例化(如 src/DiagnosticValue.php 中私有构造函数)。这些破坏在 2.11.0 与 2.12.0 中已通过"运行期弃用警告"做了铺垫,属于先警告后强制的标准迁移路径。

2.x 系列:安全公告与兼容性打磨

2.x 的价值在于安全修复密度极高,并持续为 3.0 铺路。

安全公告(GHSA)

版本公告修复内容
2.12.3GHSA-c2w2-prh8-qm98校验 URI host,保证getHost()与 URI authority 一致
2.12.1GHSA-vm85-hxw5-5432拒绝 HTTP 方法、协议版本与 reason phrase 中的 CR/LF 注入
2.10.2GHSA-hq7v-mx3g-29hw拒绝 URI host 组件中的控制与空白字符
2.10.2GHSA-34xg-wgjx-8xph拒绝构造请求 URI 时的畸形 Host 值

这些公告集中在"输入校验"方向,与 3.0.0 的严格化一脉相承。例如 2.12.2 还增加了 PCRE 失败时"显式报错、失败关闭(fail closed)"的策略,防止正则回退导致校验被绕过。

功能与行为要点

  • 2.13.0:新增Utils::asciiToLower/asciiToUpper/asciiUcFirst/caselessEquals/caselessContains(见 src/Utils.php 顶部实现),全部基于strtr做与区域设置无关的 ASCII 大小写折叠,这是 2.12.4/2.12.5 中修复"区域设置敏感比较"的延续——header 名与 host 的比较不再受LC_CTYPE影响。
  • 2.11.0:Utils::modifyRequest()拒绝在同一调用中同时修改 URI 与显式 Host 头;Header::parse()改用无重复前瞻的正则拆分分号参数;UriComparator::isCrossOrigin()仅为 HTTP/HTTPS 缺失端口隐式补默认端口。
  • 2.10.x:UriNormalizer的百分号编码归一化扩展到 fragment;LimitStream::getSize()在切片超出流末尾时返回 0;修复CachingStream的无限循环与回放静默损坏问题。
  • 2.9.x:MultipartStream支持嵌套数组展开;Message::bodySummary()修复多字节字符内截断返回null的问题。
  • 2.8.x:允许空列表作为 header 值;修复Uri::withQueryValue()中+号被解释为空格的问题(2.8.1);PHP 8.5 支持(2.8.0)。
  • 2.7.0:新增Utils::redactUserInfo();Query::build()支持把布尔编码为 1/0。
  • 2.6.x:修复 PHP 将数组键中的数字字符串转为 int 的问题;StreamWrapper::stream_stat()在内层流 size 为null时返回false。
  • 2.5.0:psr/http-message约束调整为^1.1 || ^2.0。

2.0.0 的基础框架

2.0.0(2021-06-30,与 RC 完全相同)是 1.x 时代的"现代化转折":新增 PSR-17 工厂、所有类声明为final、全面引入 PHP 7 类型提示;移除 PHP < 7.2 支持,并删除GuzzleHttp\Psr7命名空间下的全部函数(1.7.0 已把它们替换为静态方法)。2.1.0 还引入了专用异常MalformedUriException(见 src/Exception/MalformedUriException.php),它继承自InvalidArgumentException,保证向后兼容的同时让"URI 畸形"可被精确捕获。

1.x 时代:功能沉淀与历史遗产

1.x 记录了 PSR-7 生态早期最有影响力的能力建设,许多设计沿用至今:

  • 1.4.0(2017-02-21):按 RFC 3986 引入大量 URI 工具——Uri::isDefaultPort、Uri::isAbsolute、网络路径引用/绝对路径引用/相对路径引用/同文档引用判断、composeComponents,以及UriNormalizer::normalize/isEquivalent、UriResolver::relativize;同时把"非法 URI 修改"从静默容错改为抛异常,例如对带 authority 的 URI 设置不以/开头且非空的路径会直接抛错。
  • 1.3.x(2016):补齐ServerRequestInterface、UploadedFileInterface等剩余 PSR-7 接口;支持stream_for从标量构造;Uri允许继承。
  • 1.2.x(2015-2016):支持无 authority 的 URI、HTTP 451 状态码、'0'作为文件名、非标准端口进 Host 头;CachingStream支持前向 seek。
  • 1.1.0:URI 可为相对引用;multipart/form-data头部大小写不敏感覆盖;不再对缺失 scheme 且无端口的 URI 添加端口。
  • 1.0.0(2015-05-19):初始发布,当时尚未支持ServerRequestInterface与UploadedFileInterface。

1.x 时代的另一个遗产是Message::bodySummary()的迭代:从 1.5.1 的"仅可读时取摘要"、1.5.2 的"检查 body 大小",到 2.4.1 的"读取前回绕"、2.9.1 的"多字节截断安全",再到 3.0 的"恢复原始位置 + null 默认值",最终形态集中体现在 src/Message.php。

实战指引:如何解读与应用本 CHANGELOG

升级路径速查

  1. 从 1.x 升 2.x:把命名空间函数调用改写为静态方法(如copy_to_stream()→Utils::copyToStream());适配 PSR-17 工厂与final类限制;捕获MalformedUriException替代通用异常判断。
  2. 从 2.x 升 3.0:阅读 2.11.0/2.12.0 的Deprecated清单——凡在 2.x 中被标记弃用的传参(非字符串 header 值、空 header 数组、非字符串 query 值、非有限浮点数、依赖自动大写的请求方法、非法 URI scheme 等)在 3.0 都会被直接拒绝;确认 PHP 版本 ≥ 7.4 且psr/http-message为^2.0。
  3. 关注安全补丁:升级到 2.12.3+(或直接 3.0.0),可覆盖 GHSA-c2w2-prh8-qm98、GHSA-vm85-hxw5-5432、GHSA-hq7v-mx3g-29hw、GHSA-34xg-wgjx-8xph 四项公告涉及的校验问题。

在源码中验证版本行为

  • 想确认 3.0 的 Host 同步逻辑,可查看 src/Message.php 中toString()与hostHeaderFromUri();
  • 想确认超时异常链路,可追踪 src/Utils.php 中copyToStream()/hash()里的StreamTimeout::read调用与TimeoutException的抛出点;
  • 想确认 URI 严格校验,可阅读 src/Rfc3986.php 的isValidScheme()/isValidHost()/isValidPort()与 src/UriNormalizer.php 的常量位掩码定义;
  • 对应的行为均有测试覆盖,例如 tests/DiagnosticValueTest.php、tests/UtilsTest.php、tests/UriNormalizerTest.php,可用composer test(或仓库 Makefile 中的测试目标)在本地验证。

小结

guzzlehttp/psr7的 CHANGELOG 是一部浓缩的 PHP HTTP 生态演进史:1.x 补齐能力,2.x 奠定现代化与安全基线,3.0.0 则以"拒绝含糊、拒绝注入、拒绝非法输入"的姿态完成收束。对使用方而言,最大的价值不在于逐条记忆变更,而在于识别出三条主线——输入校验严格化、区域设置无关化(ASCII case folding)、超时与溢出显式化——它们既是每次安全公告的根源,也是 3.0 迁移时最需要自查的检查清单。升级时对照本文的版本速查表逐项排查,即可平稳完成从 1.x/2.x 到 3.0 的过渡。

  • 后端

【免费下载链接】psr7

PSR-7 HTTP message library

项目地址:https://gitcode.com/gh_mirrors/ps/psr7
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询