PHPackages                             phly/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. phly/http

Abandoned → [zendframework/zend-diactoros](/?search=zendframework%2Fzend-diactoros)ArchivedLibrary[HTTP &amp; Networking](/categories/http)

phly/http
=========

PSR HTTP Message implementations

0.14.1(11y ago)16493.2k—0%28[1 issues](https://github.com/phly/http/issues)3BSD-2-ClausePHPPHP &gt;=5.4.8

Since Aug 25Pushed 9mo ago16 watchersCompare

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

READMEChangelog (2)Dependencies (3)Versions (36)Used By (3)

phly/http
=========

[](#phlyhttp)

> ⚠️ **Archived 2025-08-17**
>
> ## Abandoned! Or, rather, rebranded!
>
> [](#abandoned-or-rather-rebranded)
>
> phly/http has moved to the zendframework organization as [zend-diactoros](https://github.com/zendframework/zend-diactoros)(Diactoros, literally "the messenger," an epithet for Hermes).
>
> Please use that package instead, and contribute issues and pull requests against it I have closed issues and pull requests against phly/http at this time.

[![Scrutinizer Code Quality](https://camo.githubusercontent.com/58104e7f1ac70de4cff19c3dd8e9cfa27a38c2a7c74ff035b35d93db0376d469/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f70686c792f687474702f6261646765732f7175616c6974792d73636f72652e706e673f623d6d6173746572)](https://scrutinizer-ci.com/g/phly/http/?branch=master)[![Code Coverage](https://camo.githubusercontent.com/6a9502ade584f06d92d5d02ae057199ff43d105d8b225a84afffe7786a060485/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f70686c792f687474702f6261646765732f636f7665726167652e706e673f623d6d6173746572)](https://scrutinizer-ci.com/g/phly/http/?branch=master)[![Scrutinizer Build Status](https://camo.githubusercontent.com/0ab7b4ea37c2da5e8a4265677be0c1580d1b8ae73391dfb652a738f7e1afc6fb/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f70686c792f687474702f6261646765732f6275696c642e706e673f623d6d6173746572)](https://scrutinizer-ci.com/g/phly/http/build-status/master)

`phly/http` is a PHP package containing implementations of the [accepted PSR-7 HTTP message interfaces](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-7-http-message.md), as well as a "server" implementation similar to [node's http.Server](http://nodejs.org/api/http.html).

This package exists:

- to provide a proof-of-concept of the proposed PSR HTTP message interfaces with relation to server-side applications.
- to provide a node-like paradigm for PHP front controllers.
- to provide a common methodology for marshaling a request from the server environment.

Installation and Requirements
-----------------------------

[](#installation-and-requirements)

Install this library using composer:

```
$ composer require phly/http
```

`phly/http` has the following dependencies (which are managed by Composer):

- `psr/http-message`, which defines interfaces for HTTP messages, including requests and responses. `phly/http` provides implementations of each of these.

Usage
-----

[](#usage)

Usage will differ based on whether you are writing an HTTP client, or a server-side application.

For HTTP client purposes, you will create and populate a `Request` instance, and the client should return a `Response` instance.

For server-side applications, you will create a `ServerRequest` instance, and populate and return a `Response` instance.

### HTTP Clients

[](#http-clients)

A client will *send* a request, and *return* a response. As a developer, you will *create* and *populate* the request, and then *introspect* the response. Both requests and responses are immutable; if you make changes -- e.g., by calling setter methods -- you must capture the return value, as it is a new instance.

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

(Note: phly/http does NOT ship with a client implementation; the above is just an illustration of a possible implementation.)

### Server-Side Applications

[](#server-side-applications)

Server-side applications will need to marshal the incoming request based on superglobals, and will then populate and send a response.

#### Marshaling an incoming request

[](#marshaling-an-incoming-request)

PHP contains a plethora of information about the incoming request, and keeps that information in a variety of locations. `Phly\Http\ServerRequestFactory::fromGlobals()` can simplify marshaling that information into a request instance.

You can call the factory method with or without the following arguments, in the following order:

- `$server`, typically `$_SERVER`
- `$query`, typically `$_GET`
- `$body`, typically `$_POST`
- `$cookies`, typically `$_COOKIE`
- `$files`, typically `$_FILES`

The method will then return a `Phly\Http\ServerRequest` instance. If any argument is omitted, the associated superglobal will be used.

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

#### Manipulating the response

[](#manipulating-the-response)

Use the response object to add headers and provide content for the response. Writing to the body does not create a state change in the response, so it can be done without capturing the return value. Manipulating headers does, however.

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

#### "Serving" an application

[](#serving-an-application)

`Phly\Http\Server` mimics a portion of the API of node's `http.Server` class. It invokes a callback, passing it an `ServerRequest`, an `Response`, and optionally a callback to use for incomplete/unhandled requests.

You can create a server in one of three ways:

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

Server callbacks can expect up to three arguments, in the following order:

- `$request` - the request object
- `$response` - the response object
- `$done` - an optional callback to call when complete

Once you have your server instance, you must instruct it to listen:

```
$server->listen();
```

At this time, you can optionally provide a callback to `listen()`; this will be passed to the handler as the third argument (`$done`):

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

Typically, the `listen` callback will be an error handler, and can expect to receive the request, response, and error as its arguments (though the error may be null).

API
---

[](#api)

### Request Message

[](#request-message)

`Phly\Http\Request` implements `Psr\Http\Message\RequestInterface`, and is intended for client-side requests. It includes the following methods:

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

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

Requests are immutable. Any methods that would change state -- those prefixed with `with` and `without` -- all return a new instance with the changes requested.

### ServerRequest Message

[](#serverrequest-message)

For server-side applications, `Phly\Http\ServerRequest` implements `Psr\Http\Message\ServerRequestInterface`, which provides access to the elements of an HTTP request, as well as uniform access to the various elements of incoming data. The methods included are:

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

The `ServerRequest` is immutable. Any methods that would change state -- those prefixed with `with` and `without` -- all return a new instance with the changes requested. Server parameters are considered completely immutable, however, as they cannot be recalculated, and, rather, is a source for other values.

### Response Message

[](#response-message)

`Phly\Http\Response` provides an implementation of `Psr\Http\Message\ResponseInterface`, an object to be used to aggregate response information for both HTTP clients and server-side applications, including headers and message body content. It includes the following:

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

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

Like the `Request` and `ServerRequest`, responses are immutable. Any methods that would change state -- those prefixed with `with` and `without` -- all return a new instance with the changes requested.

#### ServerRequestFactory

[](#serverrequestfactory)

This static class can be used to marshal a `ServerRequest` instance from the PHP environment. The primary entry point is `Phly\Http\ServerRequestFactory::fromGlobals(array $server, array $query, array $body, array $cookies, array $files)`. This method will create a new `ServerRequest` instance with the data provided. Examples of usage are:

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

[](#uri)

`Phly\Http\Uri` is an implementation of `Psr\Http\Message\UriInterface`, and models and validates URIs. It implements `__toString()`, allowing it to be represented as a string and `echo()`'d directly. The following methods are pertinent:

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

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

Like the various message objects, URIs are immutable. Any methods that would change state -- those prefixed with `with` and `without` -- all return a new instance with the changes requested.

### Stream

[](#stream)

`Phly\Http\Stream` is an implementation of `Psr\Http\Message\StreamInterface`, and provides a number of facilities around manipulating the composed PHP stream resource. The constructor accepts a stream, which may be either:

- a stream identifier; e.g., `php://input`, a filename, etc.
- a PHP stream resource

If a stream identifier is provided, an optional second parameter may be provided, the file mode by which to `fopen` the stream.

`ServerRequest` objects by default use a `php://input` stream set to read-only; `Response` objects by default use a `php://memory` with a mode of `wb+`, allowing binary read/write access.

In most cases, you will not interact with the Stream object directly.

### UploadedFile

[](#uploadedfile)

`Phly\Http\UploadedFile` is an implementation of `Psr\Http\Message\UploadedFileInterface`, and provides abstraction around a single uploaded file, including behavior for interacting with it as a stream or moving it to a filesystem location.

In most cases, you will only use the methods defined in the `UploadedFileInterface`.

### Server

[](#server)

`Phly\Http\Server` represents a server capable of executing a callback. It has four methods:

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

You can create an instance of the `Server` using any of the constructor, `createServer()`, or `createServerFromRequest()` methods. If you wish to use the default request and response implementations, `createServer($middleware, $_SERVER, $_GET, $_POST, $_COOKIE, $_FILES)` is the recommended option, as this method will also marshal the `ServerRequest` object based on the PHP request environment. If you wish to use your own implementations, pass them to the constructor or `createServerFromRequest()` method (the latter will create a default `Response` instance if you omit it).

`listen()` executes the callback. If a `$finalHandler` is provided, it will be passed as the third argument to the `$callback` registered with the server.

Emitting responses
------------------

[](#emitting-responses)

If you are using a non-SAPI PHP implementation and wish to use the `Server` class, or if you do not want to use the `Server` implementation but want to emit a response, this package provides an interface, `Phly\Http\Response\EmitterInterface`, defining a method `emit()` for emitting the response. A single implementation is currently available, `Phly\Http\Response\SapiEmitter`, which will use the native PHP functions `header()` and `echo` in order to emit the response. If you are using a non-SAPI implementation, you will need to create your own `EmitterInterface` implementation.

Serialization
-------------

[](#serialization)

At times, it's useful to either create a string representation of a message (serialization), or to cast a string or stream message to an object (deserialization). This package provides features for this in `Phly\Http\Request\Serializer` and `Phly\Http\Response\Serializer`; each provides the following static methods:

- `fromString($message)` will create either a `Request` or `Response` instance (based on the serializer used) from the string message.
- `fromStream(Psr\Http\Message\StreamInterface $stream)` will create either a `Request` or `Response` instance (based on the serializer used) from the provided stream.
- `toString(Psr\Http\Message\RequestInterface|Psr\Http\Message\ResponseInterface $message)` will create either a string from the provided message.

The deserialization methods (`from*()`) will raise exceptions if errors occur while parsing the message. The serialization methods (`toString()`) will raise exceptions if required data for serialization is not present in the message instance.

###  Health Score

47

—

FairBetter than 94% of packages

Maintenance41

Moderate activity, may be stable

Popularity47

Moderate usage in the ecosystem

Community32

Small or concentrated contributor base

Maturity60

Established project with proven stability

 Bus Factor1

Top contributor holds 88.2% 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 ~7 days

Recently: every ~2 days

Total

36

Last Release

4015d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/25943?v=4)[Matthew Weier O'Phinney](/maintainers/weierophinney)[@weierophinney](https://github.com/weierophinney)

---

Top Contributors

[![weierophinney](https://avatars.githubusercontent.com/u/25943?v=4)](https://github.com/weierophinney "weierophinney (306 commits)")[![vrkansagara](https://avatars.githubusercontent.com/u/12006483?v=4)](https://github.com/vrkansagara "vrkansagara (6 commits)")[![pine3ree](https://avatars.githubusercontent.com/u/3229979?v=4)](https://github.com/pine3ree "pine3ree (6 commits)")[![harikt](https://avatars.githubusercontent.com/u/120454?v=4)](https://github.com/harikt "harikt (5 commits)")[![mtymek](https://avatars.githubusercontent.com/u/777893?v=4)](https://github.com/mtymek "mtymek (4 commits)")[![GeLoLabs](https://avatars.githubusercontent.com/u/149005863?v=4)](https://github.com/GeLoLabs "GeLoLabs (3 commits)")[![ins0](https://avatars.githubusercontent.com/u/2622534?v=4)](https://github.com/ins0 "ins0 (3 commits)")[![jodiedunlop](https://avatars.githubusercontent.com/u/4055554?v=4)](https://github.com/jodiedunlop "jodiedunlop (2 commits)")[![acelot](https://avatars.githubusercontent.com/u/1065215?v=4)](https://github.com/acelot "acelot (1 commits)")[![ptlis](https://avatars.githubusercontent.com/u/508422?v=4)](https://github.com/ptlis "ptlis (1 commits)")[![sagikazarmark](https://avatars.githubusercontent.com/u/1226384?v=4)](https://github.com/sagikazarmark "sagikazarmark (1 commits)")[![samsonasik](https://avatars.githubusercontent.com/u/459648?v=4)](https://github.com/samsonasik "samsonasik (1 commits)")[![sasezaki](https://avatars.githubusercontent.com/u/42755?v=4)](https://github.com/sasezaki "sasezaki (1 commits)")[![trowski](https://avatars.githubusercontent.com/u/1628287?v=4)](https://github.com/trowski "trowski (1 commits)")[![vitorbrandao](https://avatars.githubusercontent.com/u/109226?v=4)](https://github.com/vitorbrandao "vitorbrandao (1 commits)")[![GeeH](https://avatars.githubusercontent.com/u/613376?v=4)](https://github.com/GeeH "GeeH (1 commits)")[![henriquemoody](https://avatars.githubusercontent.com/u/154023?v=4)](https://github.com/henriquemoody "henriquemoody (1 commits)")[![dzentota](https://avatars.githubusercontent.com/u/834595?v=4)](https://github.com/dzentota "dzentota (1 commits)")[![joksnet](https://avatars.githubusercontent.com/u/145141?v=4)](https://github.com/joksnet "joksnet (1 commits)")[![marcosh](https://avatars.githubusercontent.com/u/2643972?v=4)](https://github.com/marcosh "marcosh (1 commits)")

---

Tags

http

###  Code Quality

TestsPHPUnit

Code StylePHP\_CodeSniffer

### Embed Badge

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

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

###  Alternatives

[guzzlehttp/psr7

PSR-7 message implementation that also provides common utility methods

7.9k1.0B3.2k](/packages/guzzlehttp-psr7)[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/psr-http-message-bridge

PSR HTTP message bridge

1.3k296.6M807](/packages/symfony-psr-http-message-bridge)[league/uri-interfaces

Common tools for parsing and resolving RFC3987/RFC3986 URI

536204.9M23](/packages/league-uri-interfaces)[php-http/client-common

Common HTTP Client implementations and tools for HTTPlug

1.1k225.5M571](/packages/php-http-client-common)

PHPackages © 2026

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