{"id":18321797,"url":"https://github.com/chillerlan/php-http-message-utils","last_synced_at":"2026-01-06T15:02:51.875Z","repository":{"id":62501782,"uuid":"352429896","full_name":"chillerlan/php-http-message-utils","owner":"chillerlan","description":"A collection of utilities for use with PSR-7 Message implementations.","archived":false,"fork":false,"pushed_at":"2024-07-26T16:12:18.000Z","size":804,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-03-06T18:03:03.387Z","etag":null,"topics":["http-message","php7-is-dead","php8","psr-17","psr-7"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chillerlan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null},"funding":{"ko_fi":"codemasher","custom":"https://www.paypal.com/donate?hosted_button_id=WLYUNAT9ZTJZ4"}},"created_at":"2021-03-28T20:20:09.000Z","updated_at":"2024-07-26T16:06:06.000Z","dependencies_parsed_at":"2024-03-15T22:25:04.337Z","dependency_job_id":"b05f51ca-6acd-4ea5-bece-f4ffc6d0af9c","html_url":"https://github.com/chillerlan/php-http-message-utils","commit_stats":{"total_commits":45,"total_committers":2,"mean_commits":22.5,"dds":0.4444444444444444,"last_synced_commit":"d365401b993c1d13c4fe0d6387aa08f1fc092e62"},"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chillerlan%2Fphp-http-message-utils","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chillerlan%2Fphp-http-message-utils/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chillerlan%2Fphp-http-message-utils/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chillerlan%2Fphp-http-message-utils/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chillerlan","download_url":"https://codeload.github.com/chillerlan/php-http-message-utils/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245591586,"owners_count":20640692,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["http-message","php7-is-dead","php8","psr-17","psr-7"],"created_at":"2024-11-05T18:21:38.156Z","updated_at":"2026-01-06T15:02:51.790Z","avatar_url":"https://github.com/chillerlan.png","language":"PHP","funding_links":["https://ko-fi.com/codemasher","https://www.paypal.com/donate?hosted_button_id=WLYUNAT9ZTJZ4"],"categories":[],"sub_categories":[],"readme":"# chillerlan/php-http-message-utils\n\nA collection of framework-agnostic utilities for use with [PSR-7 Message implementations](https://www.php-fig.org/psr/psr-7/).\n\n[![PHP Version Support][php-badge]][php]\n[![version][packagist-badge]][packagist]\n[![license][license-badge]][license]\n[![Continuous Integration][gh-action-badge]][gh-action]\n[![Coverage][coverage-badge]][coverage]\n[![Codacy][codacy-badge]][codacy]\n[![Packagist downloads][downloads-badge]][downloads]\n\n[php-badge]: https://img.shields.io/packagist/php-v/chillerlan/php-http-message-utils?logo=php\u0026color=8892BF\n[php]: https://www.php.net/supported-versions.php\n[packagist-badge]: https://img.shields.io/packagist/v/chillerlan/php-http-message-utils?logo=packagist\n[packagist]: https://packagist.org/packages/chillerlan/php-http-message-utils\n[license-badge]: https://img.shields.io/github/license/chillerlan/php-http-message-utils\n[license]: https://github.com/chillerlan/php-http-message-utils/blob/main/LICENSE\n[coverage-badge]: https://img.shields.io/codecov/c/github/chillerlan/php-http-message-utils?logo=codecov\n[coverage]: https://codecov.io/github/chillerlan/php-http-message-utils\n[codacy-badge]: https://img.shields.io/codacy/grade/70e19515c2734e0a9036d83dbbd1469c?logo=codacy\n[codacy]: https://app.codacy.com/gh/chillerlan/php-http-message-utils/dashboard\n[downloads-badge]: https://img.shields.io/packagist/dt/chillerlan/php-http-message-utils?logo=packagist\n[downloads]: https://packagist.org/packages/chillerlan/php-http-message-utils/stats\n[gh-action-badge]: https://img.shields.io/github/actions/workflow/status/chillerlan/php-http-message-utils/ci.yml?branch=main\u0026logo=github\n[gh-action]: https://github.com/chillerlan/php-http-message-utils/actions/workflows/ci.yml?query=branch%3Amain\n\n\n# Documentation\n\n## Requirements\n  - PHP 8.1+\n    - `ext-fileinfo`, `ext-intl`, `ext-json`, `ext-mbstring`, `ext-simplexml`, `ext-zlib`\n    - 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)\n\n## Installation\n\n**requires [composer](https://getcomposer.org)**\n\n`composer.json` (note: replace `dev-main` with a [version boundary](https://getcomposer.org/doc/articles/versions.md), e.g. `^2.2`)\n```json\n{\n\t\"require\": {\n\t\t\"php\": \"^8.1\",\n\t\t\"chillerlan/php-http-message-utils\": \"dev-main#\u003ccommit_hash\u003e\"\n\t}\n}\n```\nProfit!\n\n\n## Usage\n\n### `URLExtractor`\n\nThe `URLExtractor` wraps a PSR-18 `ClientInterface` to extract and follow shortened URLs to their original location.\n\n```php\n// @see https://github.com/chillerlan/php-httpinterface\n$options                 = new HTTPOptions;\n$options-\u003euser_agent     = 'my cool user agent 1.0';\n$options-\u003essl_verifypeer = false;\n$options-\u003ecurl_options   = [\n\tCURLOPT_FOLLOWLOCATION =\u003e false,\n\tCURLOPT_MAXREDIRS      =\u003e 25,\n];\n\n$httpClient   = new CurlClient($responseFactory, $options, $logger);\n$urlExtractor = new URLExtractor($httpClient, $responseFactory);\n\n$request = $factory-\u003ecreateRequest('GET', 'https://t.co/ZSS6nVOcVp');\n\n$urlExtractor-\u003esendRequest($request); // -\u003e response from the final location\n\n// you can retrieve an array with all followed locations afterwards\n$responses = $urlExtractor-\u003egetResponses(); // -\u003e ResponseInterface[]\n\n// if you just want the URL of the final location, you can use the extract method:\n$url = $urlExtractor-\u003eextract('https://t.co/ZSS6nVOcVp'); // -\u003e https://api.guildwars2.com/v2/build\n```\n\n### `EchoClient`\n\nThe `EchoClient` returns a JSON representation the original message:\n\n```php\n$echoClient = new EchoClient($responseFactory);\n\n$request  = $requestFactory-\u003ecreateRequest('GET', 'https://example.com?whatever=value');\n$response = $echoClient-\u003esendRequest($request);\n$json     = json_decode($response-\u003egetBody()-\u003egetContents());\n```\n\nWhich yields an object similar to the following\n\n```json\n{\n\t\"headers\": {\n\t\t\"Host\": \"example.com\"\n\t},\n\t\"request\": {\n\t\t\"url\": \"https://example.com?whatever=value\",\n\t\t\"params\": {\n\t\t\t\"whatever\": \"value\"\n\t\t},\n\t\t\"method\": \"GET\",\n\t\t\"target\": \"/\",\n\t\t\"http\": \"1.1\"\n\t},\n\t\"body\": \"\"\n}\n```\n\n\n### `LoggingClient`\n\nThe `LoggingClient` wraps a `ClientInterface` and outputs the HTTP messages in a readable way through a `LoggerInterface` (do NOT use in production!).\n\n```php\n$loggingClient = new LoggingClient($httpClient, $logger);\n\n$loggingClient-\u003esendRequest($request); // -\u003e log to output given via logger\n```\n\nThe output looks similar to the following (using [monolog](https://github.com/Seldaek/monolog)):\n\n```\n[2024-03-15 22:10:41][debug] LoggingClientTest:\n----HTTP-REQUEST----\nGET /get HTTP/1.1\nHost: httpbin.org\n\n\n[2024-03-15 22:10:41][debug] LoggingClientTest:\n----HTTP-RESPONSE---\nHTTP/1.1 200 OK\nDate: Fri, 15 Mar 2024 21:10:40 GMT\nContent-Type: application/json\nContent-Length: 294\nConnection: keep-alive\nServer: gunicorn/19.9.0\nAccess-Control-Allow-Origin: *\nAccess-Control-Allow-Credentials: true\n\n{\n  \"args\": {},\n  \"headers\": {\n    \"Host\": \"httpbin.org\",\n    \"User-Agent\": \"chillerlanPHPUnitHttp/1.0.0 +https://github.com/chillerlan/phpunit-http\",\n    \"X-Amzn-Trace-Id\": \"Root=1-65f4b950-1f87b9e37182673438091aea\"\n  },\n  \"origin\": \"93.236.207.163\",\n  \"url\": \"https://httpbin.org/get\"\n}\n```\n\n\n## API\nThe following classes contain static methods for use with PSR-7 http message objects.\n\n### `HeaderUtil`\n| method                              | return   | info                                                                                                                                                                                                                                                                     |\n|-------------------------------------|----------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `normalize(array $headers)`         | `array`  | Normalizes an array of header lines to format `[\"Name\" =\u003e \"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. |\n| `trimValues(array $values)`         | `array`  | Trims whitespace from the header values                                                                                                                                                                                                                                  |\n| `normalizeHeaderName(string $name)` | `string` | Normalizes a header name, e.g. \"conTENT- lenGTh\" -\u003e \"Content-Length\"                                                                                                                                                                                                     |\n\n### `QueryUtil`\n| method                                                                                           | return          | info                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |\n|--------------------------------------------------------------------------------------------------|-----------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `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`:\u003cbr\u003e`BOOLEANS_AS_BOOL`: unchanged boolean value (default)\u003cbr\u003e`BOOLEANS_AS_INT`: integer values 0 or 1\u003cbr\u003e`BOOLEANS_AS_STRING`: \"true\"/\"false\" strings\u003cbr\u003e`BOOLEANS_AS_INT_STRING`: \"0\"/\"1\" strings |\n| `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`).                                                                                                                                                                                                                                                                           |\n| `merge(string $uri, array $query)`                                                               | `string`        | Merges additional query parameters into an existing query string.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |\n| `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).                                                                                                                                                                                                                                                                                                                                                                                                          |\n| `recursiveRawurlencode(mixed $data)`                                                             | `array\\|string` | Recursive [`rawurlencode`](https://www.php.net/manual/en/function.rawurlencode)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |\n\n### `MessageUtil`\n| method                                                                                                                                                                                                                                              | return              | info                                                                                                                                                                                                                                                  |\n|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `getContents(MessageInterface $message)`                                                                                                                                                                                                            | `string`            | Reads the body content of a `MessageInterface` and makes sure to rewind.                                                                                                                                                                              |\n| `decodeJSON(MessageInterface $message, bool $assoc = false)`                                                                                                                                                                                        | mixed               | fetches 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.                                                                                   |\n| `decodeXML(MessageInterface $message, bool $assoc = false)`                                                                                                                                                                                         | mixed               | fetches 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.                                                                                         |\n| `toString(MessageInterface $message, bool $appendBody = true)`                                                                                                                                                                                      | `string`            | Returns the string representation of an HTTP message.                                                                                                                                                                                                 |\n| `toJSON(MessageInterface $message, bool $appendBody = true)`                                                                                                                                                                                        | `string`            | Returns the string representation of an HTTP message.                                                                                                                                                                                                 |\n| `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. |\n| `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                                                                                                                                                 |\n| `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.                                                                                                      |\n| `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)                                                                                                                                                                                         |\n| `getCookiesFromHeader(MessageInterface $message)`                                                                                                                                                                                                   | `array\\|null`       | Attempts to extract and parse a cookie from a \"Cookie\" (user-agent) header                                                                                                                                                                            |\n\n### `UriUtil`\n| method                                                                 | return         | info                                                                                                                                                                                                                                                                        |\n|------------------------------------------------------------------------|----------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `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.                                                                                                                                                         |\n| `isAbsolute(UriInterface $uri)`                                        | `bool`         | Checks whether the URI is absolute, i.e. it has a scheme.                                                                                                                                                                                                                   |\n| `isNetworkPathReference(UriInterface $uri)`                            | `bool`         | Checks whether the URI is a network-path reference.                                                                                                                                                                                                                         |\n| `isAbsolutePathReference(UriInterface $uri)`                           | `bool`         | Checks whether the URI is a absolute-path reference.                                                                                                                                                                                                                        |\n| `isRelativePathReference(UriInterface $uri)`                           | `bool`         | Checks whether the URI is a relative-path reference.                                                                                                                                                                                                                        |\n| `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.                                                                                                                                                 |\n| `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\". |\n| `parseUrl(string $url)`                                                | `?array`       | UTF-8 aware `\\parse_url()` replacement.                                                                                                                                                                                                                                     |\n\n### `MimeTypeUtil`\n| method                                | return    | info                                                                                                                                                                                                                                              |\n|---------------------------------------|-----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `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)) |\n| `getFromFilename(string $filename)`   | `?string` | Get the mime type from a file name                                                                                                                                                                                                                |\n| `getFromContent(string $content)`     | `?string` | Get the mime type from the given content                                                                                                                                                                                                          |\n\n### `StreamUtil`\n| method                                                                                       | return     | info                                                                                                                                                |\n|----------------------------------------------------------------------------------------------|------------|-----------------------------------------------------------------------------------------------------------------------------------------------------|\n| `getContents(string $extension)`                                                             | `string`   | Reads the content from a stream and make sure we rewind                                                                                             |\n| `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. |\n| `tryFopen(string $filename, string $mode, $context = null)`                                  | `resource` | Safely open a PHP resource, throws instead of raising warnings and errors                                                                           |\n| `tryGetContents($stream, int $length = null, int $offset = -1)`                              | `string`   | Safely get the contents of a stream resource, throws instead of raising warnings and errors                                                         |\n| `validateMode(string $mode)`                                                                 | `string`   | Checks if the given mode is valid for `fopen()`                                                                                                     |\n| `modeAllowsReadWrite(string $mode)`                                                          | `bool`     | Checks whether the given mode allows reading and writing                                                                                            |\n| `modeAllowsReadOnly(string $mode)`                                                           | `bool`     | Checks whether the given mode allows only reading                                                                                                   |\n| `modeAllowsWriteOnly(string $mode)`                                                          | `bool`     | Checks whether the given mode allows only writing                                                                                                   |\n| `modeAllowsRead(string $mode)`                                                               | `bool`     | Checks whether the given mode allows reading                                                                                                        |\n| `modeAllowsWrite(string $mode)`                                                              | `bool`     | Checks whether the given mode allows writing                                                                                                        |\n\n### `ServerUtil`\nThe `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`.\nIt provides convenience methods to create server requests, URIs and uploaded files from the [superglobals](https://www.php.net/manual/en/language.variables.superglobals.php).\n\n| method                                        | return                                               | info                                                                                                                                                                                                        |\n|-----------------------------------------------|------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `createServerRequestFromGlobals()`            | `ServerRequestInterface`                             | Returns a ServerRequest object populated from the superglobals `$_GET`, `$_POST`, `$_COOKIE`, `$_FILES` and `$_SERVER`.                                                                                     |\n| `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`).  |\n| `normalizeFiles(array $files)`                | `UploadedFileInterface[]`                            | Returns an `UploadedFile` instance array.                                                                                                                                                                   |\n| `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. |\n| `normalizeNestedFileSpec(array $files):array` | `array`                                              | Normalizes an array of file specifications. Loops through all nested files and returns a normalized array of `UploadedFileInterface` instances.                                                             |\n\n### `Cookie`\nImplements a [HTTP cookie](https://datatracker.ietf.org/doc/html/rfc6265#section-4.1)\n\n| method                                                           | return   | info                                                           |\n|------------------------------------------------------------------|----------|----------------------------------------------------------------|\n| `__construct(string $name, string $value = null)`                | -        |                                                                |\n| `__toString()`                                                   | `string` | returns the full cookie string to use in a `Set-Cookie` header |\n| `withNameAndValue(string $name, string $value)`                  | `Cookie` |                                                                |\n| `withExpiry(DateTimeInterface\\|DateInterval\\|int\\|null $expiry)` | `Cookie` |                                                                |\n| `withDomain(string\\|null $domain, bool $punycode = null)`        | `Cookie` |                                                                |\n| `withPath(string\\|null $path)`                                   | `Cookie` |                                                                |\n| `withSecure(bool $secure)`                                       | `Cookie` |                                                                |\n| `withHttpOnly(bool $httpOnly)`                                   | `Cookie` |                                                                |\n| `withSameSite(string\\|null $sameSite)`                           | `Cookie` |                                                                |\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchillerlan%2Fphp-http-message-utils","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchillerlan%2Fphp-http-message-utils","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchillerlan%2Fphp-http-message-utils/lists"}