riimu / kit-urlparser
符合RFC 3986规范的URL解析库,包含PSR-7 Uri组件
Requires
- php: >=5.6.0
- psr/http-message: ^1.0
Suggests
- ext-intl: Required to parse URIs with IDNs
README
UrlParser 是一个PHP库,提供符合RFC 3986规范的URL解析器和符合PSR-7的URI组件。该库的目的是提供一个准确实现RFC规范的解析器,与内置函数parse_url()
不同,后者在某些细微方面与规范有差异。
该库有两个主要目的。第一个是提供解析URL的信息。为了实现这一点,库实现了PSR-7的标准URI处理接口,并提供了使从URL中检索常用信息更简单的方法。第二个目的是允许使用PSR-7标准接口修改URL,以及一些使某些任务更直接的方法。
虽然这个库主要打算用于解析URL,但解析是基于通用的URI语法的。因此,可以使用这个库来验证和解析任何其他类型的URI与通用语法的兼容性。库不对URL执行任何特定方案的验证。
除了默认的RFC 3986兼容模式之外,该库还提供了一些选项,允许解析包含UTF-8字符的URL,同时将它们转换为适当的百分编码和IDN ascii格式。
API文档可在以下位置找到: http://kit.riimu.net/api/urlparser/
要求
- 最低支持的PHP版本是5.6
- 该库依赖于以下外部PHP库
- psr/http-message (
^1.0
)
- psr/http-message (
- 该库依赖于以下PHP扩展
intl
(仅需要IDN支持)
安装
使用Composer安装
安装此库最简单的方法是使用Composer处理依赖项。为了通过Composer安装此库,请按照以下两个步骤操作
-
通过在你的项目根目录中运行Composer的命令行安装来获取
composer.phar
。 -
一旦运行了安装脚本,你应该在你的项目根目录中有一个
composer.phar
文件,然后你可以运行以下命令php composer.phar require "riimu/kit-urlparser:^2.1"
通过Composer安装此库后,您可以通过包含由Composer在安装过程中生成的vendor/autoload.php
文件来加载库。
将库作为依赖项添加
如果您已经熟悉如何使用Composer,您还可以通过将以下composer.json
文件添加到您的项目并运行composer install
命令来将库作为依赖项添加。
{ "require": { "riimu/kit-urlparser": "^2.1" } }
手动安装
如果您不想使用Composer来加载库,您也可以手动下载库。通过下载最新版本并提取src
文件夹到您的项目中。然后,您可以通过包含提供的src/autoload.php
文件来加载库类。
请注意,使用Composer还会自动下载其他所需的PHP库。如果您手动安装此库,您还需要提供这些其他所需的库。
使用方法
使用此库相对简单。该库提供了一个URL解析类UriParser
和一个不可变值对象类Uri
,用于表示URL。要解析URL,您可以将URL作为字符串提供给UriParser
中的parse()
方法,该方法返回一个由解析的URL生成的Uri
实例。
例如
<?php require 'vendor/autoload.php'; $parser = new \Riimu\Kit\UrlParser\UriParser(); $uri = $parser->parse('http://www.example.com'); echo $uri->getHost(); // Outputs 'www.example.com'
或者,您也可以完全不使用UriParser
,只需将URL作为构造函数参数提供给Uri
<?php require 'vendor/autoload.php'; $uri = new \Riimu\Kit\UrlParser\Uri('http://www.example.com'); echo $uri->getHost(); // Outputs 'www.example.com'
使用parse()
方法和构造函数之间的主要区别在于,如果提供的URL不是一个有效的URL,则parse()
方法将返回一个null
,而构造函数将抛出InvalidArgumentException
异常。
要从中检索不同类型的URL信息,Uri
类提供了各种不同的方法来帮助您。以下是一个概述不同可用方法的简单示例
<?php require 'vendor/autoload.php'; $parser = new \Riimu\Kit\UrlParser\UriParser(); $uri = $parser->parse('http://jane:pass123@www.example.com:8080/site/index.php?action=login&prev=index#form'); echo $uri->getScheme() . PHP_EOL; // outputs: http echo $uri->getUsername() . PHP_EOL; // outputs: jane echo $uri->getPassword() . PHP_EOL; // outputs: pass123 echo $uri->getHost() . PHP_EOL; // outputs: www.example.com echo $uri->getTopLevelDomain() . PHP_EOL; // outputs: com echo $uri->getPort() . PHP_EOL; // outputs: 8080 echo $uri->getStandardPort() . PHP_EOL; // outputs: 80 echo $uri->getPath() . PHP_EOL; // outputs: /site/index.php echo $uri->getPathExtension() . PHP_EOL; // outputs: php echo $uri->getQuery() . PHP_EOL; // outputs: action=login&prev=index echo $uri->getFragment() . PHP_EOL; // outputs: form print_r($uri->getPathSegments()); // [0 => 'site', 1 => 'index.php'] print_r($uri->getQueryParameters()); // ['action' => 'login', 'prev' => 'index']
Uri
组件也提供了各种修改URL的方法,允许您从单独的组件构造新的URL或修改现有的URL。请注意,Uri
组件是一个不可变值对象,这意味着每个修改方法都会返回一个新的Uri
实例,而不是修改现有的实例。以下是一个从组件构造URL的简单示例
<?php require 'vendor/autoload.php'; $uri = (new \Riimu\Kit\UrlParser\Uri()) ->withScheme('http') ->withUserInfo('jane', 'pass123') ->withHost('www.example.com') ->withPort(8080) ->withPath('/site/index.php') ->withQueryParameters(['action' => 'login', 'prev' => 'index']) ->withFragment('form'); // Outputs: http://jane:pass123@www.example.com:8080/site/index.php?action=login&prev=index#form echo $uri;
如前一个示例所示,Uri
组件还提供了一个__toString()
方法,该方法提供了URL字符串。
检索信息
以下是Uri
组件提供的用于从URL检索信息的方法列表
-
getScheme()
从URL返回方案或如果没有方案则为空字符串。 -
getAuthority()
返回URL中包含用户信息、主机名和端口的组件,格式为user-info@hostname:port
。 -
getUserInfo()
返回包含用户名和密码的组件,两者之间由冒号分隔。 -
getUsername()
返回URL中的解码用户名,如果URL中没有用户名则为空字符串。 -
getPassword()
返回URL中的解码密码,如果URL中没有密码则为空字符串。 -
getHost()
返回URL中的主机名,如果URL中没有主机则为空字符串。 -
getIpAddress()
如果主机是IP地址,则返回主机中的IP地址。如果不是IP地址,此方法将返回null
。如果提供了IPv6地址,则返回地址而不包含周围的括号。 -
getTopLevelDomain()
返回主机中的顶级域名。如果没有主机或主机是IP地址,则返回空字符串。 -
getPort()
返回URL中的端口号,如果URL中没有端口号则为null
。如果端口号是当前方案的标准端口号(例如,http的80),则此方法也将返回null
。 -
getStandardPort()
返回当前方案的标准端口号。如果没有方案或方案的标准端口号未知,则返回null
。 -
getPath()
返回URL中的路径,如果URL中没有路径则为空字符串。 -
getPathSegments()
返回一个解码后的路径段数组(即每个正斜杠分割的路径)。空路径段会被丢弃,不包含在返回的数组中。 -
getPathExtension()
从路径返回文件扩展名,或者如果没有路径则返回空字符串。 -
getQuery()
返回 URL 的查询字符串,如果没有查询字符串则返回空字符串。 -
getQueryParameters()
使用parse_str()
函数解析 URL 的查询字符串,并返回解析值数组。 -
getFragment()
返回 URL 的片段,如果没有片段则返回空字符串。 -
__toString()
返回 URL 的字符串表示形式。
修改 URL
Uri
组件提供了各种方法,可用于修改 URL 和构建新的 URL。请注意,由于 Uri
类是一个不可变值对象,每个方法都返回一个新的 Uri
实例,而不是修改现有的实例。
-
withScheme($scheme)
返回具有给定方案的新的实例。可以使用空方案从 URL 中删除方案。注意,任何提供的方案都会被转换为小写。 -
withUserInfo($user, $password = null)
返回具有给定用户名和密码的新实例。请注意,除非提供了用户名,否则密码会被忽略。可以使用空用户名从 URL 中删除用户名和密码。任何不能单独插入 URL 的字符都会进行百分号编码。 -
withHost($host)
返回具有给定主机的新实例。可以使用空主机从 URL 中删除主机。注意,此方法不接受国际域名。注意,此方法还将主机转换为小写。 -
withPort($port)
返回具有给定端口的新的实例。可以使用null
从 URL 中删除端口。 -
withPath($path)
返回具有给定路径的新实例。可以使用空路径从 URL 中删除路径。注意,任何不是有效路径字符的字符都会在 URL 中进行百分号编码。但是,现有的百分号编码字符不会进行双重编码。 -
withPathSegments(array $segments)
返回一个具有从路径段数组构造的路径的新实例。段中的所有无效路径字符(包括正斜杠和现有的百分号编码字符)都会进行百分号编码。 -
withQuery($query)
返回具有给定查询字符串的新实例。可以使用空查询字符串从 URL 中删除路径。注意,任何不是有效查询字符串字符的字符都会在 URL 中进行百分号编码。但是,现有的百分号编码字符不会进行双重编码。 -
withQueryParameters(array $parameters)
返回使用http_build_query()
函数从提供的参数构造查询字符串的新实例。参数中的所有无效查询字符串字符(包括和号、等号和现有的百分号编码字符)都会进行百分号编码。 -
withFragment($fragment)
返回具有给定片段的新实例。可以使用空字符串从 URL 中删除片段。注意,任何不是有效片段字符的字符都会在 URL 中进行百分号编码。但是,现有的百分号编码字符不会进行双重编码。
UTF-8 和国际域名
默认情况下,此库提供了一个符合 RFC 3986 规范的解析器。RFC 规范不允许在域名或其他 URL 部分中使用 UTF-8 字符。这些字符在 URL 中的正确表示是使用 IDN 标准表示域名,并在其他部分中对 UTF-8 字符进行百分号编码。
然而,为了帮助您处理UTF-8编码的字符,Uri
组件中的许多方法会自动对无法单独插入URL的任何字符进行百分号编码,包括UTF-8字符。然而,由于涉及到的复杂性,withHost()
方法不允许UTF-8编码的字符。
默认情况下,解析器也不解析包含UTF-8编码字符的任何URL,因为这会违反RFC规范。但是,解析器提供了两种额外的解析模式,在可能的情况下允许这些字符。
如果您希望解析可能包含UTF-8字符的用户信息(即用户名或密码)、路径、查询或片段组件的URL,您只需使用UTF-8解析模式。例如
<?php require 'vendor/autoload.php'; $parser = new \Riimu\Kit\UrlParser\UriParser(); $parser->setMode(\Riimu\Kit\UrlParser\UriParser::MODE_UTF8); $uri = $parser->parse('http://www.example.com/föö/bär.html'); echo $uri->getPath(); // Outputs: /f%C3%B6%C3%B6/b%C3%A4r.html
然而,域名中的UTF-8字符是一个更为复杂的问题。但是,解析器提供了一种基本的IDNA模式来解析这些域名。例如
<?php require 'vendor/autoload.php'; $parser = new \Riimu\Kit\UrlParser\UriParser(); $parser->setMode(\Riimu\Kit\UrlParser\UriParser::MODE_IDNA); $uri = $parser->parse('http://www.fööbär.com'); echo $uri->getHost(); // Outputs: www.xn--fbr-rla2ga.com
请注意,使用此解析模式需要启用PHP扩展intl
。也可以通过Uri
组件构造函数的第二个参数提供适当的解析模式。
尽管支持解析这些UTF-8字符,但此库不提供任何反向操作的方法,因为此库的目的是处理符合RFC 3986的URI。
URL规范化
由于RFC 3986规范定义了一些URL,尽管有细微的差异,但它们是等效的,因此此库对提供的值进行了一些最小规范化。您可能会在例如解析用户提供的URL时遇到这些实例。您可能会遇到的最显著的规范化如下
scheme
和host
组件被视为不区分大小写。因此,这些组件总是被规范化为小写。- 如果端口号是当前方案的默认端口号,则不会将其包含在
getAuthority()
和__toString()
返回的字符串中。 - 百分号编码以不区分大小写的方式处理。因此,此库将十六进制字符规范化为大写。
- 返回字符串中路径开头的正斜杠数量可能会根据URL是否具有
authority
组件而改变。 - 由于
UriParser
与PSR-7规范一起工作,该规范不提供提供编码的用户名或密码的方式,因此解析和生成的URI中userinfo
组件中的百分号编码字符可能会有所不同。
致谢
此库版权所有(c)2013-2022 Riikka Kalliomäki。
请参阅LICENSE以获取许可和复制信息。