A PSR-7 HTTP message library for PHP 8.1+.
composer require effectra/http-message- PHP ^8.1
- psr/http-message ^1.1 || ^2.0
- PSR-7 compliant —
Request,Response,ServerRequest,Uri,Stream,UploadedFile,Message - Case-insensitive headers —
hasHeader(),getHeader(),withHeader(), etc. all normalize to lowercase - Immutable with* methods — all PSR-7
with*methods return new instances; mutableset*methods are also available - Response factories —
withJson(),static json(),static html(),static emptyResponse() - ServerRequest utilities —
fromGlobals()factory,replaceHeader()helper - Stream from file path — constructor accepts a file path string and opens it as a resource
- UploadedFile —
getStream()reads from the actual uploaded file - PHP 8 features —
finalclasses,readonlyproperties,#[Immutable]attribute - Comprehensive test suite — 196+ tests, PHPStan level 6 clean
use Effectra\Http\Message\Request;
use Effectra\Http\Message\Uri;
$uri = new Uri('https://api.example.com/users');
$request = new Request('POST', $uri, ['Content-Type' => 'application/json'], '{"name":"John"}');
echo $request->getMethod(); // POST
echo $request->getHeaderLine('Content-Type'); // application/jsonImmutable with* methods:
$new = $request->withMethod('PUT')->withUri(new Uri('https://other.com'));
// $request is unchangedMutable set* methods:
$request->setMethod('PATCH')->setUri(new Uri('/local'));
// $request is modified in placeuse Effectra\Http\Message\Response;
$response = new Response(200, ['X-Custom' => 'value'], 'OK');
echo $response->getStatusCode(); // 200
echo $response->getReasonPhrase(); // OK// JSON response
$res = Response::json(['status' => 'ok']);
$res = (new Response())->withJson(['error' => 'bad'], 400);
// HTML response
$res = Response::html('<h1>Hello</h1>', 200);
// Empty response (e.g. 204 No Content)
$res = Response::emptyResponse(204);All standard HTTP status codes (100–511) are available as class constants:
Response::HTTP_OK; // 200
Response::HTTP_NOT_FOUND; // 404
Response::HTTP_I_AM_A_TEAPOT; // 418use Effectra\Http\Message\ServerRequest;
$request = ServerRequest::fromGlobals();
echo $request->getMethod(); // GET, POST, etc.
echo $request->getServerParams()['REMOTE_ADDR'];
$input = $request->getParsedBody(); // POST / JSON bodyuse Effectra\Http\Message\Uri;
$uri = new Uri('https://example.com/path?q=hello#section');
echo $uri->getScheme(); // https
echo $uri->getHost(); // example.com
echo $uri->getPath(); // /path
echo $uri->getQuery(); // q=hello
$new = $uri->withScheme('http')->withHost('other.org');use Effectra\Http\Message\Stream;
// From a string
$stream = new Stream('content');
echo $stream->getContents(); // content
// From a file path (opens automatically)
$stream = new Stream('/path/to/file.txt');
// From a resource
$stream = new Stream(fopen('php://memory', 'r+'));
$stream->write('data');use Effectra\Http\Message\UploadedFile;
$file = new UploadedFile(
$_FILES['avatar']['tmp_name'],
$_FILES['avatar']['size'],
$_FILES['avatar']['error'],
$_FILES['avatar']['name'],
$_FILES['avatar']['type']
);
$stream = $file->getStream(); // read file contents
echo $file->getClientFilename(); // original name
$file->moveTo('/storage/avatars/1.jpg');All header operations are case-insensitive:
$request = new Request('GET', '/', ['Content-Type' => 'text/html']);
$request->hasHeader('content-type'); // true
$request->hasHeader('CONTENT-TYPE'); // true
$request->hasHeader('Content-Type'); // true
$request->getHeader('CONTENT-TYPE'); // ['text/html']
$cloned = $request->withoutHeader('content-type');
$cloned = $request->withAddedHeader('X-Custom', 'val');use Effectra\Http\Message\Attribute\Immutable;
#[Immutable('This class follows the PSR-7 immutable pattern')]
class MyMessage
{
// ...
}#[Immutable] and #[Deprecated] attributes are available for documentation and static analysis.
composer run phpstanLevel 6 with baseline. The _ide_helper.php file provides additional type information for better IDE support.
composer testContributions are welcome. Please open an issue or submit a pull request.
MIT