Skip to content

InitPHP/HTTP

InitPHP HTTP

Standards-compliant PSR-7 message, PSR-17 factory, PSR-18 client and SAPI response emitter for PHP 7.4+.

Latest Stable Version Total Downloads License PHP Version Require Tests Static Analysis

A single dependency-light package that ships the four building blocks every PHP project ends up wiring by hand: immutable HTTP messages, a unified factory, a cURL-backed client, and an emitter that converts a ResponseInterface into bytes on the wire.

composer require initphp/http
use InitPHP\HTTP\Facade\Factory;
use InitPHP\HTTP\Facade\Emitter;

$response = Factory::createResponse(200, 'OK')
    ->withHeader('Content-Type', 'text/plain; charset=utf-8');
$response->getBody()->write('Hello, world!');

Emitter::emit($response);

Table of Contents


Features

  • PSR-7 v1 & v2 compatible — works with the entire PSR-7 ecosystem.
  • PSR-17 factory — one class implements every factory interface (Request, Response, ServerRequest, Stream, UploadedFile, Uri).
  • PSR-18 client backed by cURL with sane production defaults: 30 s request timeout, 10 s connect timeout, redirect following, raw CURLOPT_* overrides without subclassing.
  • SAPI emitter that streams the response to the browser with optional chunked output and Content-Range support.
  • Lazy static facades for projects that prefer Factory::createResponse() over instantiating helpers explicitly.
  • Strict PSR-7 immutabilitywith*() returns deep-cloned messages; mutating the clone never touches the original (verified by a dedicated immutability test suite).
  • Zero runtime dependencies outside psr/http-*. ext-curl is only required when you actually use the client.
  • Passes the upstream php-http/psr7-integration-tests and http-interop/http-factory-tests suites.

Requirements

Component Minimum
PHP 7.4
ext-json always required
ext-curl required by InitPHP\HTTP\Client\Client (PSR-18 transport)
psr/http-message `^1.0
psr/http-factory ^1.0
psr/http-client ^1.0

Tested on PHP 7.4, 8.0, 8.1, 8.2, 8.3 and 8.4 in CI.

Installation

composer require initphp/http

Quick Start

Building a PSR-7 Request

use InitPHP\HTTP\Message\Request;

$request = new Request(
    'POST',
    'https://api.example.com/users',
    ['Accept' => 'application/json'],
    json_encode(['name' => 'Ada']),
    '1.1'
);

$request = $request->withHeader('Content-Type', 'application/json; charset=utf-8');

Building a PSR-7 Response

use InitPHP\HTTP\Message\Response;

$response = (new Response())
    ->withStatus(201, 'Created')
    ->withHeader('Location', '/users/42');

$response->getBody()->write('{"id":42}');

Convenience producers on the concrete Response:

$response = (new Response())->json(['id' => 42], 201);
$response = (new Response())->redirect('https://example.com/welcome', 302);

Sending an HTTP request (PSR-18)

use InitPHP\HTTP\Client\Client;
use InitPHP\HTTP\Message\Request;

$client = (new Client())
    ->withTimeout(10)
    ->withConnectTimeout(3)
    ->withUserAgent('my-app/1.0');

$response = $client->sendRequest(
    new Request('GET', 'https://httpbin.org/get')
);

echo $response->getStatusCode();          // 200
echo (string) $response->getBody();       // {"args":{},"headers":{...},...}

Higher-level helpers when you don't want to build a Request by hand:

$response = $client->get('https://api.example.com/users');
$response = $client->post('https://api.example.com/users', '{"name":"Ada"}', [
    'Content-Type' => 'application/json',
]);

PSR-18 contract is honoured: 4xx/5xx responses are returned, not thrown. Only transport failures raise Psr\Http\Client\NetworkExceptionInterface.

Emitting a response (SAPI)

use InitPHP\HTTP\Emitter\Emitter;

$emitter = new Emitter(/* strictMode: */ true);
$emitter->emit($response);                  // echoes body in one go

// For large bodies, stream in chunks:
$emitter->emit($response, 8192);

Range requests (Content-Range: bytes 0-1023/...) are honoured automatically.

Hydrating a ServerRequest from globals

use InitPHP\HTTP\Message\ServerRequest;

$request = ServerRequest::createFromGlobals();
// or with explicit data (recommended for tests and long-running runtimes):
$request = ServerRequest::createFromGlobals($server, $get, $post, $cookies, $files);

The factory is stateless — every call returns a fresh instance computed from the supplied arrays. Safe under Swoole, RoadRunner, Octane and FrankenPHP.

Using the static facades

For projects that prefer terseness over explicit DI:

use InitPHP\HTTP\Facade\Factory;
use InitPHP\HTTP\Facade\Client;
use InitPHP\HTTP\Facade\Emitter;

$request  = Factory::createRequest('GET', 'https://example.com');
$response = Client::sendRequest($request);
Emitter::emit($response);

Each facade lazily resolves a singleton on first call; subsequent calls return the same instance. Facades are entirely optional — every facade is just a thin static wrapper over a concrete service class you can instantiate yourself.

Documentation

In-depth guides live under docs/:

PSR Compliance

This package is verified against the official compliance suites:

Suite Result
php-http/psr7-integration-tests passing
http-interop/http-factory-tests (PSR-17) passing
In-house PSR-18 smoke suite against the PHP built-in test server passing
In-house PSR-7 immutability suite passing

Relevant specs: PSR-7, PSR-17, PSR-18.

Migration from 2.x

Version 3.0 is a breaking release. The highlights:

  • The custom InitPHP\HTTP\Message\Interfaces\* interfaces have been removed. Type-hint against the PSR-7 interfaces directly (Psr\Http\Message\RequestInterface, etc.).
  • Request::createFromGlobals() and the magic $request->name = $value parameter bag have been removed. Use ServerRequest::createFromGlobals() (now stateless) and $request->getParsedBody() instead.
  • Client::sendRequest() no longer inspects the concrete Request class — it only sees the PSR-7 contract. Pre-encode array/DOM/XML payloads before calling.
  • Client now defaults to a 30 s request timeout and 10 s connect timeout. Pass ->withTimeout(0) if you need the legacy "no timeout" behaviour.
  • The misspelled facade trait/interface names Facadeble[Interface] are now Facadable[Interface]; the old names remain as @deprecated aliases and will be removed in 4.0.

See docs/upgrade-guide.md for the full migration walk-through and a copy-pasteable code-mod list.

Contributing

Contributions are welcome — bug reports, doc improvements, performance patches, anything.

Security

If you discover a security vulnerability please review the project's Security Policy and report it privately. Please do not file public GitHub issues for security problems.

License

MIT License — Copyright © Muhammet ŞAFAK and contributors.

About

Standards-compliant PSR-7, PSR-17, PSR-18 HTTP messages, factories, cURL client, and SAPI response emitter for PHP 7.4+ (PSR-7 v1 & v2 compatible).

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages