sabre / http

sabre/http 库提供了处理 HTTP 请求和响应的实用工具。

7.0.4 2024-09-06 11:41 UTC

README

该库提供了一套工具,用于简化 HTTP 协议的工作。

大多数 PHP 脚本都在 HTTP 请求中运行,但访问 HTTP 请求的信息至少是繁琐的。

存在着不良的实践、不一致和混淆。这个库实际上是对以下 PHP 构造的包装:

输入

  • $_GET,
  • $_POST,
  • $_SERVER,
  • php://input$HTTP_RAW_POST_DATA

输出

  • php://outputecho
  • header().

这个库提供的,是一个 Request 对象和一个 Response 对象。

这些对象是可扩展的,并且很容易模拟。

构建状态

Build Status

安装

确保您已安装 composer。在您的项目目录中,创建或编辑一个 composer.json 文件,并确保它包含以下内容

{
    "require" : {
        "sabre/http" : "~5.0.0"
    }
}

之后,只需运行 composer install 即可。

快速历史

该库于 2009 年诞生,作为 sabre/dav 项目的一部分,该项目大量使用了它。

它被拆分为一个单独的库,以使其更容易管理发布,并希望使其在 sabre/dav 的范围之外也能使用。

虽然完全独立开发,但这个库与 Symfony 的 HttpFoundation 有很多重叠。

上述库执行了很多其他操作,并且非常受欢迎,因此如果您正在寻找满足这一特定需求的东西,我建议您也考虑 HttpFoundation

入门

首先最重要的是,这个库包装了超级全局变量。实例化请求对象的最简单方法是以下方法

use Sabre\HTTP;

include 'vendor/autoload.php';

$request = HTTP\Sapi::getRequest();

这行代码应仅在整个应用程序中发生一次。在其他地方,您应使用依赖注入传递此请求对象。

您应该始终对其接口进行类型提示

function handleRequest(HTTP\RequestInterface $request) {

    // Do something with this request :)

}

响应对象可以这样创建

use Sabre\HTTP;

include 'vendor/autoload.php';

$response = new HTTP\Response();
$response->setStatus(201); // created !
$response->setHeader('X-Foo', 'bar');
$response->setBody(
    'success!'
);

在您完全构建了响应之后,您必须调用

HTTP\Sapi::sendResponse($response);

这行代码通常也只出现在您的应用程序中(在最后)。

装饰器

如果您希望在应用程序中扩展 RequestResponse 对象,例如,如果希望它们携带更多关于当前请求的信息,这可能很有用。

例如,您可能想向请求对象添加一个 isLoggedIn 方法。

简单地扩展请求和响应可能存在一些问题

  1. 您可能希望以不同的方式扩展对象以实现新的行为,在应用程序的不同子系统,
  2. Sapi::getRequest 工厂始终返回一个 Request 实例,因此您还必须重写工厂方法,
  3. 通过控制实例化和依赖库或应用程序中的特定 RequestResponse 实例,您使其他应用程序难以使用 sabre/http

简而言之,这将是糟糕的设计。相反,建议使用装饰器模式来添加所需的新行为。sabre/http提供了辅助类以快速实现此功能。

示例

use Sabre\HTTP;

class MyRequest extends HTTP\RequestDecorator {

    function isLoggedIn() {

        return true;

    }

}

我们的应用程序假设真正的Request对象是在其他地方由其他子系统实例化的。这可以简单地是一个像在应用程序顶部调用$request = Sapi::getRequest()这样的调用,也可能是在某个单元测试中。

在当前子系统内,我们所知道的就是我们收到了一个$request,并且它实现了Sabre\HTTP\RequestInterface接口。要装饰此对象,我们只需要做

$request = new MyRequest($request);

就这样;我们现在有了isLoggedIn方法,而不必触及核心实例。

客户端

此包还包含一个简单的cURL包装器,这将允许您使用您已经熟悉的RequestResponse对象编写简单的客户端。

这绝对不是像Guzzle这样的东西的替代品,但它提供了一个简单轻量级的API,用于偶尔的API调用。

用法

use Sabre\HTTP;

$request = new HTTP\Request('GET', 'http://example.org/');
$request->setHeader('X-Foo', 'Bar');

$client = new HTTP\Client();
$response = $client->send($request);

echo $response->getBodyAsString();

客户端使用sabre/event发出3个事件:beforeRequestafterRequesterror

$client = new HTTP\Client();
$client->on('beforeRequest', function($request) {

    // You could use beforeRequest to, for example, inject a few extra headers
    // into the Request object.

});

$client->on('afterRequest', function($request, $response) {

    // The afterRequest event could be a good time to do some logging, or
    // do some rewriting in the response.

});

$client->on('error', function($request, $response, &$retry, $retryCount) {

    // The error event is triggered for every response with an HTTP code higher
    // than 399.

});

$client->on('error:401', function($request, $response, &$retry, $retryCount) {

    // You can also listen for specific error codes. This example shows how
    // to inject HTTP authentication headers if a 401 was returned.

    if ($retryCount > 1) {
        // We're only going to retry exactly once.
    }

    $request->setHeader('Authorization', 'Basic xxxxxxxxxx');
    $retry = true;

});

异步请求

Client也支持异步请求。如果您需要执行多个可以并行执行请求,这特别有用。

此功能的底层系统是简单的cURL多请求处理程序,但它提供了更友好的API来处理此功能。

示例用法

use Sabre\HTTP;

$request = new Request('GET', 'http://localhost/');
$client = new Client();

// Executing 1000 requests
for ($i = 0; $i < 1000; $i++) {
    $client->sendAsync(
        $request,
        function(ResponseInterface $response) {
            // Success handler
        },
        function($error) {
            // Error handler
        }
    ); 
}

// Wait for all requests to get a result.
$client->wait();

查看examples/asyncclient.php获取更多信息。

编写反向代理

结合所有这些工具,编写简单的反向HTTP代理变得非常容易。

use
    Sabre\HTTP\Sapi,
    Sabre\HTTP\Client;

// The url we're proxying to.
$remoteUrl = 'http://example.org/';

// The url we're proxying from. Please note that this must be a relative url,
// and basically acts as the base url.
//
// If your $remoteUrl doesn't end with a slash, this one probably shouldn't
// either.
$myBaseUrl = '/reverseproxy.php';
// $myBaseUrl = '/~evert/sabre/http/examples/reverseproxy.php/';

$request = Sapi::getRequest();
$request->setBaseUrl($myBaseUrl);

$subRequest = clone $request;

// Removing the Host header.
$subRequest->removeHeader('Host');

// Rewriting the url.
$subRequest->setUrl($remoteUrl . $request->getPath());

$client = new Client();

// Sends the HTTP request to the server
$response = $client->send($subRequest);

// Sends the response back to the client that connected to the proxy.
Sapi::sendResponse($response);

请求和响应API

请求

/**
 * Creates the request object
 *
 * @param string $method
 * @param string $url
 * @param array $headers
 * @param resource $body
 */
public function __construct($method = null, $url = null, array $headers = null, $body = null);

/**
 * Returns the current HTTP method
 *
 * @return string
 */
function getMethod();

/**
 * Sets the HTTP method
 *
 * @param string $method
 * @return void
 */
function setMethod($method);

/**
 * Returns the request url.
 *
 * @return string
 */
function getUrl();

/**
 * Sets the request url.
 *
 * @param string $url
 * @return void
 */
function setUrl($url);

/**
 * Returns the absolute url.
 *
 * @return string
 */
function getAbsoluteUrl();

/**
 * Sets the absolute url.
 *
 * @param string $url
 * @return void
 */
function setAbsoluteUrl($url);

/**
 * Returns the current base url.
 *
 * @return string
 */
function getBaseUrl();

/**
 * Sets a base url.
 *
 * This url is used for relative path calculations.
 *
 * The base url should default to /
 *
 * @param string $url
 * @return void
 */
function setBaseUrl($url);

/**
 * Returns the relative path.
 *
 * This is being calculated using the base url. This path will not start
 * with a slash, so it will always return something like
 * 'example/path.html'.
 *
 * If the full path is equal to the base url, this method will return an
 * empty string.
 *
 * This method will also urldecode the path, and if the url was encoded as
 * ISO-8859-1, it will convert it to UTF-8.
 *
 * If the path is outside the base url, a LogicException will be thrown.
 *
 * @return string
 */
function getPath();

/**
 * Returns the list of query parameters.
 *
 * This is equivalent to PHP's $_GET superglobal.
 *
 * @return array
 */
function getQueryParameters();

/**
 * Returns the POST data.
 *
 * This is equivalent to PHP's $_POST superglobal.
 *
 * @return array
 */
function getPostData();

/**
 * Sets the post data.
 *
 * This is equivalent to PHP's $_POST superglobal.
 *
 * This would not have been needed if POST data was accessible as
 * php://input, but unfortunately we need to special-case it.
 *
 * @param array $postData
 * @return void
 */
function setPostData(array $postData);

/**
 * Returns an item from the _SERVER array.
 *
 * If the value does not exist in the array, null is returned.
 *
 * @param string $valueName
 * @return string|null
 */
function getRawServerValue($valueName);

/**
 * Sets the _SERVER array.
 *
 * @param array $data
 * @return void
 */
function setRawServerData(array $data);

/**
 * Returns the body as a readable stream resource.
 *
 * Note that the stream may not be rewindable, and therefore may only be
 * read once.
 *
 * @return resource
 */
function getBodyAsStream();

/**
 * Returns the body as a string.
 *
 * Note that because the underlying data may be based on a stream, this
 * method could only work correctly the first time.
 *
 * @return string
 */
function getBodyAsString();

/**
 * Returns the message body, as its internal representation.
 *
 * This could be either a string or a stream.
 *
 * @return resource|string
 */
function getBody();

/**
 * Updates the body resource with a new stream.
 *
 * @param resource $body
 * @return void
 */
function setBody($body);

/**
 * Returns all the HTTP headers as an array.
 *
 * @return array
 */
function getHeaders();

/**
 * Returns a specific HTTP header, based on its name.
 *
 * The name must be treated as case-insensitive.
 *
 * If the header does not exist, this method must return null.
 *
 * @param string $name
 * @return string|null
 */
function getHeader($name);

/**
 * Updates an HTTP header.
 *
 * The case-sensitivity of the name value must be retained as-is.
 *
 * @param string $name
 * @param string $value
 * @return void
 */
function setHeader($name, $value);

/**
 * Resets HTTP headers
 *
 * This method overwrites all existing HTTP headers
 *
 * @param array $headers
 * @return void
 */
function setHeaders(array $headers);

/**
 * Adds a new set of HTTP headers.
 *
 * Any header specified in the array that already exists will be
 * overwritten, but any other existing headers will be retained.
 *
 * @param array $headers
 * @return void
 */
function addHeaders(array $headers);

/**
 * Removes an HTTP header.
 *
 * The specified header name must be treated as case-insensitive.
 * This method should return true if the header was successfully deleted,
 * and false if the header did not exist.
 *
 * @return bool
 */
function removeHeader($name);

/**
 * Sets the HTTP version.
 *
 * Should be 1.0, 1.1 or 2.0.
 *
 * @param string $version
 * @return void
 */
function setHttpVersion($version);

/**
 * Returns the HTTP version.
 *
 * @return string
 */
function getHttpVersion();

响应

/**
 * Returns the current HTTP status.
 *
 * This is the status-code as well as the human-readable string.
 *
 * @return string
 */
function getStatus();

/**
 * Sets the HTTP status code.
 *
 * This can be either the full HTTP status code with human-readable string,
 * for example, "403 I can't let you do that, Dave".
 *
 * Or just the code, in which case the appropriate default message will be
 * added.
 *
 * @param string|int $status
 * @throws \InvalidArgumentExeption
 * @return void
 */
function setStatus($status);

/**
 * Returns the body as a readable stream resource.
 *
 * Note that the stream may not be rewindable, and therefore may only be
 * read once.
 *
 * @return resource
 */
function getBodyAsStream();

/**
 * Returns the body as a string.
 *
 * Note that because the underlying data may be based on a stream, this
 * method could only work correctly the first time.
 *
 * @return string
 */
function getBodyAsString();

/**
 * Returns the message body, as its internal representation.
 *
 * This could be either a string or a stream.
 *
 * @return resource|string
 */
function getBody();


/**
 * Updates the body resource with a new stream.
 *
 * @param resource $body
 * @return void
 */
function setBody($body);

/**
 * Returns all the HTTP headers as an array.
 *
 * @return array
 */
function getHeaders();

/**
 * Returns a specific HTTP header, based on its name.
 *
 * The name must be treated as case-insensitive.
 *
 * If the header does not exist, this method must return null.
 *
 * @param string $name
 * @return string|null
 */
function getHeader($name);

/**
 * Updates an HTTP header.
 *
 * The case-sensitivity of the name value must be retained as-is.
 *
 * @param string $name
 * @param string $value
 * @return void
 */
function setHeader($name, $value);

/**
 * Resets HTTP headers
 *
 * This method overwrites all existing HTTP headers
 *
 * @param array $headers
 * @return void
 */
function setHeaders(array $headers);

/**
 * Adds a new set of HTTP headers.
 *
 * Any header specified in the array that already exists will be
 * overwritten, but any other existing headers will be retained.
 *
 * @param array $headers
 * @return void
 */
function addHeaders(array $headers);

/**
 * Removes an HTTP header.
 *
 * The specified header name must be treated as case-insensitive.
 * This method should return true if the header was successfully deleted,
 * and false if the header did not exist.
 *
 * @return bool
 */
function removeHeader($name);

/**
 * Sets the HTTP version.
 *
 * Should be 1.0, 1.1 or 2.0.
 *
 * @param string $version
 * @return void
 */
function setHttpVersion($version);

/**
 * Returns the HTTP version.
 *
 * @return string
 */
function getHttpVersion();

由fruux制作

此库由fruux开发。如需商业服务或企业支持,请与我们联系。