PHPackages                             chillerlan/php-http-message-utils - 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. chillerlan/php-http-message-utils

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

chillerlan/php-http-message-utils
=================================

PSR-7/17/18 utilities

2.2.2(1y ago)018.6k↓25%4MITPHPPHP ^8.1

Since Mar 30Pushed 1y ago1 watchersCompare

[ Source](https://github.com/chillerlan/php-http-message-utils)[ Packagist](https://packagist.org/packages/chillerlan/php-http-message-utils)[ Fund](https://ko-fi.com/codemasher)[ RSS](/packages/chillerlan-php-http-message-utils/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (10)Dependencies (11)Versions (15)Used By (4)

chillerlan/php-http-message-utils
=================================

[](#chillerlanphp-http-message-utils)

A collection of framework-agnostic utilities for use with [PSR-7 Message implementations](https://www.php-fig.org/psr/psr-7/).

[![PHP Version Support](https://camo.githubusercontent.com/1c30ed8e1eb5ed920cefbb3dbe3e23c782571c286fe686e592b216700a68783a/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f6368696c6c65726c616e2f7068702d687474702d6d6573736167652d7574696c733f6c6f676f3d70687026636f6c6f723d383839324246)](https://www.php.net/supported-versions.php)[![version](https://camo.githubusercontent.com/84f12b0f605294ca3ca335e62abc41c4aa8eafe6d99c29198433f8d9e6b3e2b4/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6368696c6c65726c616e2f7068702d687474702d6d6573736167652d7574696c733f6c6f676f3d7061636b6167697374)](https://packagist.org/packages/chillerlan/php-http-message-utils)[![license](https://camo.githubusercontent.com/04039f484e92cc2d79a08bc4eaef4c411f58cffe48ccc95436867e7a35fc7584/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f6368696c6c65726c616e2f7068702d687474702d6d6573736167652d7574696c73)](https://github.com/chillerlan/php-http-message-utils/blob/main/LICENSE)[![Continuous Integration](https://camo.githubusercontent.com/42a50e37aecb150c851f4b74543dc601d1c81abed7f8673ca6b8004ded335683/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6368696c6c65726c616e2f7068702d687474702d6d6573736167652d7574696c732f63692e796d6c3f6272616e63683d6d61696e266c6f676f3d676974687562)](https://github.com/chillerlan/php-http-message-utils/actions/workflows/ci.yml?query=branch%3Amain)[![Coverage](https://camo.githubusercontent.com/37945d7857bb9e0efb4946771acf49c9a1ff4e853e9ddebfdabcf962bf615f7b/68747470733a2f2f696d672e736869656c64732e696f2f636f6465636f762f632f6769746875622f6368696c6c65726c616e2f7068702d687474702d6d6573736167652d7574696c733f6c6f676f3d636f6465636f76)](https://codecov.io/github/chillerlan/php-http-message-utils)[![Codacy](https://camo.githubusercontent.com/66cd143b677191959b214bd09aeda908fffb420de240cb33e4bf87ce47506e2b/68747470733a2f2f696d672e736869656c64732e696f2f636f646163792f67726164652f37306531393531356332373334653061393033366438336462626431343639633f6c6f676f3d636f64616379)](https://app.codacy.com/gh/chillerlan/php-http-message-utils/dashboard)[![Packagist downloads](https://camo.githubusercontent.com/bf1df346b550eb500a88fc3fb70ee620a9d5d1de68bb875c92e4b2149acce921/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6368696c6c65726c616e2f7068702d687474702d6d6573736167652d7574696c733f6c6f676f3d7061636b6167697374)](https://packagist.org/packages/chillerlan/php-http-message-utils/stats)

Documentation
=============

[](#documentation)

Requirements
------------

[](#requirements)

- PHP 8.1+
    - `ext-fileinfo`, `ext-intl`, `ext-json`, `ext-mbstring`, `ext-simplexml`, `ext-zlib`
    - for `MessageUtil::decompress()`: `ext-br` [kjdev/php-ext-brotli](https://github.com/kjdev/php-ext-brotli) or `ext-zstd` [kjdev/php-ext-zstd](https://github.com/kjdev/php-ext-zstd)

Installation
------------

[](#installation)

**requires [composer](https://getcomposer.org)**

`composer.json` (note: replace `dev-main` with a [version boundary](https://getcomposer.org/doc/articles/versions.md), e.g. `^2.2`)

```
{
	"require": {
		"php": "^8.1",
		"chillerlan/php-http-message-utils": "dev-main#"
	}
}
```

Profit!

Usage
-----

[](#usage)

### `URLExtractor`

[](#urlextractor)

The `URLExtractor` wraps a PSR-18 `ClientInterface` to extract and follow shortened URLs to their original location.

```
// @see https://github.com/chillerlan/php-httpinterface
$options                 = new HTTPOptions;
$options->user_agent     = 'my cool user agent 1.0';
$options->ssl_verifypeer = false;
$options->curl_options   = [
	CURLOPT_FOLLOWLOCATION => false,
	CURLOPT_MAXREDIRS      => 25,
];

$httpClient   = new CurlClient($responseFactory, $options, $logger);
$urlExtractor = new URLExtractor($httpClient, $responseFactory);

$request = $factory->createRequest('GET', 'https://t.co/ZSS6nVOcVp');

$urlExtractor->sendRequest($request); // -> response from the final location

// you can retrieve an array with all followed locations afterwards
$responses = $urlExtractor->getResponses(); // -> ResponseInterface[]

// if you just want the URL of the final location, you can use the extract method:
$url = $urlExtractor->extract('https://t.co/ZSS6nVOcVp'); // -> https://api.guildwars2.com/v2/build
```

### `EchoClient`

[](#echoclient)

The `EchoClient` returns a JSON representation the original message:

```
$echoClient = new EchoClient($responseFactory);

$request  = $requestFactory->createRequest('GET', 'https://example.com?whatever=value');
$response = $echoClient->sendRequest($request);
$json     = json_decode($response->getBody()->getContents());
```

Which yields an object similar to the following

```
{
	"headers": {
		"Host": "example.com"
	},
	"request": {
		"url": "https://example.com?whatever=value",
		"params": {
			"whatever": "value"
		},
		"method": "GET",
		"target": "/",
		"http": "1.1"
	},
	"body": ""
}
```

### `LoggingClient`

[](#loggingclient)

The `LoggingClient` wraps a `ClientInterface` and outputs the HTTP messages in a readable way through a `LoggerInterface` (do NOT use in production!).

```
$loggingClient = new LoggingClient($httpClient, $logger);

$loggingClient->sendRequest($request); // -> log to output given via logger
```

The output looks similar to the following (using [monolog](https://github.com/Seldaek/monolog)):

```
[2024-03-15 22:10:41][debug] LoggingClientTest:
----HTTP-REQUEST----
GET /get HTTP/1.1
Host: httpbin.org

[2024-03-15 22:10:41][debug] LoggingClientTest:
----HTTP-RESPONSE---
HTTP/1.1 200 OK
Date: Fri, 15 Mar 2024 21:10:40 GMT
Content-Type: application/json
Content-Length: 294
Connection: keep-alive
Server: gunicorn/19.9.0
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true

{
  "args": {},
  "headers": {
    "Host": "httpbin.org",
    "User-Agent": "chillerlanPHPUnitHttp/1.0.0 +https://github.com/chillerlan/phpunit-http",
    "X-Amzn-Trace-Id": "Root=1-65f4b950-1f87b9e37182673438091aea"
  },
  "origin": "93.236.207.163",
  "url": "https://httpbin.org/get"
}

```

API
---

[](#api)

The following classes contain static methods for use with PSR-7 http message objects.

### `HeaderUtil`

[](#headerutil)

methodreturninfo`normalize(array $headers)``array`Normalizes an array of header lines to format `["Name" => "Value (, Value2, Value3, ...)", ...]` An exception is being made for `Set-Cookie`, which holds an array of values for each cookie. For multiple cookies with the same name, only the last value will be kept.`trimValues(array $values)``array`Trims whitespace from the header values`normalizeHeaderName(string $name)``string`Normalizes a header name, e.g. "conTENT- lenGTh" -&gt; "Content-Length"### `QueryUtil`

[](#queryutil)

methodreturninfo`cleanParams(iterable $params, int $bool_cast = null, bool $remove_empty = true)``array`Cleans/normalizes an array of query parameters, booleans will be converted according to the given `$bool_cast` constant. By default, booleans will be left as-is (`Query::BOOLEANS_AS_BOOL`) and may result in empty values. If `$remove_empty` is set to true, empty non-boolean and null values will be removed from the array. The `Query` class provides the following constants for `$bool_cast`:
`BOOLEANS_AS_BOOL`: unchanged boolean value (default)
`BOOLEANS_AS_INT`: integer values 0 or 1
`BOOLEANS_AS_STRING`: "true"/"false" strings
`BOOLEANS_AS_INT_STRING`: "0"/"1" strings`build(array $params, int $encoding = null, string $delimiter = null, string $enclosure = null)``string`Builds a query string from an array of key value pairs, similar to [`http_build_query`](https://www.php.net/manual/en/function.http-build-query). Valid values for `$encoding` are `PHP_QUERY_RFC3986` (default) and `PHP_QUERY_RFC1738`, any other integer value will be interpreted as "no encoding" (`Query::NO_ENCODING`).`merge(string $uri, array $query)``string`Merges additional query parameters into an existing query string.`parse(string $querystring, int $urlEncoding = null)``array`Parses a query string into an associative array, similar to [`parse_str`](https://www.php.net/manual/en/function.parse-str) (without the inconvenient usage of a by-reference result variable).`recursiveRawurlencode(mixed $data)``array|string`Recursive [`rawurlencode`](https://www.php.net/manual/en/function.rawurlencode)### `MessageUtil`

[](#messageutil)

methodreturninfo`getContents(MessageInterface $message)``string`Reads the body content of a `MessageInterface` and makes sure to rewind.`decodeJSON(MessageInterface $message, bool $assoc = false)`mixedfetches the body of a `MessageInterface` and converts it to a JSON object (`stdClass`) or an associative array if `$assoc` is set to `true` and returns the result.`decodeXML(MessageInterface $message, bool $assoc = false)`mixedfetches the body of a `MessageInterface` and converts it to a `SimpleXMLElement` or an associative array if `$assoc` is set to `true` and returns the result.`toString(MessageInterface $message, bool $appendBody = true)``string`Returns the string representation of an HTTP message.`toJSON(MessageInterface $message, bool $appendBody = true)``string`Returns the string representation of an HTTP message.`decompress(MessageInterface $message)``string`Decompresses the message content according to the `Content-Encoding` header (`compress`, `deflate`, `gzip`, `br`, `zstd`) and returns the decompressed data. `br` and `zstd` will throw a `RuntimeException` if the respecive extensions are missing.`setContentLengthHeader(MessageInterface $message)``MessageInterface`Sets a Content-Length header in the given message in case it does not exist and body size is not null`setContentTypeHeader(MessageInterface $message, string $filename = null, string $extension = null)``MessageInterface`Tries to determine the content type from the given values and sets the Content-Type header accordingly, throws if no mime type could be guessed.`setCookie(ResponseInterface $message, string $name, string $value = null, DateTimeInterface|DateInterval|int $expiry = null, string $domain = null, string $path = null, bool $secure = false, bool $httpOnly = false, string $sameSite = null)``ResponseInterface`Adds a Set-Cookie header to a ResponseInterface (convenience)`getCookiesFromHeader(MessageInterface $message)``array|null`Attempts to extract and parse a cookie from a "Cookie" (user-agent) header### `UriUtil`

[](#uriutil)

methodreturninfo`isDefaultPort(UriInterface $uri)``bool`Checks whether the `UriInterface` has a port set and if that port is one of the default ports for the given scheme.`isAbsolute(UriInterface $uri)``bool`Checks whether the URI is absolute, i.e. it has a scheme.`isNetworkPathReference(UriInterface $uri)``bool`Checks whether the URI is a network-path reference.`isAbsolutePathReference(UriInterface $uri)``bool`Checks whether the URI is a absolute-path reference.`isRelativePathReference(UriInterface $uri)``bool`Checks whether the URI is a relative-path reference.`withoutQueryValue(UriInterface $uri, string $key)``UriInterface`Removes a specific query string value. Any existing query string values that exactly match the provided `$key` are removed.`withQueryValue(UriInterface $uri, string $key, string $value = null)``UriInterface`Adds a specific query string value. Any existing query string values that exactly match the provided `$key` are removed and replaced with the given `$key`-`$value` pair. A value of null will set the query string key without a value, e.g. "key" instead of "key=value".`parseUrl(string $url)``?array`UTF-8 aware `\parse_url()` replacement.### `MimeTypeUtil`

[](#mimetypeutil)

methodreturninfo`getFromExtension(string $extension)``?string`Get the mime type for the given file extension (checks against the constant `chillerlan\HTTP\Utils\MIMETYPES`, a list of mime types from the [apache default config](http://svn.apache.org/repos/asf/httpd/httpd/branches/1.3.x/conf/mime.types))`getFromFilename(string $filename)``?string`Get the mime type from a file name`getFromContent(string $content)``?string`Get the mime type from the given content### `StreamUtil`

[](#streamutil)

methodreturninfo`getContents(string $extension)``string`Reads the content from a stream and make sure we rewind`copyToStream(StreamInterface $source, StreamInterface $destination, int $maxLength = null)``int`Copies a stream to another stream, starting from the current position of the source stream, reading to the end or until the given maxlength is hit.`tryFopen(string $filename, string $mode, $context = null)``resource`Safely open a PHP resource, throws instead of raising warnings and errors`tryGetContents($stream, int $length = null, int $offset = -1)``string`Safely get the contents of a stream resource, throws instead of raising warnings and errors`validateMode(string $mode)``string`Checks if the given mode is valid for `fopen()``modeAllowsReadWrite(string $mode)``bool`Checks whether the given mode allows reading and writing`modeAllowsReadOnly(string $mode)``bool`Checks whether the given mode allows only reading`modeAllowsWriteOnly(string $mode)``bool`Checks whether the given mode allows only writing`modeAllowsRead(string $mode)``bool`Checks whether the given mode allows reading`modeAllowsWrite(string $mode)``bool`Checks whether the given mode allows writing### `ServerUtil`

[](#serverutil)

The `ServerUtil` object requires a set of [PSR-17 factories](https://www.php-fig.org/psr/psr-17/) on invocation, namely `ServerRequestFactoryInterface`, `UriFactoryInterface`, `UploadedFileFactoryInterface` and `StreamFactoryInterface`. It provides convenience methods to create server requests, URIs and uploaded files from the [superglobals](https://www.php.net/manual/en/language.variables.superglobals.php).

methodreturninfo`createServerRequestFromGlobals()``ServerRequestInterface`Returns a ServerRequest object populated from the superglobals `$_GET`, `$_POST`, `$_COOKIE`, `$_FILES` and `$_SERVER`.`createUriFromGlobals()``UriInterface`Creates an Uri populated with values from [`$_SERVER`](https://www.php.net/manual/en/reserved.variables.server) (`HTTP_HOST`, `SERVER_NAME`, `SERVER_ADDR`, `SERVER_PORT`, `REQUEST_URI`, `QUERY_STRING`).`normalizeFiles(array $files)``UploadedFileInterface[]`Returns an `UploadedFile` instance array.`createUploadedFileFromSpec(array $value)``UploadedFileInterface` or `UploadedFileInterface[]`Creates an UploadedFile instance from a `$_FILES` specification. If the specification represents an array of values, this method will delegate to `normalizeNestedFileSpec()` and return that return value.`normalizeNestedFileSpec(array $files):array``array`Normalizes an array of file specifications. Loops through all nested files and returns a normalized array of `UploadedFileInterface` instances.### `Cookie`

[](#cookie)

Implements a [HTTP cookie](https://datatracker.ietf.org/doc/html/rfc6265#section-4.1)

methodreturninfo`__construct(string $name, string $value = null)`-`__toString()``string`returns the full cookie string to use in a `Set-Cookie` header`withNameAndValue(string $name, string $value)``Cookie``withExpiry(DateTimeInterface|DateInterval|int|null $expiry)``Cookie``withDomain(string|null $domain, bool $punycode = null)``Cookie``withPath(string|null $path)``Cookie``withSecure(bool $secure)``Cookie``withHttpOnly(bool $httpOnly)``Cookie``withSameSite(string|null $sameSite)``Cookie`

###  Health Score

38

—

LowBetter than 85% of packages

Maintenance33

Infrequent updates — may be unmaintained

Popularity26

Limited adoption so far

Community13

Small or concentrated contributor base

Maturity68

Established project with proven stability

 Bus Factor1

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

Recently: every ~36 days

Total

13

Last Release

661d ago

Major Versions

1.1.0 → 2.0.02023-08-02

PHP version history (2 changes)1.0.0PHP ^7.4 || ^8.0

2.0.0PHP ^8.1

### Community

Maintainers

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

---

Top Contributors

[![codemasher](https://avatars.githubusercontent.com/u/592497?v=4)](https://github.com/codemasher "codemasher (132 commits)")

---

Tags

http-messagephp7-is-deadphp8psr-17psr-7httppsr-7messagepsr-17psr-18

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP\_CodeSniffer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/chillerlan-php-http-message-utils/health.svg)

```
[![Health](https://phpackages.com/badges/chillerlan-php-http-message-utils/health.svg)](https://phpackages.com/packages/chillerlan-php-http-message-utils)
```

###  Alternatives

[guzzlehttp/psr7

PSR-7 message implementation that also provides common utility methods

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

HTTP tools for developing more consistent HTTP implementations.

28137.8k](/packages/phpro-http-tools)[elastic/transport

HTTP transport PHP library for Elastic products

2020.6M7](/packages/elastic-transport)[vultr/vultr-php

The Official Vultr API PHP Wrapper.

2243.9k1](/packages/vultr-vultr-php)[chillerlan/php-httpinterface

A PSR-7/17/18 http message/client implementation

1417.1k5](/packages/chillerlan-php-httpinterface)[amphp/http-client-psr7

PSR-7 adapter for Amp's HTTP client.

1454.7k4](/packages/amphp-http-client-psr7)

PHPackages © 2026

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