当前位置:首页 > 文章列表 > 文章 > php教程 > PHP 8.5 Uri 类怎样规范化 URL

PHP 8.5 Uri 类怎样规范化 URL

来源:17golang原创 2026-11-03 09:11:40 0浏览 收藏

在 PHP 8.5 中,处理 URL 不必再把 parse_url() 返回的数组和一串字符串替换拼在一起。URI 扩展提供了 Uri\\Rfc3986\\Uri 与 Uri\\WhatWg\\Url 两套对象模型:前者按 RFC 3986 处理通用 URI,后者按 WHATWG URL Standard 处理浏览器语境中的 URL。要把输入整理成稳定、可比较的 URI 字符串,通常从 Uri\\Rfc3986\\Uri 开始。

官方地址:https://www.php.net/manual/en/book.uri.php

规范化 URL 的关键不是“把字符串变漂亮”,而是先选定解析标准,再让 Uri 对象负责组件标准化;需要保留输入的原始编码时,使用 toRawString(),需要稳定表示时使用 toString()。

PHP 官方手册说明,PHP 8.5 新增的 URI 扩展实现 RFC 3986 和 WHATWG URL Standard。下面只围绕 URL 规范化、字段读取、等价比较和方案选择展开,不把它扩展成网络请求或完整业务校验教程。

先分清“规范化”与“原样重组”

Uri\\Rfc3986\\Uri 是只读对象。构造对象后,getScheme()、getHost()、getPath() 等方法读取的是规范化后的组件;toString() 把这些组件重新组成规范化 URI,toRawString() 则尽量保留输入中的原始表示。

RFC 3986 规范化包含几个容易混淆的细节:scheme 和 host 会转为小写,百分号编码中的十六进制字母会统一为大写,百分号编码的非保留字符可以解码,路径中的 dot segment 会被移除。它不是“所有 URL 都按浏览器地址栏规则处理”,所以不能拿这套结果替代 WHATWG URL 语义。

PHP Uri Rfc3986 Uri 将 URL 组件映射为规范化字符串与原始字符串的静态结构说明图
图1:PHP Uri\\Rfc3986\\Uri 规范化 URL 的结构示意图,不是截图或运行证据。

用 Uri\\Rfc3986\\Uri 生成规范化 URL

最小用法是把输入传给构造函数,再分别读取结构化字段和两个字符串表示。下面的示例故意同时保留规范化结果和原始结果,方便你在日志、缓存键或审计记录中按用途选择。

toString();

    // toRawString() 面向保留原始编码的场景,不要把它当成规范化结果。
    $raw = $uri->toRawString();

    // 结构化读取比手动切分字符串更容易对应 RFC 3986 的组件。
    printf("scheme=%s host=%s path=%s\n", $uri->getScheme(), $uri->getHost(), $uri->getPath());
    printf("normalized=%s\nraw=%s\n", $normalized, $raw);
} catch (\Uri\InvalidUriException $exception) {
    // 输入不符合 RFC 3986 时记录原因,由调用方决定拒绝、提示或回退。
    error_log('URI parse failed: ' . $exception->getMessage());
}

示例中的重点是对象职责:业务代码不需要先调用 strtolower(),也不应该用 str_replace() 猜测路径中的 .. 应该如何处理。规范化后的 host、scheme 和 path 由 URI 规则统一决定。异常处理也要保留,因为“能被字符串函数拼出来”不等于“能被指定标准接受”。

字段读取和字符串输出要按用途分开

如果业务只是展示或转发 URL,toString() 往往足够;如果需要把域名、路径或查询参数映射到不同字段,就直接调用组件方法。官方手册列出了 scheme、host、port、path、query、fragment、username 等读取接口,并同时提供对应的 raw 方法。

这一区分对缓存键尤其重要。缓存键需要稳定时可以使用规范化字符串,但如果系统还要回显用户输入、保留签名原文或记录代理层的原始编码,就应把 raw 表示单独保存,不能用规范化字符串覆盖审计需要的原始值。

 $uri->getScheme(),
    'host' => $uri->getHost(),
    'path' => $uri->getPath(),
    'query' => $uri->getQuery(),
    'fragment' => $uri->getFragment(),
];

// JSON 只负责展示结构,不改变 Uri 对象本身的只读性质。
echo json_encode($parts, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);

// 需要保留输入样式时,原始组件要从 raw 方法读取。
echo $uri->getRawPath();

不要把 getQuery() 当成“已经按业务规则排序的参数表”。它返回的是 URI 组件,不会替你决定参数重复、参数顺序或业务签名规则。若应用的签名算法规定查询参数排序和编码方式,应在明确的签名层实现,而不是把 Uri 的规范化误认为业务 canonicalization。

等价比较时明确是否包含 fragment

URI 对象还提供 equals()。默认比较模式排除 fragment,这一点适合很多服务端资源判断,因为 fragment 通常只在客户端定位文档内部位置;如果你的业务把 fragment 作为资源身份的一部分,就要显式选择包含它的比较模式。

equals($right);

// 显式包含 fragment,适合把页面锚点也纳入身份的场景。
$sameDocumentLocation = $left->equals(
    $right,
    \Uri\UriComparisonMode::IncludeFragment
);

var_dump($sameResource, $sameDocumentLocation);

这里的选择是业务语义,不是哪个常量“更严格”。静态资源缓存、接口去重和后端权限判断通常关注不含 fragment 的 URI;前端文档锚点或需要精确复现位置的场景,才应把 fragment 纳入比较。

parse_url、RFC 3986 Uri 和 WHATWG Url 怎么选

PHP 8.5 并不是简单地把 parse_url() 换了一个类名。三种方案的结果模型和标准不同:parse_url() 返回历史兼容的数组;Uri\\Rfc3986\\Uri 提供遵循 RFC 3986 的只读对象;Uri\\WhatWg\\Url 则面向 WHATWG URL Standard,并提供 ASCII 或 Unicode 主机等 URL 语境接口。

PHP parse_url RFC 3986 Uri 和 WHATWG Url 的标准与适用边界静态对比图
图2:PHP 三种 URL 处理方案的适用边界示意图,不是截图或运行证据。
方案结果形态适合的边界不应直接假设
parse_url()数组或单个组件需要兼容既有代码和既有返回结构它不是 RFC 3986 与 WHATWG 的统一实现
Uri\\Rfc3986\\Uri只读 URI 对象服务端通用 URI、规范化、结构化比较它不等于浏览器地址栏的 WHATWG 解析
Uri\\WhatWg\\Url只读 URL 对象需要 WHATWG URL 语义、Unicode/ASCII 主机处理它不应被当作 RFC 3986 的结果

如果是新写的服务端代码,且目标是按通用 URI 标准得到稳定字符串,优先使用 Uri\\Rfc3986\\Uri。如果代码在处理浏览器表单、前端 URL 或 WHATWG 兼容行为,就选择 Uri\\WhatWg\\Url。如果旧系统大量依赖数组键名、空值行为或历史异常边界,先保留 parse_url(),再用测试覆盖迁移差异。

哪些场景不适合直接替换旧代码

第一种情况是兼容性:项目仍运行在 PHP 8.4 或更低版本时,不能只改命名空间就使用 PHP 8.5 的 URI 类。第二种情况是标准依赖:旧代码可能故意依赖 parse_url() 的历史行为,替换后数组访问、缺失组件和错误处理方式都会变化。第三种情况是业务校验:URI 规范化解决的是解析和重组,不自动完成允许域名、协议白名单、端口策略或 SSRF 防护。

尤其不要用“先解析、再拼接字符串”的方式绕过标准差异。安全边界应在解析标准确定后建立:同一套规则负责提取 host,后续 allowlist、DNS 解析、请求策略和审计记录也要明确使用哪一种表示。否则,校验阶段与真正发请求的阶段采用不同解析器,仍可能出现判断不一致。

一张表确定落地方案

你的目标建议入口理由
生成稳定的 RFC 3986 URI 字符串Uri\\Rfc3986\\Uri::toString()由对象统一处理组件规范化和重组
保留用户输入的原始编码toRawString() 或 raw 组件方法规范化输出不应覆盖展示与审计需要的原文
比较服务端资源是否相同equals() 默认模式默认不把 fragment 纳入比较
处理浏览器 URL 语义Uri\\WhatWg\\Url标准边界与 RFC 3986 不同,不能混用结果
保持旧数组接口不变parse_url()优先保证既有调用方兼容,再规划迁移

最终可以把决策压缩成一句话:先确定 URL 需要遵循 RFC 3986 还是 WHATWG,再选择对应的 Uri 类;只有在旧行为本身就是兼容要求时,才继续保留 parse_url()。规范化字符串、原始字符串和业务 canonicalization 也要分成三个概念管理。

toString() 会不会保留 URL 的原始大小写?

不应这样假设。RFC 3986 Uri 的规范化字符串会按规则处理 scheme、host、百分号编码和路径点段;如果需要保留输入表示,应使用 raw 方法。

能不能用 Uri 类直接验证域名是否允许访问?

不能。Uri 类负责按指定标准解析和重组;允许域名、端口、协议以及网络访问安全仍需由应用自己的策略层处理。

为什么不把所有项目都改成 WHATWG Url?

因为 WHATWG 和 RFC 3986 面向的语境不同。浏览器 URL 兼容性是 WHATWG 的优势,服务端通用 URI 规范化则通常更适合 RFC 3986。迁移前要看调用方真正依赖的标准。

本文依据 PHP 官方 URI 手册、Uri\\Rfc3986\\Uri 类文档、toString() 文档、parse_url() 文档和 PHP 8.5 发布说明整理:https://www.php.net/manual/en/book.uri.php、https://www.php.net/manual/en/class.uri-rfc3986-uri.php、https://www.php.net/manual/en/uri-rfc3986-uri.tostring.php、https://www.php.net/manual/en/function.parse-url.php。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Redis 8.10 命令文档怎样帮助客户端做能力探测Redis 8.10 命令文档怎样帮助客户端做能力探测
上一篇
Redis 8.10 命令文档怎样帮助客户端做能力探测
PHP 8.5 UriUrl 怎样读取查询参数
下一篇
PHP 8.5 UriUrl 怎样读取查询参数
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    856次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    860次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    938次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    914次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    746次使用