drnkwati/guzzle-psr7

PHP 5.3 兼容的 guzzle/psr7 分支

dev-master / 1.0.x-dev 2018-03-13 15:26 UTC

This package is auto-updated.

Last update: 2024-09-22 11:04:30 UTC


README

Build Status Latest Stable Version License

这是一个兼容 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 相同。

此存储库包含完整的 PSR-7 消息实现、多个流装饰器以及一些有用的功能,如查询字符串解析。

流实现

此软件包包含多个流实现和流装饰器。

AppendStream

GuzzleHttp\Psr7\AppendStream

从多个流中读取,一个接一个。

use GuzzleHttp\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

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\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

GuzzleHttp\Psr7\DroppingStream

DroppingStream 是一种流装饰器,当底层流的大小变得过大时开始丢弃数据。

use GuzzleHttp\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

GuzzleHttp\Psr7\FnStream

基于函数哈希的组合流实现。

允许在不需要为简单的扩展点创建具体类的情况下轻松测试和扩展提供的流。

use GuzzleHttp\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

GuzzleHttp\Psr7\InflateStream

使用 PHP 的 zlib.inflate 过滤器来解压 deflate 或 gzipped 内容。

此流装饰器跳过给定流的第一个 10 个字节以删除 gzip 头,将提供的流转换为 PHP 流资源,然后附加 zlib.inflate 过滤器。然后将流转换回 Hough 流资源以用作 Hough 流。

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\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

GuzzleHttp\Psr7\MultipartStream

当读取时返回流式多部分或 multipart/form-data 流的字节的流。

NoSeekStream

GuzzleHttp\Psr7\NoSeekStream

NoSeekStream 包装了一个流,并且不允许查找。

use GuzzleHttp\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

GuzzleHttp\Psr7\PumpStream

提供只读流,从 PHP 可调用中泵送数据。

当调用提供的可调用函数时,PumpStream会将请求读取的数据量传递给该函数。可调用函数可以选择忽略此值,返回少于或多于请求的字节数。由提供的可调用函数返回的任何额外数据都将使用PumpStream的read()函数内部缓冲,直到被消耗。当没有更多数据可读取时,提供的可调用函数必须返回false。

实现流装饰器

由于有GuzzleHttp\Psr7\StreamDecorator,创建流变得非常简单。该类提供的方法通过代理到底层流实现了Psr\Http\Message\StreamInterface。只需扩展StreamDecorator并实现自定义方法。

例如,假设我们希望在从流中读取最后一个字节时调用一个特定函数。这可以通过覆盖read()方法来实现。

use Psr\Http\Message\StreamInterface;
use GuzzleHttp\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 GuzzleHttp\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流包装器

如果您需要将PSR-7流用作PHP流资源,可以使用GuzzleHttp\Psr7\StreamWrapper类。

使用GuzzleHttp\Psr7\StreamWrapper::getResource()方法从PSR-7流创建PHP流。

use GuzzleHttp\Psr7\StreamWrapper;

$stream = GuzzleHttp\Psr7\stream_for('hello!');
$resource = StreamWrapper::getResource($stream);
echo fread($resource, 6); // outputs hello!

函数API

GuzzleHttp\Psr7命名空间下有各种函数可用。

函数str

function str(MessageInterface $message)

返回HTTP消息的字符串表示。

$request = new GuzzleHttp\Psr7\Request('GET', 'http://example.com');
echo GuzzleHttp\Psr7\str($request);

函数uri_for

function uri_for($uri)

此函数接受一个字符串或Psr\Http\Message\UriInterface,并返回给定值的UriInterface。如果值已经是UriInterface,则按原样返回。

$uri = GuzzleHttp\Psr7\uri_for('http://example.com');
assert($uri === GuzzleHttp\Psr7\uri_for($uri));

函数stream_for

function stream_for($resource = '', array $options = array())

根据输入类型创建一个新流。

选项是一个关联数组,可以包含以下键

    • metadata: 自定义元数据的数组。
    • size: 流的大小。

此方法接受以下$resource类型

  • Psr\Http\Message\StreamInterface: 按原样返回值。
  • string: 创建一个使用给定字符串作为内容的流对象。
  • resource: 创建一个包装给定PHP流资源的流对象。
  • Iterator: 如果提供的值实现了Iterator,则将创建一个只读流对象,该对象包装给定的可迭代对象。每次从流中读取时,迭代器中的数据将填充缓冲区,并持续调用,直到缓冲区等于请求的读取大小。后续的读取调用将首先从缓冲区读取,然后对底层迭代器调用next,直到迭代器耗尽。
  • object with __toString(): 如果对象具有__toString()方法,则该对象将被转换为字符串,然后返回一个使用字符串值的流。
  • NULL: 当传递null时,将返回一个空的流对象。
  • callable: 当传递可调用函数时,将创建一个只读流对象,该对象调用给定的可调用函数。可调用函数以要读取的建议字节数为参数调用。可调用函数可以返回任意数量的字节数,但当没有更多数据可返回时,必须返回false。包装可调用函数的流对象将调用可调用函数,直到有请求的字节数可用。任何额外的字节数都将被缓冲并在后续读取中使用。
$stream = GuzzleHttp\Psr7\stream_for('foo');
$stream = GuzzleHttp\Psr7\stream_for(fopen('/path/to/file', 'r'));

$generator function ($bytes) {
    for ($i = 0; $i < $bytes; $i++) {
        yield ' ';
    }
}

$stream = GuzzleHttp\Psr7\stream_for($generator(100));

函数parse_header

function parse_header($header)

解析包含";"分隔数据的头值数组,并将其解析为表示头键值对数据的关联数组数组。当参数不包含值,但仅包含键时,此函数将注入一个带有''字符串值的键。

函数normalize_header

function normalize_header($header)

将可能包含逗号分隔头的头值数组转换为不包含逗号分隔值的头数组。

函数modify_request

function modify_request(RequestInterface $request, array $changes)

根据给定的更改克隆并修改请求。此方法有助于减少突变消息所需的克隆数量。

更改可以是以下之一

  • method: (字符串) 更改HTTP方法。
  • set_headers: (数组) 设置给定的头。
  • remove_headers: (数组) 删除给定的头。
  • body: (混合类型) 设置给定的主体。
  • uri: (UriInterface) 设置URI。
  • query: (字符串) 设置URI的查询字符串值。
  • version: (字符串) 设置协议版本。

函数 rewind_body

函数 rewind_body(MessageInterface $message)

尝试重置消息主体,失败时抛出异常。只有在调用 tell() 返回值不为 0 时,消息的主体才会被重置。

函数 try_fopen

函数 try_fopen($filename, $mode)

使用文件名安全地打开PHP流资源。

当fopen失败时,PHP通常引发警告。此函数添加一个错误处理程序,检查错误并抛出异常。

函数 copy_to_string

函数 copy_to_string(StreamInterface $stream, $maxLen = -1)

将流的内容复制到字符串中,直到读取给定的字节数。

函数 copy_to_stream

函数 copy_to_stream(StreamInterface $source, StreamInterface $dest, $maxLen = -1)

将流的内容复制到另一个流中,直到读取给定的字节数。

函数 hash

函数 hash(StreamInterface $stream, $algo, $rawOutput = false)

计算流的哈希值。此方法读取整个流以计算滚动哈希(基于PHP的hash_init函数)。

函数 readline

函数 readline(StreamInterface $stream, $maxLength = null)

从流中读取一行,直到最大允许缓冲区长度。

函数 parse_request

函数 parse_request($message)

将请求消息字符串解析为请求对象。

函数 parse_response

函数 parse_response($message)

将响应消息字符串解析为响应对象。

函数 parse_query

函数 parse_query($str, $urlEncoding = true)

将查询字符串解析为关联数组。

如果对于相同的键找到多个值,则该键值对的值将成为一个数组。此函数不将嵌套PHP风格数组解析为关联数组(例如,foo[a]=1&foo[b]=2 将解析为 array('foo[a]' => '1', 'foo[b]' => '2'))。

函数 build_query

函数 build_query(array $params, $encoding = PHP_QUERY_RFC3986)

从键值对数组构建查询字符串。

此函数可以使用parse_query()的返回值构建查询字符串。此函数在遇到数组时不会修改提供的键(如http_build_query)。

函数 mimetype_from_filename

函数 mimetype_from_filename($filename)

通过查看扩展名确定文件的mimetype。

函数 mimetype_from_extension

函数 mimetype_from_extension($extension)

将文件扩展名映射到mimetype。

附加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是否为绝对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::withoutQueryValue

public static function withoutQueryValue(UriInterface $uri, $key): UriInterface

创建一个新的URI,删除特定的查询字符串值。任何与提供的键完全匹配的现有查询字符串值都会被删除。

引用解析

GuzzleHttp\Psr7\UriResolver提供了解析根据RFC 3986第5节在基本URI上下文中URI引用的方法。这也就是例如网络浏览器在基于当前请求URI解析网站中的链接时所做的。

GuzzleHttp\Psr7\UriResolver::resolve

public static function resolve(UriInterface $base, UriInterface $rel): UriInterface

将相对URI转换为一个新的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%b1bhttp://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.orghttp://example.org/

  • UriNormalizer::REMOVE_DEFAULT_HOST

    从URI中移除给定URI方案的默认主机。只有“file”方案定义了默认主机“localhost”。根据RFC 3986,所有file:/myfilefile:///myfilefile://localhost/myfile都是等效的。

    示例:file://localhost/myfilefile:///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.htmlhttp://example.org/a/c/d.html

  • UriNormalizer::REMOVE_DUPLICATE_SLASHES

    包含两个或更多相邻斜杠的路径将转换为一个。Web服务器通常忽略重复的斜杠,并将这些URI视为等效。但在理论上,这些URI不需要等效。因此,这种规范化可能会改变语义。编码的斜杠(%2F)不会被删除。

    示例:http://example.org//foo///bar.htmlhttp://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解析。如果不是这种情况,确定相对引用的等效性或差异就没有意义。