PHPackages                             sabre/http - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [HTTP &amp; Networking](/categories/http)
4. /
5. sabre/http

ActiveLibrary[HTTP &amp; Networking](/categories/http)

sabre/http
==========

The sabre/http library provides utilities for dealing with http requests and responses.

7.0.5(8mo ago)19714.4M—0.8%59[3 PRs](https://github.com/sabre-io/http/pulls)8BSD-3-ClausePHPPHP ^7.4 || ^8.0CI passing

Since Oct 7Pushed 4mo ago19 watchersCompare

[ Source](https://github.com/sabre-io/http)[ Packagist](https://packagist.org/packages/sabre/http)[ Docs](https://github.com/fruux/sabre-http)[ RSS](/packages/sabre-http/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (10)Dependencies (8)Versions (69)Used By (8)

sabre/http
==========

[](#sabrehttp)

This library provides a toolkit to make working with the [HTTP protocol](https://tools.ietf.org/html/rfc2616) easier.

Most PHP scripts run within an 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
------------

[](#build-status)

[![Build Status](https://github.com/sabre-io/http/actions/workflows/ci.yml/badge.svg)](https://github.com/sabre-io/http/actions/workflows/ci.yml/badge.svg)

releaseminimum PHP versionmasterPHP 7.47.0PHP 7.46.0PHP 7.45.1PHP 7.14.2PHP 5.43.0PHP 5.4Installation
------------

[](#installation)

Make sure you have [composer](http://getcomposer.org/) installed. In your project directory, create, or edit a `composer.json` file, and make sure it contains something like this:

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

After that, just hit `composer install` and you should be rolling.

Quick history
-------------

[](#quick-history)

This library came to existence in 2009, as a part of the [`sabre/dav`](http://sabre.io/)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 the scope of just `sabre/dav`.

Although completely independently developed, this library has a LOT of overlap with [Symfony's `HttpFoundation`](https://github.com/symfony/HttpFoundation).

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`](https://github.com/symfony/HttpFoundation).

Getting started
---------------

[](#getting-started)

First and foremost, this library wraps the superglobals. The easiest way to instantiate a request object is as follows:

```
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 its interface:

```
function handleRequest(HTTP\RequestInterface $request) {

    // Do something with this request :)

}
```

A response object you can just create as such:

```
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:

```
HTTP\Sapi::sendResponse($response);
```

This line should generally also appear once in your application (at the very end).

Decorators
----------

[](#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 an instance of `Request` so you would have to override the factory method as well,
3. By controlling the instantiation 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](http://en.wikipedia.org/wiki/Decorator_pattern) to add new behavior where you need it. `sabre/http`provides helper classes to quickly do this.

Example:

```
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 unit test.

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:

```
$request = new MyRequest($request);
```

And that's it; we now have an `isLoggedIn` method, without having to mess with the core instances.

Client
------

[](#client)

This package also contains a simple wrapper around [cURL](http://php.net/curl), 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](http://guzzlephp.org/), but it provides a simple and lightweight API for making the occasional API call.

### Usage

[](#usage)

```
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 events using [`sabre/event`](https://github.com/fruux/sabre-event). `beforeRequest`, `afterRequest` and `error`.

```
$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;

});
```

### Asynchronous requests

[](#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](http://php.net/curl_multi_init), but this provides a much nicer API to handle this.

Sample usage:

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

[](#writing-a-reverse-proxy)

With all these tools combined, it becomes very easy to write a simple reverse http proxy.

```
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);
```

The Request and Response APIs
-----------------------------

[](#the-request-and-response-apis)

### Request

[](#request)

```
/**
 * 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();
```

### Response

[](#response)

```
/**
 * 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();
```

Made at fruux
-------------

[](#made-at-fruux)

This library is being developed by [fruux](https://fruux.com/). Drop us a line for commercial services or enterprise support.

###  Health Score

68

—

FairBetter than 100% of packages

Maintenance69

Regular maintenance activity

Popularity65

Solid adoption and visibility

Community40

Growing community involvement

Maturity83

Battle-tested with a long release history

 Bus Factor1

Top contributor holds 53% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~77 days

Recently: every ~32 days

Total

64

Last Release

125d ago

Major Versions

6.0.2 → 7.0.32023-08-17

5.1.12 → 6.0.32024-09-06

6.0.3 → 7.0.42024-09-06

5.1.13 → 6.0.42025-09-09

6.0.4 → 7.0.52025-09-09

PHP version history (7 changes)2.0.0alpha1PHP &gt;=5.3.1

2.0.0alpha2PHP &gt;=5.4

5.0.0-alpha1PHP &gt;=7.0

5.0.1PHP ^7.0

5.1.0PHP ^7.1

5.1.1PHP ^7.1 || ^8.0

6.0.0PHP ^7.4 || ^8.0

### Community

Maintainers

![](https://www.gravatar.com/avatar/2ec28c32d012f276f61b0b58cabe3c8f674166732d9b20eeddc3f9807857ba10?d=identicon)[evert](/maintainers/evert)

![](https://www.gravatar.com/avatar/d916220fea2bfe2d822214b0f188d1087035c66245431ae0dc2df4fbfbf81f6c?d=identicon)[dominik](/maintainers/dominik)

---

Top Contributors

[![evert](https://avatars.githubusercontent.com/u/178960?v=4)](https://github.com/evert "evert (313 commits)")[![phil-davis](https://avatars.githubusercontent.com/u/1535615?v=4)](https://github.com/phil-davis "phil-davis (154 commits)")[![staabm](https://avatars.githubusercontent.com/u/120441?v=4)](https://github.com/staabm "staabm (30 commits)")[![DeepDiver1975](https://avatars.githubusercontent.com/u/1005065?v=4)](https://github.com/DeepDiver1975 "DeepDiver1975 (21 commits)")[![Hywan](https://avatars.githubusercontent.com/u/946104?v=4)](https://github.com/Hywan "Hywan (21 commits)")[![jakobsack](https://avatars.githubusercontent.com/u/776911?v=4)](https://github.com/jakobsack "jakobsack (7 commits)")[![DominikTo](https://avatars.githubusercontent.com/u/1384635?v=4)](https://github.com/DominikTo "DominikTo (5 commits)")[![mrcnpdlk](https://avatars.githubusercontent.com/u/22945316?v=4)](https://github.com/mrcnpdlk "mrcnpdlk (4 commits)")[![DanielRuf](https://avatars.githubusercontent.com/u/827205?v=4)](https://github.com/DanielRuf "DanielRuf (3 commits)")[![cedric-anne](https://avatars.githubusercontent.com/u/33253653?v=4)](https://github.com/cedric-anne "cedric-anne (3 commits)")[![petrkotek](https://avatars.githubusercontent.com/u/5679032?v=4)](https://github.com/petrkotek "petrkotek (3 commits)")[![amrita-shrestha](https://avatars.githubusercontent.com/u/54478846?v=4)](https://github.com/amrita-shrestha "amrita-shrestha (2 commits)")[![C0pyR1ght](https://avatars.githubusercontent.com/u/8182083?v=4)](https://github.com/C0pyR1ght "C0pyR1ght (2 commits)")[![come-nc](https://avatars.githubusercontent.com/u/91878298?v=4)](https://github.com/come-nc "come-nc (2 commits)")[![Dartui](https://avatars.githubusercontent.com/u/2657856?v=4)](https://github.com/Dartui "Dartui (2 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (2 commits)")[![dratini0](https://avatars.githubusercontent.com/u/1625485?v=4)](https://github.com/dratini0 "dratini0 (2 commits)")[![icewind1991](https://avatars.githubusercontent.com/u/1283854?v=4)](https://github.com/icewind1991 "icewind1991 (2 commits)")[![schoetju](https://avatars.githubusercontent.com/u/55851807?v=4)](https://github.com/schoetju "schoetju (2 commits)")[![LukasReschke](https://avatars.githubusercontent.com/u/878997?v=4)](https://github.com/LukasReschke "LukasReschke (1 commits)")

---

Tags

http

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/sabre-http/health.svg)

```
[![Health](https://phpackages.com/badges/sabre-http/health.svg)](https://phpackages.com/packages/sabre-http)
```

###  Alternatives

[guzzlehttp/psr7

PSR-7 message implementation that also provides common utility methods

7.9k1.0B3.2k](/packages/guzzlehttp-psr7)[psr/http-message

Common interface for HTTP messages

7.1k1.0B5.5k](/packages/psr-http-message)[psr/http-factory

PSR-17: Common interfaces for PSR-7 HTTP message factories

1.9k692.9M1.9k](/packages/psr-http-factory)[psr/http-client

Common interface for HTTP clients

1.7k680.7M2.1k](/packages/psr-http-client)[symfony/http-client

Provides powerful methods to fetch HTTP resources synchronously or asynchronously

2.0k314.0M3.4k](/packages/symfony-http-client)[psr/link

Common interfaces for HTTP links

2.5k144.1M68](/packages/psr-link)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
