guzzlehttp7 / psr
PSR-7消息实现,同时提供常用实用方法
Requires
- php: >=5.4.0
- psr/http-message: ~1.0
- ralouphie/getallheaders: ^2.0.5 || ^3.0.0
Requires (Dev)
- ext-zlib: *
- phpunit/phpunit: ~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10
Suggests
- laminas/laminas-httphandlerrunner: Emit PSR-7 responses
Provides
This package is not auto-updated.
Last update: 2024-09-10 07:17:14 UTC
README
此仓库包含完整的PSR-7消息实现,几个流装饰器,以及一些有用的功能,如查询字符串解析。
流实现
此包包含多个流实现和流装饰器。
AppendStream
GuzzleHttp\Psr7\AppendStream
从多个流中读取,一个接一个。
use GuzzleHttp\Psr7;
$a = Psr7\Utils::streamFor('abc, ');
$b = Psr7\Utils::streamFor('123.');
$composed = new Psr7\AppendStream([$a, $b]);
$composed->addStream(Psr7\Utils::streamFor(' Above all listen to me'));
echo $composed; // abc, 123. Above all listen to me.
BufferStream
GuzzleHttp\Psr7\BufferStream
提供可以写入以填充缓冲区并从其中读取以移除字节的缓冲区流。
此流返回一个“hwm”元数据值,告诉上游消费者流的配置高水位标记是什么,或者缓冲区的最大首选大小。
use GuzzleHttp\Psr7;
// When more than 1024 bytes are in the buffer, it will begin returning
// false to writes. This is an indication that writers should slow down.
$buffer = new Psr7\BufferStream(1024);
CachingStream
CachingStream用于允许在不可寻址的流上对之前读取的字节进行寻址。这在需要重绕流(例如,由于重定向导致)时传输不可寻址的实体体失败时非常有用。从远程流读取的数据将被缓存在PHP临时流中,以便首先在内存中缓存已读取的字节,然后在磁盘上。
use GuzzleHttp\Psr7;
$original = Psr7\Utils::streamFor(fopen('http://www.google.com', 'r'));
$stream = new Psr7\CachingStream($original);
$stream->read(1024);
echo $stream->tell();
// 1024
$stream->seek(0);
echo $stream->tell();
// 0
DroppingStream
GuzzleHttp\Psr7\DroppingStream
当底层流的大小变得过大时开始丢弃数据的流装饰器。
use GuzzleHttp\Psr7;
// Create an empty stream
$stream = Psr7\Utils::streamFor();
// Start dropping data when the stream has more than 10 bytes
$dropping = new Psr7\DroppingStream($stream, 10);
$dropping->write('01234567890123456789');
echo $stream; // 0123456789
FnStream
GuzzleHttp\Psr7\FnStream
基于函数哈希组合流实现。
允许在不需要为简单的扩展点创建具体类的情况下轻松测试和扩展提供的流。
use GuzzleHttp\Psr7;
$stream = Psr7\Utils::streamFor('hi');
$fnStream = Psr7\FnStream::decorate($stream, [
'rewind' => function () use ($stream) {
echo 'About to rewind - ';
$stream->rewind();
echo 'rewound!';
}
]);
$fnStream->rewind();
// Outputs: About to rewind - rewound!
InflateStream
GuzzleHttp\Psr7\InflateStream
使用PHP的zlib.inflate过滤器来解压缩deflate或gzip内容。
此流装饰器跳过给定流的第一个10个字节以删除gzip头,将提供的流转换为PHP流资源,然后附加zlib.inflate过滤器。然后将流转换回Guzzle流资源,以便用作Guzzle流。
LazyOpenStream
GuzzleHttp\Psr7\LazyOpenStream
在流上进行IO操作之后才懒洋洋地读取或写入文件。
use GuzzleHttp\Psr7;
$stream = new Psr7\LazyOpenStream('/path/to/file', 'r');
// The file has not yet been opened...
echo $stream->read(10);
// The file is opened and read from only when needed.
LimitStream
GuzzleHttp\Psr7\LimitStream
LimitStream可用于读取现有流对象的子集或切片。这对于将大文件分成更小的部分以便分块发送非常有用(例如,Amazon S3的多部分上传API)。
use GuzzleHttp\Psr7;
$original = Psr7\Utils::streamFor(fopen('/tmp/test.txt', 'r+'));
echo $original->getSize();
// >>> 1048576
// Limit the size of the body to 1024 bytes and start reading from byte 2048
$stream = new Psr7\LimitStream($original, 1024, 2048);
echo $stream->getSize();
// >>> 1024
echo $stream->tell();
// >>> 0
MultipartStream
GuzzleHttp\Psr7\MultipartStream
当读取时返回流式多部分或multipart/form-data流的字节的流。
NoSeekStream
GuzzleHttp\Psr7\NoSeekStream
NoSeekStream包装了一个流,不允许寻址。
use GuzzleHttp\Psr7;
$original = Psr7\Utils::streamFor('foo');
$noSeek = new Psr7\NoSeekStream($original);
echo $noSeek->read(3);
// foo
var_export($noSeek->isSeekable());
// false
$noSeek->seek(0);
var_export($noSeek->read(3));
// NULL
PumpStream
GuzzleHttp\Psr7\PumpStream
提供一个只读流,可以从PHP可调用对象中泵送数据。
调用提供的可调用对象时,PumpStream将传递请求读取的数据量。可调用对象可以选择忽略此值并返回少于或多于请求的字节数。提供的可调用对象返回的任何额外数据都将在内部缓冲,直到使用PumpStream的read()函数排空。提供的可调用对象在没有更多数据可读时必须返回false。
实现流装饰器
由于存在GuzzleHttp\Psr7\StreamDecoratorTrait
,创建流装饰器非常简单。此特质提供了一些方法,通过代理到底层流来实现Psr\Http\Message\StreamInterface
。只需使用StreamDecoratorTrait
并实现您自己的方法即可。
例如,假设我们希望在每次从流中读取最后一个字节时调用特定的函数。这可以通过重写read()
方法来实现。
use Psr\Http\Message\StreamInterface;
use GuzzleHttp\Psr7\StreamDecoratorTrait;
class EofCallbackStream implements StreamInterface
{
use StreamDecoratorTrait;
private $callback;
public function __construct(StreamInterface $stream, callable $cb)
{
$this->stream = $stream;
$this->callback = $cb;
}
public function read($length)
{
$result = $this->stream->read($length);
// Invoke the callback when EOF is hit.
if ($this->eof()) {
call_user_func($this->callback);
}
return $result;
}
}
可以将此装饰器添加到任何现有的流中,并按如下方式使用:
use GuzzleHttp\Psr7;
$original = Psr7\Utils::streamFor('foo');
$eofStream = new EofCallbackStream($original, function () {
echo 'EOF!';
});
$eofStream->read(2);
$eofStream->read(1);
// echoes "EOF!"
$eofStream->seek(0);
$eofStream->read(3);
// echoes "EOF!"
PHP StreamWrapper
如果您需要将PSR-7流用作PHP流资源,可以使用GuzzleHttp\Psr7\StreamWrapper
类。
使用GuzzleHttp\Psr7\StreamWrapper::getResource()
方法从PSR-7流创建PHP流。
use GuzzleHttp\Psr7\StreamWrapper;
$stream = GuzzleHttp\Psr7\Utils::streamFor('hello!');
$resource = StreamWrapper::getResource($stream);
echo fread($resource, 6); // outputs hello!
静态API
在GuzzleHttp\Psr7
命名空间下提供了各种静态方法。
GuzzleHttp\Psr7\Message::toString
public static function toString(MessageInterface $message): string
返回HTTP消息的字符串表示形式。
$request = new GuzzleHttp\Psr7\Request('GET', 'http://example.com');
echo GuzzleHttp\Psr7\Message::toString($request);
GuzzleHttp\Psr7\Message::bodySummary
public static function bodySummary(MessageInterface $message, int $truncateAt = 120): string|null
获取消息体的简短摘要。
如果响应不可打印,则返回null
。
GuzzleHttp\Psr7\Message::rewindBody
public static function rewindBody(MessageInterface $message): void
尝试重置消息体,并在失败时抛出异常。
只有当对tell()
的调用返回一个值,而不是0
时,才会重置消息体。
GuzzleHttp\Psr7\Message::parseMessage
public static function parseMessage(string $message): array
将HTTP消息解析为关联数组。
数组包含“start-line”键,包含消息的开始行,包含头数组值的关联数组的“headers”键,以及包含消息体的“body”键。
GuzzleHttp\Psr7\Message::parseRequestUri
public static function parseRequestUri(string $path, array $headers): string
为HTTP请求消息构造URI。
GuzzleHttp\Psr7\Message::parseRequest
public static function parseRequest(string $message): Request
将请求消息字符串解析为请求对象。
GuzzleHttp\Psr7\Message::parseResponse
public static function parseResponse(string $message): Response
将响应消息字符串解析为响应对象。
GuzzleHttp\Psr7\Header::parse
public static function parse(string|array $header): array
解析包含分号分隔数据的头值数组,将其解析为表示头键值对的关联数组的数组。如果一个参数不包含值,只包含键,此函数将注入一个带有空字符串值的键。
GuzzleHttp\Psr7\Header::normalize
public static function normalize(string|array $header): array
将可能包含逗号分隔头的头值数组转换为不包含逗号分隔值的头数组。
GuzzleHttp\Psr7\Query::parse
public static function parse(string $str, int|bool $urlEncoding = true): array
将查询字符串解析为关联数组。
如果找到相同键的多个值,该键值对的值将变成数组。此函数不将嵌套PHP样式数组解析为关联数组(例如,foo[a]=1&foo[b]=2
将被解析为['foo[a]' => '1', 'foo[b]' => '2']
)。
GuzzleHttp\Psr7\Query::build
public static function build(array $params, int|false $encoding = PHP_QUERY_RFC3986): string
从键值对数组构建查询字符串。
此函数可以使用parse()
的返回值来构建查询字符串。此函数在遇到数组时不会修改提供的键(例如,http_build_query()
会这样做)。
GuzzleHttp\Psr7\Utils::caselessRemove
public static function caselessRemove(iterable
从数据中按不区分大小写的方式移除给定的键。
GuzzleHttp\Psr7\Utils::copyToStream
public static function copyToStream(StreamInterface $source, StreamInterface $dest, int $maxLen = -1): void
将一个流的内容复制到另一个流中,直到读取到指定数量的字节。
GuzzleHttp\Psr7\Utils::copyToString
public static function copyToString(StreamInterface $stream, int $maxLen = -1): string
将一个流的内容复制到字符串中,直到读取到指定数量的字节。
GuzzleHttp\Psr7\Utils::hash
public static function hash(StreamInterface $stream, string $algo, bool $rawOutput = false): string
计算流的一个哈希值。
此方法读取整个流来计算滚动哈希,基于PHP的hash_init
函数。
GuzzleHttp\Psr7\Utils::modifyRequest
public static function modifyRequest(RequestInterface $request, array $changes): RequestInterface
克隆并修改一个请求,使用给定的更改。
此方法对于减少修改消息所需的克隆数量非常有用。
- method: (string) 改变HTTP方法。
- set_headers: (array) 设置给定头。
- remove_headers: (array) 删除给定头。
- body: (mixed) 设置给定体。
- uri: (UriInterface) 设置URI。
- query: (string) 设置URI的查询字符串值。
- version: (string) 设置协议版本。
GuzzleHttp\Psr7\Utils::readLine
public static function readLine(StreamInterface $stream, int $maxLength = null): string
从流中读取一行,直到最大允许的缓冲区长度。
GuzzleHttp\Psr7\Utils::streamFor
public static function streamFor(resource|string|null|int|float|bool|StreamInterface|callable|\Iterator $resource = '', array $options = []): StreamInterface
根据输入类型创建一个新的流。
选项是一个关联数组,可以包含以下键
- metadata: 自定义元数据数组。
- size: 流的大小。
此方法接受以下 $resource
类型
Psr\Http\Message\StreamInterface
: 返回值保持不变。string
: 创建一个使用给定字符串作为内容的流对象。resource
: 创建一个包装给定PHP流资源的流对象。Iterator
: 如果提供的值实现了Iterator
,则创建一个包装给定可迭代的只读流对象。每次从流中读取时,迭代器中的数据将填充一个缓冲区,并将连续调用,直到缓冲区等于请求的读取大小。后续的读取调用将首先从缓冲区中读取,然后对底层迭代器的next
调用,直到迭代器耗尽。object
with__toString()
: 如果对象具有__toString()
方法,则将对象转换为字符串,然后返回一个使用字符串值的流。NULL
: 当传递null
时,返回一个空的流对象。callable
当传递可调用时,创建一个调用给定可调用的只读流对象。可调用使用要读取的建议字节数来调用。可调用可以返回任意数量的字节,但在没有更多数据返回时必须返回false
。包装可调用的流对象将调用可调用,直到请求的字节数可用。任何额外的字节将被缓冲并用于后续的读取。
$stream = GuzzleHttp\Psr7\Utils::streamFor('foo');
$stream = GuzzleHttp\Psr7\Utils::streamFor(fopen('/path/to/file', 'r'));
$generator = function ($bytes) {
for ($i = 0; $i < $bytes; $i++) {
yield ' ';
}
}
$stream = GuzzleHttp\Psr7\Utils::streamFor($generator(100));
GuzzleHttp\Psr7\Utils::tryFopen
public static function tryFopen(string $filename, string $mode): resource
安全地使用文件名打开PHP流资源。
当 fopen 失败时,PHP 通常会引发警告。此函数添加一个错误处理程序,它检查错误并抛出异常。
GuzzleHttp\Psr7\Utils::uriFor
public static function uriFor(string|UriInterface $uri): UriInterface
返回给定值的 UriInterface。
此函数接受一个字符串或 UriInterface,并返回一个 UriInterface。如果值已经是 UriInterface,则按原样返回。
GuzzleHttp\Psr7\MimeType::fromFilename
public static function fromFilename(string $filename): string|null
通过查看文件的扩展名来确定文件的MIME类型。
GuzzleHttp\Psr7\MimeType::fromExtension
public static function fromExtension(string $extension): string|null
将文件扩展名映射到MIME类型。
从函数API升级
静态API首次在1.7.0版本中引入,旨在缓解全局和本地包副本之间的函数冲突问题。函数API将在2.0.0版本中移除。这里提供了一个迁移表以供您方便使用
原始函数 | 替换方法 |
---|---|
str | Message::toString |
uri_for | Utils::uriFor |
stream_for | Utils::streamFor |
parse_header | Header::parse |
normalize_header | Header::normalize |
modify_request | Utils::modifyRequest |
rewind_body | Message::rewindBody |
try_fopen | Utils::tryFopen |
copy_to_string | Utils::copyToString |
copy_to_stream | Utils::copyToStream |
hash | Utils::hash |
readline | Utils::readLine |
parse_request | Message::parseRequest |
parse_response | Message::parseResponse |
parse_query | Query::parse |
build_query | Query::build |
mimetype_from_filename | MimeType::fromFilename |
mimetype_from_extension | MimeType::fromExtension |
_parse_message | Message::parseMessage |
_parse_request_uri | Message::parseRequestUri |
get_message_body_summary | Message::bodySummary |
_caseless_remove | Utils::caselessRemove |
额外的URI方法
除了标准Psr\Http\Message\UriInterface
实现形式的GuzzleHttp\Psr7\Uri
类之外,此库还提供了一些静态方法,以便在处理URI时使用额外的功能。
URI类型
Psr\Http\Message\UriInterface
的实例可以是绝对URI或相对引用。绝对URI有一个方案。相对引用用于表示相对于另一个URI(基本URI)的URI。相对引用可以根据RFC 3986第4.2节分为几种形式
- 网络路径引用,例如
//example.com/path
- 绝对路径引用,例如
/path
- 相对路径引用,例如
subpath
以下方法可以用来识别URI的类型。
GuzzleHttp\Psr7\Uri::isAbsolute
public static function isAbsolute(UriInterface $uri): bool
URI是否是绝对的,即它有一个方案。
GuzzleHttp\Psr7\Uri::isNetworkPathReference
public static function isNetworkPathReference(UriInterface $uri): bool
URI是否是网络路径引用。以两个斜杠字符开始的相对引用称为网络路径引用。
GuzzleHttp\Psr7\Uri::isAbsolutePathReference
public static function isAbsolutePathReference(UriInterface $uri): bool
URI是否是绝对路径引用。以单个斜杠字符开始的相对引用称为绝对路径引用。
GuzzleHttp\Psr7\Uri::isRelativePathReference
public static function isRelativePathReference(UriInterface $uri): bool
URI是否是相对路径引用。不以斜杠字符开始的相对引用称为相对路径引用。
GuzzleHttp\Psr7\Uri::isSameDocumentReference
public static function isSameDocumentReference(UriInterface $uri, UriInterface $base = null): bool
URI是否是同一文档引用。同一文档引用指的是除了其片段组件外,与基本URI完全相同的URI。当未提供基本URI时,仅考虑空URI引用(除了其片段)为同一文档引用。
URI组件
用于处理URI组件的额外方法。
GuzzleHttp\Psr7\Uri::isDefaultPort
public static function isDefaultPort(UriInterface $uri): bool
URI是否有当前方案的默认端口。Psr\Http\Message\UriInterface::getPort
可能返回null或标准端口。此方法可以独立于实现使用。
GuzzleHttp\Psr7\Uri::composeComponents
public static function composeComponents($scheme, $authority, $path, $query, $fragment): string
根据RFC 3986 第 5.3 节,从其各个组件中组合一个 URI 引用字符串。通常情况下,不需要手动调用此方法,而是通过 Psr\Http\Message\UriInterface::__toString
间接使用。
GuzzleHttp\Psr7\Uri::fromParts
public static function fromParts(array $parts): UriInterface
从一个parse_url
组件哈希中创建一个 URI。
GuzzleHttp\Psr7\Uri::withQueryValue
public static function withQueryValue(UriInterface $uri, $key, $value): UriInterface
创建一个新的 URI,具有特定的查询字符串值。如果现有查询字符串值与提供的键完全匹配,则将其删除并替换为给定的键值对。null 值将设置查询字符串键而没有值,例如 "key" 而不是 "key=value"。
GuzzleHttp\Psr7\Uri::withQueryValues
public static function withQueryValues(UriInterface $uri, array $keyValueArray): UriInterface
创建一个新的 URI,具有多个查询字符串值。它与 withQueryValue()
的行为相同,但适用于键 => 值的关联数组。
GuzzleHttp\Psr7\Uri::withoutQueryValue
public static function withoutQueryValue(UriInterface $uri, $key): UriInterface
创建一个新的 URI,移除特定的查询字符串值。如果现有查询字符串值与提供的键完全匹配,则将其删除。
引用解析
GuzzleHttp\Psr7\UriResolver
提供了解析 URI 引用和基础 URI 的方法,根据 RFC 3986 第 5 节。例如,这也是网页浏览器在基于当前请求 URI 解析网站中的链接时所做的。
GuzzleHttp\Psr7\UriResolver::resolve
public static function resolve(UriInterface $base, UriInterface $rel): UriInterface
将相对 URI 转换为相对于基础 URI 的新 URI。
GuzzleHttp\Psr7\UriResolver::removeDotSegments
public static function removeDotSegments(string $path): string
根据 RFC 3986 第 5.2.4 节,从路径中删除点段并返回新路径。
GuzzleHttp\Psr7\UriResolver::relativize
public static function relativize(UriInterface $base, UriInterface $target): UriInterface
将目标 URI 作为基础 URI 的相对引用返回。此方法是 resolve() 的对应方法。
(string) $target === (string) UriResolver::resolve($base, UriResolver::relativize($base, $target))
一个用例是使用当前请求 URI 作为基础 URI,然后生成文档中的相对链接以减小文档大小或提供自包含的下载文档存档。
$base = new Uri('http://example.com/a/b/');
echo UriResolver::relativize($base, new Uri('http://example.com/a/b/c')); // prints 'c'.
echo UriResolver::relativize($base, new Uri('http://example.com/a/x/y')); // prints '../x/y'.
echo UriResolver::relativize($base, new Uri('http://example.com/a/b/?q')); // prints '?q'.
echo UriResolver::relativize($base, new Uri('http://example.org/a/b/')); // prints '//example.org/a/b/'.
规范化与比较
GuzzleHttp\Psr7\UriNormalizer
提供了根据 RFC 3986 第 6 节 规范化和比较 URI 的方法。
GuzzleHttp\Psr7\UriNormalizer::normalize
public static function normalize(UriInterface $uri, $flags = self::PRESERVING_NORMALIZATIONS): UriInterface
返回一个规范化的 URI。方案和主机组件已经根据 PSR-7 UriInterface 规范化为小写。此方法添加了可以由 $flags
参数配置的附加规范化,该参数是一个表示要应用规范化的掩码。以下是可以用的规范化:
UriNormalizer::PRESERVING_NORMALIZATIONS
默认规范化,仅包括保留语义的规范化。
UriNormalizer::CAPITALIZE_PERCENT_ENCODING
百分编码三联组中的所有字母(例如,"%3A")不区分大小写,应大写。
示例:
http://example.org/a%c2%b1b
→http://example.org/a%C2%B1b
UriNormalizer::DECODE_UNRESERVED_CHARACTERS
解码未保留字符的百分编码八位字节。为了保持一致性,URI 生产者不应创建范围在 ALPHA (%41–%5A 和 %61–%7A)、DIGIT (%30–%39)、连字符 (%2D)、点 (%2E)、下划线 (%5F) 或波浪号 (%7E) 的百分编码八位字节,并且当在 URI 中找到时,URI 规范化器应将它们解码为相应的未保留字符。
示例:
http://example.org/%7Eusern%61me/
→http://example.org/~username/
UriNormalizer::CONVERT_EMPTY_PATH
将空路径转换为"/"以适用于http和https URI。
示例:
http://example.org
→http://example.org/
UriNormalizer::REMOVE_DEFAULT_HOST
从给定URI方案的URI中移除默认主机。只有“file”方案定义了默认主机“localhost”。所有
file:/myfile
、file:///myfile
和file://localhost/myfile
根据RFC 3986都是等效的。示例:
file://localhost/myfile
→file:///myfile
UriNormalizer::REMOVE_DEFAULT_PORT
从给定URI方案的URI中移除默认端口。
示例:
http://example.org:80/
→http://example.org/
UriNormalizer::REMOVE_DOT_SEGMENTS
移除不必要的点段。相对路径引用中的点段不会被移除,因为这会改变URI引用的语义。
示例:
http://example.org/../a/b/../c/./d.html
→http://example.org/a/c/d.html
UriNormalizer::REMOVE_DUPLICATE_SLASHES
将包含两个或更多连续斜杠的路径转换为一个。Web服务器通常忽略重复的斜杠,并认为那些URI是等效的。但在理论 上,这些URI不需要是等效的。因此,这种规范化可能会改变语义。编码的斜杠(%2F)不会被移除。
示例:
http://example.org//foo///bar.html
→http://example.org/foo/bar.html
UriNormalizer::SORT_QUERY_PARAMETERS
按字母顺序对带有值的查询参数进行排序。但是,URI中参数的顺序可能很重要(这不是由标准定义的)。因此,这种规范化可能不安全,并可能改变URI的语义。
示例:
?lang=en&article=fred
→?article=fred&lang=en
GuzzleHttp\Psr7\UriNormalizer::isEquivalent
public static function isEquivalent(UriInterface $uri1, UriInterface $uri2, $normalizations = self::PRESERVING_NORMALIZATIONS): bool
判断两个URI是否可以被视为等效。在比较之前,两个URI都会自动使用给定的$normalizations
掩码进行规范化。该方法还接受相对URI引用,并在它们等效时返回true。这当然假设它们将相对于相同的基URI进行解析。如果这不是这种情况,则相对引用的等价性或差异的确定没有任何意义。