ehough / psr7
PHP 5.3 兼容的 guzzle/psr7 分支
This package is not auto-updated.
Last update: 2020-04-17 18:17:24 UTC
README
PHP 5.3 兼容的 guzzle/psr7
分支。
为什么?
35% 的所有 PHP 服务器仍然(遗憾的是)运行 PHP 5.3 及以下版本,但 guzzle/psr7
需要 PHP 5.4 或更高版本。此分支使 guzzle/psr7
兼容 PHP 5.3.29 至 7.1。
如何使用此分支
用法与 guzzle/psr7
相同,除了该库中的类命名空间位于 Hough\Psr7
而不是 GuzzleHttp\Psr7
下。
此存储库包含完整的 PSR-7 消息实现,几个流装饰器以及一些有用的功能,如查询字符串解析。
流实现
此包包含多个流实现和流装饰器。
AppendStream
Hough\Psr7\AppendStream
从多个流中按顺序读取。
use Hough\Psr7; $a = Psr7\stream_for('abc, '); $b = Psr7\stream_for('123.'); $composed = new Psr7\AppendStream(array($a, $b)); $composed->addStream(Psr7\stream_for(' Above all listen to me')); echo $composed; // abc, 123. Above all listen to me.
BufferStream
Hough\Psr7\BufferStream
提供可以写入以填充缓冲区的缓冲流,并可以从中读取以从缓冲区中删除字节的流。
此流返回一个 "hwm" 元数据值,该值告诉上游消费者流的配置高水位标记是多少,或缓冲区的最大首选大小。
use Hough\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 Hough\Psr7; $original = Psr7\stream_for(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
Hough\Psr7\DroppingStream
当底层流的大小变得过大时,开始丢弃数据的流装饰器。
use Hough\Psr7; // Create an empty stream $stream = Psr7\stream_for(); // Start dropping data when the stream has more than 10 bytes $dropping = new Psr7\DroppingStream($stream, 10); $dropping->write('01234567890123456789'); echo $stream; // 0123456789
FnStream
Hough\Psr7\FnStream
基于函数哈希组合流实现。
允许在不需要为简单的扩展点创建具体类的情况下轻松测试和扩展提供的流。
use Hough\Psr7; $stream = Psr7\stream_for('hi'); $fnStream = Psr7\FnStream::decorate($stream, array( 'rewind' => function () use ($stream) { echo 'About to rewind - '; $stream->rewind(); echo 'rewound!'; } )); $fnStream->rewind(); // Outputs: About to rewind - rewound!
InflateStream
Hough\Psr7\InflateStream
使用 PHP 的 zlib.inflate 过滤器来膨胀已压缩的内容。
此流装饰器跳过给定流的第一个10个字节以去除gzip头,将提供的流转换为PHP流资源,然后附加zlib.inflate过滤器。然后,该流被转换回Hough流资源,用作Hough流。
LazyOpenStream
Hough\Psr7\LazyOpenStream
仅在流上发生IO操作后才打开文件进行懒惰读取或写入。
use Hough\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
Hough\Psr7\LimitStream
LimitStream可用于读取现有流对象的一个子集或片段。这可以用于将大文件分割成小块,分块发送(例如,Amazon S3的multipart上传API)。
use Hough\Psr7; $original = Psr7\stream_for(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
Hough\Psr7\MultipartStream
当读取时,返回用于流式多部分或multipart/form-data流的字节数。
NoSeekStream
Hough\Psr7\NoSeekStream
NoSeekStream包装一个流,不允许进行查找。
use Hough\Psr7; $original = Psr7\stream_for('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
Hough\Psr7\PumpStream
提供一个只读流,从PHP可调用函数中泵送数据。
当调用提供的可调用函数时,PumpStream将请求读取的数据量传递给可调用函数。可调用函数可以选择忽略此值并返回少于或多于请求的字节数。由提供的可调用函数返回的任何额外数据都将使用PumpStream的read()函数内部缓冲,直到排空。提供的可调用函数必须在没有更多数据可读时返回false。
实现流装饰器
由于有Hough\Psr7\StreamDecorator
,创建流非常简单。此类通过代理到底层流来提供实现Psr\Http\Message\StreamInterface
的方法。只需扩展StreamDecorator
并实现您自定义的方法。
例如,如果我们想每次从流中读取最后一个字节时调用一个特定的函数,这可以通过重写read()
方法来实现。
use Psr\Http\Message\StreamInterface; use Hough\Psr7\StreamDecorator; class EofCallbackStream extends StreamDecorator implements StreamInterface { 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 Hough\Psr7; $original = Psr7\stream_for('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流资源,可以使用Hough\Psr7\StreamWrapper
类。
使用Hough\Psr7\StreamWrapper::getResource()
方法从PSR-7流创建PHP流。
use Hough\Psr7\StreamWrapper; $stream = Hough\Psr7\stream_for('hello!'); $resource = StreamWrapper::getResource($stream); echo fread($resource, 6); // outputs hello!
函数API
在Hough\Psr7
命名空间下有各种函数可用。
function str
function str(MessageInterface $message)
返回HTTP消息的字符串表示形式。
$request = new Hough\Psr7\Request('GET', 'http://example.com'); echo Hough\Psr7\str($request);
function uri_for
function uri_for($uri)
此函数接受一个字符串或Psr\Http\Message\UriInterface
,并返回给定值的UriInterface。如果值已经是UriInterface
,则按原样返回。
$uri = Hough\Psr7\uri_for('http://example.com'); assert($uri === Hough\Psr7\uri_for($uri));
function stream_for
function stream_for($resource = '', array $options = array())
根据输入类型创建一个新的流。
“Options”是一个关联数组,可以包含以下键
-
- metadata:自定义元数据的数组。
-
- size:流的尺寸。
此方法接受以下$resource
类型
Psr\Http\Message\StreamInterface
:返回值不变。string
:创建一个使用给定字符串作为内容的流对象。resource
:创建一个封装给定PHP流资源的流对象。Iterator
:如果提供的值实现了Iterator
,则将创建一个封装给定可迭代的只读流对象。每次从流中读取数据时,迭代器中的数据将填充缓冲区,并将持续调用,直到缓冲区等于请求的读取大小。后续的读取调用将首先从缓冲区中读取,然后调用底层迭代器的next
方法,直到迭代器耗尽。object
带有__toString()
:如果对象具有__toString()
方法,则对象将被转换为字符串,然后返回一个使用字符串值的流。NULL
:当传递null
时,将返回一个空的流对象。callable
:当传递可调用函数时,将创建一个调用给定可调用函数的只读流对象。可调用函数以要读取的建议字节数为参数调用。可调用函数可以返回任意数量的字节,但当没有更多数据返回时必须返回false
。封装可调用函数的流对象将调用可调用函数,直到可用的字节数等于请求的字节数。任何额外的字节将被缓冲并用于后续的读取。
$stream = Hough\Psr7\stream_for('foo'); $stream = Hough\Psr7\stream_for(fopen('/path/to/file', 'r')); $generator function ($bytes) { for ($i = 0; $i < $bytes; $i++) { yield ' '; } } $stream = Hough\Psr7\stream_for($generator(100));
function parse_header
function parse_header($header)
将包含分号分隔数据的头部值数组解析为表示头部键值对的关联数组。当参数不包含值,只包含键时,此函数将注入一个带有''字符串值的键。
function normalize_header
function normalize_header($header)
将可能包含逗号分隔头部的值数组转换为没有逗号分隔值的头部数组。
function modify_request
function modify_request(RequestInterface $request, array $changes)
克隆并修改具有给定更改的请求。此方法对于减少需要克隆以更改消息的数量非常有用。
更改可以是以下之一
- method:(字符串)更改HTTP方法。
- set_headers:(数组)设置给定的头部。
- remove_headers:(数组)删除给定的头部。
- body:(混合)设置给定的主体。
- uri:(UriInterface)设置URI。
- query:(字符串)设置URI的查询字符串值。
- version:(字符串)设置协议版本。
function rewind_body
function rewind_body(MessageInterface $message)
尝试重置消息主体,并在失败时抛出异常。只有当对tell()
的调用返回值不是0
时,消息的主体才会被重置。
function try_fopen
function try_fopen($filename, $mode)
使用文件名安全地打开PHP流资源。
当fopen失败时,PHP通常会引发一个警告。此函数添加了一个错误处理器,它会检查错误并抛出异常。
function copy_to_string
function copy_to_string(StreamInterface $stream, $maxLen = -1)
将流的内容复制到字符串中,直到读取到指定数量的字节。
function copy_to_stream
function copy_to_stream(StreamInterface $source, StreamInterface $dest, $maxLen = -1)
将一个流的内容复制到另一个流中,直到读取到指定数量的字节。
function hash
function hash(StreamInterface $stream, $algo, $rawOutput = false)
计算流的哈希值。此方法读取整个流以计算滚动哈希(基于PHP的hash_init函数)。
function readline
function readline(StreamInterface $stream, $maxLength = null)
从流中读取一行,直到最大允许的缓冲区长度。
function parse_request
function parse_request($message)
将请求消息字符串解析为请求对象。
function parse_response
function parse_response($message)
将响应消息字符串解析为响应对象。
function parse_query
function parse_query($str, $urlEncoding = true)
将查询字符串解析为关联数组。
如果找到相同键的多个值,该键值对的值将成为一个数组。此函数不会将嵌套PHP风格数组解析为关联数组(例如,foo[a]=1&foo[b]=2
将被解析为array('foo[a]' => '1', 'foo[b]' => '2')
)。
function build_query
function build_query(array $params, $encoding = PHP_QUERY_RFC3986)
从键值对数组构建查询字符串。
此函数可以使用parse_query()的返回值构建查询字符串。当遇到数组时,此函数不会修改提供的键(如http_build_query所做的那样)。
function mimetype_from_filename
function mimetype_from_filename($filename)
通过查看扩展名确定文件的mimetype。
function mimetype_from_extension
function mimetype_from_extension($extension)
将文件扩展名映射到mimetype。
附加URI方法
除了以Hough\Psr7\Uri类的形式实现的标准的Psr\Http\Message\UriInterface
实现之外,此库还提供了一些静态方法,用于处理URI。
URI类型
Psr\Http\Message\UriInterface
的实例可以是绝对 URI 或相对引用。绝对 URI 包含一个方案。相对引用用于表示相对于另一个 URI(基础 URI)的 URI。根据 RFC 3986 第 4.2 节,相对引用可以划分为几种形式。
- 网络路径引用,例如:
//example.com/path
- 绝对路径引用,例如:
/path
- 相对路径引用,例如:
subpath
以下方法可以用来识别 URI 的类型。
Hough\Psr7\Uri::isAbsolute
public static function isAbsolute(UriInterface $uri): bool
判断 URI 是否为绝对 URI,即它是否包含一个方案。
Hough\Psr7\Uri::isNetworkPathReference
public static function isNetworkPathReference(UriInterface $uri): bool
判断 URI 是否为网络路径引用。以两个斜杠字符开始的相对引用被称为网络路径引用。
Hough\Psr7\Uri::isAbsolutePathReference
public static function isAbsolutePathReference(UriInterface $uri): bool
判断 URI 是否为绝对路径引用。以单个斜杠字符开始的相对引用被称为绝对路径引用。
Hough\Psr7\Uri::isRelativePathReference
public static function isRelativePathReference(UriInterface $uri): bool
判断 URI 是否为相对路径引用。不以斜杠字符开始的相对引用被称为相对路径引用。
Hough\Psr7\Uri::isSameDocumentReference
public static function isSameDocumentReference(UriInterface $uri, UriInterface $base = null): bool
判断 URI 是否为同一文档引用。同一文档引用是指,除了其片段组件外,与基础 URI 相同的 URI。当未提供基础 URI 时,仅当空 URI 引用(除片段外)时才被认为是同一文档引用。
URI 组件
用于处理 URI 组件的附加方法。
Hough\Psr7\Uri::isDefaultPort
public static function isDefaultPort(UriInterface $uri): bool
判断 URI 是否具有当前方案的默认端口。Psr\Http\Message\UriInterface::getPort
可返回 null 或标准端口。此方法可以独立于实现使用。
Hough\Psr7\Uri::composeComponents
public static function composeComponents($scheme, $authority, $path, $query, $fragment): string
根据 RFC 3986 第 5.3 节 从 URI 的各个组件中组成 URI 引用字符串。通常此方法不需要手动调用,而是通过 Psr\Http\Message\UriInterface::__toString
间接使用。
Hough\Psr7\Uri::fromParts
public static function fromParts(array $parts): UriInterface
从一组 parse_url
组件中创建 URI。
Hough\Psr7\Uri::withQueryValue
public static function withQueryValue(UriInterface $uri, $key, $value): UriInterface
创建一个新的URI,其中包含特定的查询字符串值。任何与提供的键完全匹配的现有查询字符串值都将被删除并替换为给定的键值对。null值将设置查询字符串键而没有值,例如"key"而不是"key=value"。
Hough\Psr7\Uri::withoutQueryValue
public static function withoutQueryValue(UriInterface $uri, $key): UriInterface
创建一个新的URI,其中删除了特定的查询字符串值。任何与提供的键完全匹配的现有查询字符串值都将被删除。
参考解析
Hough\Psr7\UriResolver
提供了解析URI引用的方法,该方法根据RFC 3986第5节在基本URI的上下文中进行。例如,这也是网络浏览器在基于当前请求URI解析网站中的链接时所做的事情。
Hough\Psr7\UriResolver::resolve
public static function resolve(UriInterface $base, UriInterface $rel): UriInterface
将相对URI转换为相对于基本URI的新URI。
Hough\Psr7\UriResolver::removeDotSegments
public static function removeDotSegments(string $path): string
从路径中删除点段,并返回根据RFC 3986第5.2.4节返回的新路径。
Hough\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/'.
标准化和比较
Hough\Psr7\UriNormalizer
提供根据RFC 3986第6节进行URI标准化和比较的方法。
Hough\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
Hough\Psr7\UriNormalizer::isEquivalent
public static function isEquivalent(UriInterface $uri1, UriInterface $uri2, $normalizations = self::PRESERVING_NORMALIZATIONS): bool
判断两个URI是否可以被认为是等效的。在比较之前,两个URI都自动根据给定的$normalizations
位掩码进行标准化。该方法还接受相对URI引用,并在它们等效时返回true。这当然假设它们将与相同的基URI解析。如果不是这种情况,等效或不同相对引用的确定没有任何意义。