exteon / uri
一组用于解析、组合和操作 URI 的对象
Requires (Dev)
- phpunit/phpunit: ^8.5
README
提供一组用于解析、组合和操作 URI 的对象
解析 URI 字符串
use Exteon\Uri\Uri; $uri = Uri::fromString('http://user:pass@foo.bar:8080/path/to?query#fragment'); var_dump( $uri->getScheme(), $uri->getUser(), $uri->getPass(), $uri->getHost(), $uri->getPort(), $uri->getPath(), $uri->getQueryString(), $uri->getFragment() );
生成 URI 字符串
use Exteon\Uri\Uri; $uri = new Uri( 'http', 'foo.bar', '8080', 'user', 'pass', 'path/to', 'query', 'fragment' ); var_dump($uri->toString());
注意
未实现神奇的 __toString()
方法,我认为它的语义不一致,因此请使用显式的 toString()
。
URI 操作
注意
Uri
对象不是不可变的;在进行操作之前,请确保在适当的地方使用 clone
。
设置器
您可以使用 setScheme(), setUser(), setPass(), setHost(), setPort(), setPath(), setQueryString(), setFragment()
设置器来修改 URI。
基础和相对 URL,组合
Uri
对象可以用来将相对 URI 组合到基础 URI。
use Exteon\Uri\Uri; $baseUri = Uri::fromString('scheme://host/root/?query#fragment'); $uri = Uri::fromString('a'); $uri->composeWithBase($baseUri); echo $uri->toString(); // scheme://host/root/a $uri = Uri::fromString('/a'); $uri->composeWithBase($baseUri); echo $uri->toString(); // scheme://host/a $uri = Uri::fromString('://host2/a'); $uri->composeWithBase($baseUri); echo $uri->toString(); // scheme://host2/a $uri = Uri::fromString(''); $uri->composeWithBase($baseUri); echo $uri->toString(); // scheme://host/root/?query#fragment $uri = Uri::fromString('#fragment2'); $uri->composeWithBase($baseUri); echo $uri->toString(); // scheme://host/root/?query#fragment2 $uri = Uri::fromString('?query2'); $uri->composeWithBase($baseUri); echo $uri->toString(); // scheme://host/root/?query2 $uri = Uri::fromString('?query2#fragment2'); $uri->composeWithBase($baseUri); echo $uri->toString(); // scheme://host/root/?query2#fragment2 $baseUri = Uri::fromString('scheme://host/root/a?query#fragment'); $uri = Uri::fromString('b'); $uri->composeWithBase($baseUri); echo $uri->toString(); // scheme://host/root/b
composeWithBase()
的逆操作是 applyRelative()
,当在基础 URI 上以相对 URI 作为参数运行时,它是非常对称的。
相对 URL 也可以从绝对 URL 和基础 URL 中导出
use Exteon\Uri\Uri; $baseUri = Uri::fromString('scheme://host/a/b?query#fragment'); $uri = Uri::fromString('scheme://host/a/b?query#fragment'); $uri->makeRelativeToBase($baseUri); echo $uri->toString(); // $uri = Uri::fromString('scheme://host/a/b?query'); $uri->makeRelativeToBase($baseUri); echo $uri->toString(); // # $uri = Uri::fromString('scheme://host/a/b'); $uri->makeRelativeToBase($baseUri); echo $uri->toString(); // ? $uri = Uri::fromString('scheme://host/a/b#fragment'); $uri->makeRelativeToBase($baseUri); echo $uri->toString(); // ?#fragment $uri = Uri::fromString('scheme://host/a/b?query#fragment2'); $uri->makeRelativeToBase($baseUri); echo $uri->toString(); // #fragment2 $uri = Uri::fromString('scheme://host/a/b?query2#fragment'); $uri->makeRelativeToBase($baseUri); echo $uri->toString(); // ?query2#fragment $uri = Uri::fromString('scheme://host/a/c?query#fragment'); $uri->makeRelativeToBase($baseUri); echo $uri->toString(); // c?query#fragment $uri = Uri::fromString('scheme://host/a?query#fragment'); $uri->makeRelativeToBase($baseUri); echo $uri->toString(); // /a?query#fragment $uri = Uri::fromString('scheme://host2/a/b?query#fragment'); $uri->makeRelativeToBase($baseUri); echo $uri->toString(); // ://host2/a/b?query#fragment $baseUri = Uri::fromString('scheme:a/b'); $uri = Uri::fromString('scheme:a'); $uri->makeRelativeToBase($baseUri); echo $uri->toString(); // :a
注意
Uri
将允许解析和生成形式为 ://host/path
的相对空方案 URI,这些 URI 在 RFC 3986 中是不允许的,但在浏览器 URL 中是常见的,用于指定“与浏览页面相同的协议”。
注意
请注意路径中的尾部 /
;该库使用浏览器组合算法:一个相对 URL bar
与基础 URL foo
和 foo/
组合将分别产生 bar
和 foo/bar
。此例外是 UnixPathUri
。
ascend()
和 descend()
虽然 RFC 3986 中没有出现,但 URI 的路径部分已成为一种非常通用的约定,即通过 /
分隔的分层组织组件的序列。为了满足这一约定,所有 URI 对象都实现了 ascend()
和 descend()
函数。
public function ascend(int $levels = 1): self;
use Exteon\Uri\Uri; $uri = Uri::fromString('a/b?qs'); $uri->ascend(); var_dump($uri->toString()); // a/
注意
使用 ascend()
时,生成的 URI 总是会被视为目录,并且有尾部斜杠。
public function descend(string $path): self;
use Exteon\Uri\Uri; $uri = Uri::fromString('a/b?qs'); $uri->descend('c/d'); var_dump($uri->toString()); // a/c/d
注意
使用 descend()
时,Web 协议,将递归路径应用于 URI 目录,如上面的示例所示。因为 a/b
不包含尾部斜杠,所以目录部分是 a/
,然后将 c/d
应用到其中。
上述描述的例外是 UnixPathUri
。
PHP URI
使用 Uri
,查询字符串没有被赋予任何特殊含义。您可以使用 PHPUri
对象来解析和生成 PHP 查询字符串
use Exteon\Uri\PhpUri; $initial = '?foo=bar'; $uri = PhpUri::fromString($initial); var_dump($uri->getQuery()); // ['foo' => 'bar']
use Exteon\Uri\PhpUri; $uri = new PhpUri(); $uri->setQuery(['foo' => 'bar']); echo $uri->toString(); // ?foo=bar
注意
PHP 的 http_build_query()
在查询字符串聚合时静默丢弃 NULL 值的键。为了保持一致性,您必须显式处理 NULL 值。为此,PHPUri
提供了两个辅助方法:nullValuesToEmptyString()
和 nullValuesUnset()
(默认 PHP 行为),您可以在将查询传递给构造函数或 setQuery()
之前使用这些方法。如果传递给 setQuery()
的数组包含 NULL 值,则将抛出 InvalidArgumentException
。
Unix 路径 URI
UnixPathUri
模型了一个只能有路径部分(没有方案、主机、查询字符串、片段)的 URI。它们可以像 Web URI 一样组合,但有一个相当重要的不同约定。
对于UnixPathUri
,即使URI没有尾部斜杠,getDirectory()
和getPath()
也表示相同的资源。
示例
use Exteon\Uri\UnixPathUri; $uri = UnixPathUri::fromString('/a/b'); var_dump($uri->getPath()); // /a/b var_dump($uri->getDirectory()); // /a/b/ // Uri::getDirectory() would have been "/a/"
这将对相对URI的应用和派生方式产生影响。例如
use Exteon\Uri\UnixPathUri; $base = UnixPathUri::fromString('/a'); $relative = UnixPathUri::fromString('b'); $relative->composeWithBase($base); var_dump($relative->toString()); // /a/b // With Uri, the result would have been "/b"
以更直观的方式,UnixPathUri
URI类型就像Unix shell路径一样,相对URI就像在基本URI上运行cd
命令。显然没有实现特殊的路径片段如.
和..
,你可以使用ascend()
方法来模拟进入上级目录。
UnixPathUri
可以与其他类型的URI结合(即相对UnixPathUri
可以通过Uri::applyRelative()
与根WebUri
结合),从而得到完整的Web URI。