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)16495.0k↑331.4%28[1 issues](https://github.com/phly/http/issues)3BSD-2-ClausePHPPHP &gt;=5.4.8

Since Aug 25Pushed 10mo ago1 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 2d 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 93% of packages

Maintenance39

Infrequent updates — may be unmaintained

Popularity48

Moderate usage in the ecosystem

Community29

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

4061d 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

8.0k1.1B4.0k](/packages/guzzlehttp-psr7)[symfony/psr-http-message-bridge

PSR HTTP message bridge

1.3k320.9M983](/packages/symfony-psr-http-message-bridge)[amphp/http-server

A non-blocking HTTP application server for PHP based on Amp.

1.3k6.7M109](/packages/amphp-http-server)[neuron-core/neuron-ai

The PHP Agentic Framework.

2.0k656.1k38](/packages/neuron-core-neuron-ai)[mezzio/mezzio

PSR-15 Middleware Microframework

3923.8M126](/packages/mezzio-mezzio)[laudis/neo4j-php-client

Neo4j-PHP-Client is the most advanced PHP Client for Neo4j

185702.8k44](/packages/laudis-neo4j-php-client)

PHPackages © 2026

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