diff options
Diffstat (limited to 'vendor/sabre/http/README.md')
-rw-r--r-- | vendor/sabre/http/README.md | 746 |
1 files changed, 746 insertions, 0 deletions
diff --git a/vendor/sabre/http/README.md b/vendor/sabre/http/README.md new file mode 100644 index 000000000..ae03a796e --- /dev/null +++ b/vendor/sabre/http/README.md @@ -0,0 +1,746 @@ +sabre/http +========== + +This library provides a toolkit to make working with the HTTP protocol easier. + +Most PHP scripts run within a HTTP request but accessing information about the +HTTP request is cumbersome at least. + +There's bad practices, inconsistencies and confusion. This library is +effectively a wrapper around the following PHP constructs: + +For Input: + +* `$_GET`, +* `$_POST`, +* `$_SERVER`, +* `php://input` or `$HTTP_RAW_POST_DATA`. + +For output: + +* `php://output` or `echo`, +* `header()`. + +What this library provides, is a `Request` object, and a `Response` object. + +The objects are extendable and easily mockable. + +Build status +------------ + +| branch | status | +| ------ | ------ | +| master | [![Build Status](https://travis-ci.org/fruux/sabre-http.svg?branch=master)](https://travis-ci.org/fruux/sabre-http) | +| 3.0 | [![Build Status](https://travis-ci.org/fruux/sabre-http.svg?branch=3.0)](https://travis-ci.org/fruux/sabre-http) | + +Installation +------------ + +Make sure you have [composer][1] installed. In your project directory, create, +or edit a `composer.json` file, and make sure it contains something like this: + +```json +{ + "require" : { + "sabre/http" : "~3.0.0" + } +} +``` + +After that, just hit `composer install` and you should be rolling. + +Quick history +------------- + +This library came to existence in 2009, as a part of the [`sabre/dav`][2] +project, which uses it heavily. + +It got split off into a separate library to make it easier to manage +releases and hopefully giving it use outside of the scope of just `sabre/dav`. + +Although completely independently developed, this library has a LOT of +overlap with [Symfony's `HttpFoundation`][3]. + +Said library does a lot more stuff and is significantly more popular, +so if you are looking for something to fulfill this particular requirement, +I'd recommend also considering [`HttpFoundation`][3]. + + +Getting started +--------------- + +First and foremost, this library wraps the superglobals. The easiest way to +instantiate a request object is as follows: + +```php +use Sabre\HTTP; + +include 'vendor/autoload.php'; + +$request = HTTP\Sapi::getRequest(); +``` + +This line should only happen once in your entire application. Everywhere else +you should pass this request object around using dependency injection. + +You should always typehint on it's interface: + +```php +function handleRequest(HTTP\RequestInterface $request) { + + // Do something with this request :) + +} +``` + +A response object you can just create as such: + +```php +use Sabre\HTTP; + +include 'vendor/autoload.php'; + +$response = new HTTP\Response(); +$response->setStatus(201); // created ! +$response->setHeader('X-Foo', 'bar'); +$response->setBody( + 'success!' +); + +``` + +After you fully constructed your response, you must call: + +```php +HTTP\Sapi::sendResponse($response); +``` + +This line should generally also appear once in your application (at the very +end). + +Decorators +---------- + +It may be useful to extend the `Request` and `Response` objects in your +application, if you for example would like them to carry a bit more +information about the current request. + +For instance, you may want to add an `isLoggedIn` method to the Request +object. + +Simply extending Request and Response may pose some problems: + +1. You may want to extend the objects with new behaviors differently, in + different subsystems of your application, +2. The `Sapi::getRequest` factory always returns a instance of + `Request` so you would have to override the factory method as well, +3. By controlling the instantation and depend on specific `Request` and + `Response` instances in your library or application, you make it harder to + work with other applications which also use `sabre/http`. + +In short: it would be bad design. Instead, it's recommended to use the +[decorator pattern][6] to add new behavior where you need it. `sabre/http` +provides helper classes to quickly do this. + +Example: + +```php +use Sabre\HTTP; + +class MyRequest extends HTTP\RequestDecorator { + + function isLoggedIn() { + + return true; + + } + +} +``` + +Our application assumes that the true `Request` object was instantiated +somewhere else, by some other subsystem. This could simply be a call like +`$request = Sapi::getRequest()` at the top of your application, +but could also be somewhere in a unittest. + +All we know in the current subsystem, is that we received a `$request` and +that it implements `Sabre\HTTP\RequestInterface`. To decorate this object, +all we need to do is: + +```php +$request = new MyRequest($request); +``` + +And that's it, we now have an `isLoggedIn` method, without having to mess +with the core instances. + + +Client +------ + +This package also contains a simple wrapper around [cURL][4], which will allow +you to write simple clients, using the `Request` and `Response` objects you're +already familiar with. + +It's by no means a replacement for something like [Guzzle][7], but it provides +a simple and lightweight API for making the occasional API call. + +### Usage + +```php +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(); +``` + +The client emits 3 event using [`sabre/event`][5]. `beforeRequest`, +`afterRequest` and `error`. + +```php +$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 a 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; + +}); +``` + +### Asynchronous requests + +The `Client` also supports doing asynchronous requests. This is especially handy +if you need to perform a number of requests, that are allowed to be executed +in parallel. + +The underlying system for this is simply [cURL's multi request handler][8], +but this provides a much nicer API to handle this. + +Sample usage: + +```php + +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(); + +``` + +Check out `examples/asyncclient.php` for more information. + +Writing a reverse proxy +----------------------- + +With all these tools combined, it becomes very easy to write a simple reverse +http proxy. + +```php +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 youre $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); +``` + +The Request and Response API's +------------------------------ + +### Request + +```php + +/** + * 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 incoded as + * ISO-8859-1, it will convert it to UTF-8. + * + * If the path is outside of 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 it's 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 it's 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 a HTTP header. + * + * The case-sensitity 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 a HTTP header. + * + * The specified header name must be treated as case-insenstive. + * 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 or 1.1. + * + * @param string $version + * @return void + */ +function setHttpVersion($version); + +/** + * Returns the HTTP version. + * + * @return string + */ +function getHttpVersion(); +``` + +### Response + +```php +/** + * 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 it's 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 it's 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 a HTTP header. + * + * The case-sensitity 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 a HTTP header. + * + * The specified header name must be treated as case-insenstive. + * 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 or 1.1. + * + * @param string $version + * @return void + */ +function setHttpVersion($version); + +/** + * Returns the HTTP version. + * + * @return string + */ +function getHttpVersion(); +``` + +Made at fruux +------------- + +This library is being developed by [fruux](https://fruux.com/). Drop us a line for commercial services or enterprise support. + +[1]: http://getcomposer.org/ +[2]: http://sabre.io/ +[3]: https://github.com/symfony/HttpFoundation +[4]: http://php.net/curl +[5]: https://github.com/fruux/sabre-event +[6]: http://en.wikipedia.org/wiki/Decorator_pattern +[7]: http://guzzlephp.org/ +[8]: http://php.net/curl_multi_init |