phly/http

该包已被废弃且不再维护。作者建议使用zendframework/zend-diactoros包代替。

PSR HTTP Message实现

0.14.1 2015-05-21 16:24 UTC

README

废弃!或者,更确切地说,重新命名!

phly/http已迁移到zendframework组织,作为zend-diactoros(Diactoros,字面意为“使者”,赫耳墨斯的别称)。

请使用该包,并针对它提交问题和拉取请求。我已关闭针对phly/http的问题和拉取请求。

Scrutinizer Code Quality Code Coverage Scrutinizer Build Status

phly/http是一个PHP包,包含已接受的PSR-7 HTTP消息接口的实现,以及类似于node的http.Server的“服务器”实现。

该包存在

  • 为了提供有关服务器端应用的PSR HTTP消息接口的证明概念。
  • 为了提供一个类似Node的范式用于PHP前端控制器。
  • 为了提供一个将请求从服务器环境封送的方法。

安装和需求

使用composer安装此库

$ composer require phly/http

phly/http有以下依赖(由Composer管理)

  • psr/http-message,它定义了HTTP消息的接口,包括请求和响应。phly/http为每个这些接口提供了实现。

用法

用法将根据您是编写HTTP客户端还是服务器端应用而有所不同。

对于HTTP客户端,您将创建并填充一个Request实例,客户端应返回一个Response实例。

对于服务器端应用,您将创建一个ServerRequest实例,填充并返回一个Response实例。

HTTP客户端

客户端将发送请求并返回响应。作为开发者,您将创建填充请求,然后检查响应。请求和响应都是不可变的;如果您进行更改(例如,通过调用setter方法),您必须捕获返回值,因为它是一个新实例。

// Create a request
$request = (new Phly\Http\Request())
    ->withUri(new Phly\Http\Uri('http://example.com'))
    ->withMethod('PATCH')
    ->withAddedHeader('Authorization', 'Bearer ' . $token)
    ->withAddedHeader('Content-Type', 'application/json');

// OR:
$request = new Phly\Http\Request(
    'http://example.com',
    'PATCH',
    'php://memory',
    [
        'Authorization' => 'Bearer ' . $token,
        'Content-Type'  => 'application/json',
    ]
);

// If you want to set a non-origin-form request target, set the
// request-target explicitly:
$request = $request->withRequestTarget((string) $uri));       // absolute-form
$request = $request->withRequestTarget($uri->getAuthority()); // authority-form
$request = $request->withRequestTarget('*');                 // asterisk-form

// Once you have the instance:
$request->getBody()->write(json_encode($data));
$response = $client->send($request);

printf("Response status: %d (%s)\n", $response->getStatusCode(), $response->getReasonPhrase());
printf("Headers:\n");
foreach ($response->getHeaders() as $header => $values) {
  printf("%s: %s\n", $header, implode(', ', $values));
}
printf("Message:\n%s\n", $response->getBody());

(注意:phly/http不提供客户端实现;上面只是一个可能的实现示例。)

服务器端应用

服务器端应用需要根据超全局变量封送传入的请求,然后填充并发送响应。

封送传入请求

PHP包含大量关于传入请求的信息,并将这些信息保存在多个位置。Phly\Http\ServerRequestFactory::fromGlobals()可以将这些信息简化为请求实例。

您可以用以下顺序调用工厂方法,带或不带以下参数

  • $server,通常为$_SERVER
  • $query,通常为 $_GET
  • $body,通常为 $_POST
  • $cookies,通常为 $_COOKIE
  • $files,通常为 $_FILES

该方法将返回一个 Phly\Http\ServerRequest 实例。如果省略任何参数,将使用相应的超级全局变量。

$request = Phly\Http\ServerRequestFactory::fromGlobals(
  $_SERVER,
  $_GET,
  $_POST,
  $_COOKIE,
  $_FILES
);

响应操作

使用响应对象添加头部信息并提供响应内容。向主体写入不创建响应状态变化,因此可以不捕获返回值即可完成。但操作头部信息时则会。

$response = new Phly\Http\Response();

// Write to the response body:
$response->getBody()->write("some content\n");

// Multiple calls to write() append:
$response->getBody()->write("more content\n"); // now "some content\nmore content\n"

// Add headers
// Note: headers do not need to be added before data is written to the body!
$response = $response
    ->withHeader('Content-Type', 'text/plain')
    ->withAddedHeader('X-Show-Something', 'something');

“服务”一个应用

Phly\Http\Server 模拟了 node 的 http.Server 类的部分 API。它调用一个回调,将 ServerRequestResponse 以及可选的用于不完整/未处理的请求的回调传递给该回调。

您可以通过以下三种方式之一创建服务器

// Direct instantiation, with a callback handler, request, and response
$server = new Phly\Http\Server(
    function ($request, $response, $done) {
        $response->getBody()->write("Hello world!");
    },
    $request,
    $response
);

// Using the createServer factory, providing it with the various superglobals:
$server = Phly\Http\Server::createServer(
    function ($request, $response, $done) {
        $response->getBody()->write("Hello world!");
    },
    $_SERVER,
    $_GET,
    $_POST,
    $_COOKIE,
    $_FILES
);

// Using the createServerFromRequest factory, and providing it a request:
$server = Phly\Http\Server::createServerfromRequest(
  function ($request, $response, $done) {
      $response->getBody()->write("Hello world!");
  },
  $request
);

服务器回调可以期望最多三个参数,顺序如下

  • $request - 请求对象
  • $response - 响应对象
  • $done - 当完成时可选的回调

一旦您拥有服务器实例,您必须指导它进行监听

$server->listen();

此时,您可以可选地向 listen() 提供一个回调;这将作为第三个参数($done)传递给处理器

$server->listen(function ($request, $response, $error = null) {
    if (! $error) {
        return;
    }
    // do something with the error...
});

通常,listen 回调将是一个错误处理器,并可以期望接收请求、响应和错误作为其参数(尽管错误可能为 null)。

API

请求消息

Phly\Http\Request 实现 Psr\Http\Message\RequestInterface,旨在用于客户端请求。它包括以下方法

class Request
{
    public function __construct(
        $uri = null,
        $method = null,
        $body = 'php://memory',
        array $headers = []
    );

    // See psr/http-message's RequestInterface for other methods
}

请求是不可变的。任何会改变状态的方法(以 withwithout 为前缀的)都会返回一个具有所需更改的新实例。

服务器请求消息

对于服务器端应用,Phly\Http\ServerRequest 实现 Psr\Http\Message\ServerRequestInterface,它提供了访问 HTTP 请求元素以及访问传入数据的各个元素的一致访问方式。包括以下方法

class ServerRequest
{
    public function __construct(
        array $serverParams = [],
        array $fileParams = [],
        $uri = null,
        $method = null,
        $body = 'php://input',
        array $headers = []
    );

    // See psr/http-message's ServerRequestInterface for other methods.
}

ServerRequest 是不可变的。任何会改变状态的方法(以 withwithout 为前缀的)都会返回一个具有所需更改的新实例。然而,服务器参数被认为是完全不可变的,因为它们不能被重新计算,而是作为其他值的来源。

响应消息

Phly\Http\Response 提供了 Psr\Http\Message\ResponseInterface 的实现,这是一个用于聚合响应信息的对象,用于 HTTP 客户端和服务器端应用,包括头部信息和消息主体内容。包括以下内容

class Response
{
    public function __construct(
        $body = 'php://memory',
        $statusCode = 200,
        array $headers = []
    );

    // See psr/http-message's ResponseInterface for other methods
}

RequestServerRequest 类似,响应也是不可变的。任何会改变状态的方法(以 withwithout 为前缀的)都会返回一个具有所需更改的新实例。

ServerRequestFactory

这个静态类可以用来从PHP环境中序列化一个ServerRequest实例。主要的入口点是Phly\Http\ServerRequestFactory::fromGlobals(array $server, array $query, array $body, array $cookies, array $files)。该方法将创建一个包含提供数据的新的ServerRequest实例。使用示例包括

// Returns new ServerRequest instance, using values from superglobals:
$request = ServerRequestFactory::fromGlobals();

// or

// Returns new ServerRequest instance, using values provided (in this
// case, equivalent to the previous!)
$request = RequestFactory::fromGlobals(
  $_SERVER,
  $_GET,
  $_POST,
  $_COOKIE,
  $_FILES
);

URI

Phly\Http\UriPsr\Http\Message\UriInterface的实现,用于建模和验证URI。它实现了__toString(),允许它被表示为字符串并直接通过echo()输出。以下方法相关

class Uri
{
    public function __construct($uri = '');

    // See psr/http-message's UriInterface for other methods.
}

与各种消息对象一样,URI是不可变的。任何会改变状态的方法(那些以withwithout开头的方法)都返回一个新的实例,该实例包含所请求的更改。

Phly\Http\StreamPsr\Http\Message\StreamInterface的实现,提供了一系列操作组合PHP流资源的功能。构造函数接受一个流,可以是以下之一

  • 一个流标识符;例如,php://input,一个文件名等。
  • 一个PHP流资源

如果提供了一个流标识符,还可以提供一个可选的第二个参数,即通过fopen打开流时使用的文件模式。

ServerRequest对象默认使用只读的php://input流;Response对象默认使用php://memory,模式为wb+,允许二进制读写访问。

在大多数情况下,你不会直接与流对象交互。

上传文件

Phly\Http\UploadedFilePsr\Http\Message\UploadedFileInterface的实现,提供了一种对单个上传文件的抽象,包括与它作为流交互或将其移动到文件系统位置的行为。

在大多数情况下,你只会使用在UploadedFileInterface中定义的方法。

服务器

Phly\Http\Server表示一个能够执行回调的服务器。它有四个方法

class Server
{
    public function __construct(
        callable $callback,
        Psr\Http\Message\ServerRequestInterface $request,
        Psr\Http\Message\ResponseInterface $response
    );
    public static function createServer(
        callable $callback,
        array $server,  // usually $_SERVER
        array $query,   // usually $_GET
        array $body,    // usually $_POST
        array $cookies, // usually $_COOKIE
        array $files    // usually $_FILES
    );
    public static function createServerFromRequest(
        callable $callback,
        Psr\Http\Message\ServerRequestInterface $request,
        Psr\Http\Message\ResponseInterface $response = null
    );
    public function setEmitter(Response\EmitterInterface $emitter);
    public function listen(callable $finalHandler = null);
}

你可以使用构造函数、createServer()createServerFromRequest()方法中的任何一个来创建一个Server实例。如果你希望使用默认的请求和响应实现,createServer($middleware, $_SERVER, $_GET, $_POST, $_COOKIE, $_FILES)是推荐的选择,因为这个方法还将根据PHP请求环境序列化ServerRequest对象。如果你希望使用自己的实现,将它们传递给构造函数或createServerFromRequest()方法(后者将创建一个默认的Response实例,如果你省略它)。

listen()执行回调。如果提供了$finalHandler,它将被作为第三个参数传递给服务器上注册的$callback

发出响应

如果你使用的是非SAPI的PHP实现,并希望使用Server类,或者你不希望使用Server实现但想发出响应,这个包提供了一个接口Phly\Http\Response\EmitterInterface,定义了一个用于发出响应的emit()方法。目前有一个实现,Phly\Http\Response\SapiEmitter,它将使用原生的PHP函数header()echo来发出响应。如果你使用的是非SAPI实现,你需要创建自己的EmitterInterface实现。

序列化

有时,创建消息的字符串表示(序列化),或将字符串或流消息转换为对象(反序列化)非常有用。本包在 Phly\Http\Request\SerializerPhly\Http\Response\Serializer 中提供了这些功能;每个都提供了以下静态方法:

  • fromString($message) 会从字符串消息创建一个 RequestResponse 实例(根据使用的序列化器而定)。
  • fromStream(Psr\Http\Message\StreamInterface $stream) 会从提供的流创建一个 RequestResponse 实例(根据使用的序列化器而定)。
  • toString(Psr\Http\Message\RequestInterface|Psr\Http\Message\ResponseInterface $message) 会从提供的消息创建一个字符串。

反序列化方法(from*())在解析消息时如果发生错误会抛出异常。序列化方法(toString())如果消息实例中不存在序列化所需的数据也会抛出异常。