exteon/uri

一组用于解析、组合和操作 URI 的对象

2.0.3 2022-07-19 14:08 UTC

This package is auto-updated.

Last update: 2024-09-20 03:13:04 UTC


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 foofoo/ 组合将分别产生 barfoo/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。