├── .github └── workflows │ └── main.yaml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── composer.json ├── phpcs.xml ├── phpunit.xml └── src ├── JsonPayload.php ├── Payload.php ├── UrlEncodePayload.php └── XmlPayload.php /.github/workflows/main.yaml: -------------------------------------------------------------------------------- 1 | name: "testing" 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | qa: 11 | name: Quality assurance 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v4 17 | 18 | - name: Validate composer.json and composer.lock 19 | run: composer validate 20 | 21 | - name: Cache Composer packages 22 | id: composer-cache 23 | uses: actions/cache@v4 24 | with: 25 | path: vendor 26 | key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} 27 | restore-keys: | 28 | ${{ runner.os }}-php- 29 | 30 | - name: Install dependencies 31 | if: steps.composer-cache.outputs.cache-hit != 'true' 32 | run: composer install --prefer-dist --no-progress 33 | 34 | - name: Coding Standard 35 | run: composer run-script cs 36 | 37 | tests: 38 | name: Tests 39 | runs-on: ubuntu-latest 40 | 41 | strategy: 42 | matrix: 43 | php: 44 | - 7.2 45 | - 7.3 46 | - 7.4 47 | - 8.0 48 | - 8.1 49 | - 8.2 50 | - 8.3 51 | - 8.4 52 | 53 | steps: 54 | - name: Checkout 55 | uses: actions/checkout@v4 56 | 57 | - name: Install PHP 58 | uses: shivammathur/setup-php@v2 59 | with: 60 | php-version: ${{ matrix.php }} 61 | 62 | - name: Cache PHP dependencies 63 | uses: actions/cache@v4 64 | with: 65 | path: vendor 66 | key: ${{ runner.os }}-php-${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }} 67 | restore-keys: ${{ runner.os }}-php-${{ matrix.php }}-composer- 68 | 69 | - name: Install dependencies 70 | run: composer install --prefer-dist --no-progress 71 | 72 | - name: Tests 73 | run: composer test 74 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](http://keepachangelog.com/) 5 | and this project adheres to [Semantic Versioning](http://semver.org/). 6 | 7 | ## [3.1.0] - 2025-03-21 8 | ### Added 9 | - Support for PHP 8.4 10 | 11 | ## [3.0.2] - 2024-01-12 12 | ### Fixed 13 | - Updated dependencies. 14 | 15 | ## [3.0.1] - 2020-12-02 16 | ### Added 17 | - Support for PHP 8 18 | 19 | ## [3.0.0] - 2019-11-29 20 | ### Added 21 | - New `XmlPayload` middleware [#9] 22 | - Throw `JsonException` on error (Php ^7.3) 23 | 24 | ### Removed 25 | - Support for PHP 7.0 and 7.1 26 | 27 | ## [2.1.1] - 2018-11-08 28 | ### Fixed 29 | - Use `phpstan` as a dev dependency to detect bugs 30 | - Fixed disabled associative config, that could return `null|array|object` instead only array [#8] 31 | 32 | ## [2.1.0] - 2018-08-04 33 | ### Added 34 | - PSR-17 support 35 | 36 | ## [2.0.0] - 2018-06-25 37 | ### Changed 38 | - Moved CSV parsing to `middlewares/csv-payload` 39 | - Parsing errors will result in an exception being thrown 40 | - Strict types added 41 | 42 | ## [1.0.0] - 2018-01-25 43 | ### Added 44 | - Improved testing and added code coverage reporting 45 | - Added tests for PHP 7.2 46 | 47 | ### Changed 48 | - Upgraded to the final version of PSR-15 `psr/http-server-middleware` 49 | 50 | ### Fixed 51 | - Updated license year 52 | 53 | ## [0.6.0] - 2017-11-13 54 | ### Changed 55 | - Replaced `http-interop/http-middleware` with `http-interop/http-server-middleware`. 56 | 57 | ### Removed 58 | - Removed support for PHP 5.x. 59 | 60 | ## [0.5.0] - 2017-09-21 61 | ### Changed 62 | - The `contentType()` argument is an array instead a string, allowing to assign multiple values 63 | - Append `.dist` suffix to phpcs.xml and phpunit.xml files 64 | - Changed the configuration of phpcs and php_cs 65 | - Upgraded phpunit to the latest version and improved its config file 66 | - Updated to `http-interop/http-middleware#0.5` 67 | 68 | ## [0.4.0] - 2017-02-05 69 | ### Added 70 | - New option `contentType()` to configure the `Content-Type` request header 71 | - Improve CsvPayload 72 | - New option `delimiter()` to configure the CSV delimiter character 73 | - New option `enclosure()` to configure the CSV enclosure character 74 | - New option `escape()` to configure the CSV escape character 75 | - Fixed 76 | - CsvPayload: `StreamInterface` fixed left undetached 77 | 78 | ## [0.3.0] - 2016-12-26 79 | ### Changed 80 | - Updated tests 81 | - Updated to `http-interop/http-middleware#0.4` 82 | - Updated `friendsofphp/php-cs-fixer#2.0` 83 | 84 | ## [0.2.0] - 2016-11-27 85 | ### Added 86 | - New option `methods()` to configure the allowed methods 87 | - New option `override()` to configure if the previous parsed body must be overrided 88 | 89 | ### Changed 90 | - Updated to `http-interop/http-middleware#0.3` 91 | 92 | ## [0.1.0] - 2016-10-04 93 | First version 94 | 95 | [#8]: https://github.com/middlewares/payload/issues/8 96 | [#9]: https://github.com/middlewares/payload/issues/9 97 | 98 | [3.1.0]: https://github.com/middlewares/payload/compare/v3.0.2...v3.1.0 99 | [3.0.2]: https://github.com/middlewares/payload/compare/v3.0.1...v3.0.2 100 | [3.0.1]: https://github.com/middlewares/payload/compare/v3.0.0...v3.0.1 101 | [3.0.0]: https://github.com/middlewares/payload/compare/v2.1.1...v3.0.0 102 | [2.1.1]: https://github.com/middlewares/payload/compare/v2.1.0...v2.1.1 103 | [2.1.0]: https://github.com/middlewares/payload/compare/v2.0.0...v2.1.0 104 | [2.0.0]: https://github.com/middlewares/payload/compare/v1.0.0...v2.0.0 105 | [1.0.0]: https://github.com/middlewares/payload/compare/v0.6.0...v1.0.0 106 | [0.6.0]: https://github.com/middlewares/payload/compare/v0.5.0...v0.6.0 107 | [0.5.0]: https://github.com/middlewares/payload/compare/v0.4.0...v0.5.0 108 | [0.4.0]: https://github.com/middlewares/payload/compare/v0.3.0...v0.4.0 109 | [0.3.0]: https://github.com/middlewares/payload/compare/v0.2.0...v0.3.0 110 | [0.2.0]: https://github.com/middlewares/payload/compare/v0.1.0...v0.2.0 111 | [0.1.0]: https://github.com/middlewares/payload/releases/tag/v0.1.0 112 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guide 2 | 3 | This project adheres to [The Code Manifesto](http://codemanifesto.com) as its guidelines for contributor interactions. 4 | 5 | ## The Code Manifesto 6 | 7 | We want to work in an ecosystem that empowers developers to reach their potential--one that encourages growth and effective collaboration. A space that is safe for all. 8 | 9 | A space such as this benefits everyone that participates in it. It encourages new developers to enter our field. It is through discussion and collaboration that we grow, and through growth that we improve. 10 | 11 | In the effort to create such a place, we hold to these values: 12 | 13 | 1. **Discrimination limits us.** This includes discrimination on the basis of race, gender, sexual orientation, gender identity, age, nationality, technology and any other arbitrary exclusion of a group of people. 14 | 2. **Boundaries honor us.** Your comfort levels are not everyone’s comfort levels. Remember that, and if brought to your attention, heed it. 15 | 3. **We are our biggest assets.** None of us were born masters of our trade. Each of us has been helped along the way. Return that favor, when and where you can. 16 | 4. **We are resources for the future.** As an extension of #3, share what you know. Make yourself a resource to help those that come after you. 17 | 5. **Respect defines us.** Treat others as you wish to be treated. Make your discussions, criticisms and debates from a position of respectfulness. Ask yourself, is it true? Is it necessary? Is it constructive? Anything less is unacceptable. 18 | 6. **Reactions require grace.** Angry responses are valid, but abusive language and vindictive actions are toxic. When something happens that offends you, handle it assertively, but be respectful. Escalate reasonably, and try to allow the offender an opportunity to explain themselves, and possibly correct the issue. 19 | 7. **Opinions are just that: opinions.** Each and every one of us, due to our background and upbringing, have varying opinions. That is perfectly acceptable. Remember this: if you respect your own opinions, you should respect the opinions of others. 20 | 8. **To err is human.** You might not intend it, but mistakes do happen and contribute to build experience. Tolerate honest mistakes, and don't hesitate to apologize if you make one yourself. 21 | 22 | ## How to contribute 23 | 24 | This is a collaborative effort. We welcome all contributions submitted as pull requests. 25 | 26 | (Contributions on wording & style are also welcome.) 27 | 28 | ### Bugs 29 | 30 | A bug is a demonstrable problem that is caused by the code in the repository. Good bug reports are extremely helpful – thank you! 31 | 32 | Please try to be as detailed as possible in your report. Include specific information about the environment – version of PHP, etc, and steps required to reproduce the issue. 33 | 34 | ### Pull Requests 35 | 36 | Good pull requests – patches, improvements, new features – are a fantastic help. Before create a pull request, please follow these instructions: 37 | 38 | * The code must follow the [PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md). Run `composer cs-fix` to fix your code before commit. 39 | * Write tests 40 | * Document any change in `README.md` and `CHANGELOG.md` 41 | * One pull request per feature. If you want to do more than one thing, send multiple pull request 42 | 43 | ### Runing tests 44 | 45 | ```sh 46 | composer test 47 | ``` 48 | 49 | To get code coverage information execute the following comand: 50 | 51 | ```sh 52 | composer coverage 53 | ``` 54 | 55 | Then, open the `./coverage/index.html` file in your browser. 56 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019-2025 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # middlewares/payload 2 | 3 | [![Latest Version on Packagist][ico-version]][link-packagist] 4 | [![Software License][ico-license]](LICENSE) 5 | ![Testing][ico-ga] 6 | [![Total Downloads][ico-downloads]][link-downloads] 7 | 8 | Parses the body of the request if it's not parsed and the method is POST, PUT or DELETE. It contains the following components to support different formats: 9 | 10 | * [JsonPayload](#jsonpayload) 11 | * [UrlEncodePayload](#urlencodepayload) 12 | * [CsvPayload](#csvpayload) 13 | * [XmlPayload](#xmlpayload) 14 | 15 | Failure to parse the body will result in a `Middlewares\Utils\HttpErrorException` being thrown. See [middlewares/utils](https://github.com/middlewares/utils#httperrorexception) for additional details. 16 | 17 | ## Requirements 18 | 19 | * PHP >= 7.2 20 | * A [PSR-7 http library](https://github.com/middlewares/awesome-psr15-middlewares#psr-7-implementations) 21 | * A [PSR-15 middleware dispatcher](https://github.com/middlewares/awesome-psr15-middlewares#dispatcher) 22 | 23 | ## Installation 24 | 25 | This package is installable and autoloadable via Composer as [middlewares/payload](https://packagist.org/packages/middlewares/payload). 26 | 27 | ```sh 28 | composer require middlewares/payload 29 | ``` 30 | 31 | ## JsonPayload 32 | 33 | Parses the JSON payload of the request. 34 | 35 | ```php 36 | Dispatcher::run([ 37 | (new Middlewares\JsonPayload()) 38 | ->associative(false) 39 | ->depth(64) 40 | ]); 41 | 42 | $response = $dispatcher->dispatch(new ServerRequest()); 43 | ``` 44 | 45 | Contains the following options to configure the [json_decode](http://php.net/manual/en/function.json-decode.php) function: 46 | 47 | ### associative 48 | 49 | Enabled by default, convert the objects into associative arrays. 50 | 51 | ```php 52 | //Disable associative arrays 53 | $payload = (new Middlewares\JsonPayload())->associative(false); 54 | ``` 55 | 56 | ### depth 57 | 58 | To configure the recursion depth option of json_decode. By default is `512`. 59 | 60 | ### options 61 | 62 | To pass the bitmask of json_decode options: `JSON_BIGINT_AS_STRING` (enabled by default), `JSON_OBJECT_AS_ARRAY`, `JSON_THROW_ON_ERROR`. 63 | 64 | ### methods 65 | 66 | To configure the allowed methods. By default only the requests with the method `POST, PUT, PATCH, DELETE, COPY, LOCK, UNLOCK` are handled. 67 | 68 | ```php 69 | //Parse json only with POST and PUT requests 70 | $payload = (new Middlewares\JsonPayload())->methods(['POST', 'PUT']); 71 | ``` 72 | 73 | ### contentType 74 | 75 | To configure all `Content-Type` headers allowed in the request. By default is `application/json` 76 | 77 | ```php 78 | //Parse json only in request with these two Content-Type values 79 | $payload = (new Middlewares\JsonPayload())->contentType(['application/json', 'text/json']); 80 | ``` 81 | 82 | ### override 83 | 84 | To override the previous parsed body if exists (`false` by default) 85 | 86 | 87 | ## UrlEncodePayload 88 | 89 | Parses the url-encoded payload of the request. 90 | 91 | ```php 92 | Dispatcher::run([ 93 | new Middlewares\UrlEncodePayload() 94 | ]); 95 | ``` 96 | 97 | ### methods 98 | 99 | To configure the allowed methods. By default only the requests with the method `POST, PUT, PATCH, DELETE, COPY, LOCK, UNLOCK` are handled. 100 | 101 | ### contentType 102 | 103 | To configure all Content-Type headers allowed in the request. By default is `application/x-www-form-urlencoded` 104 | 105 | ### override 106 | 107 | To override the previous parsed body if exists (`false` by default) 108 | 109 | 110 | ## CsvPayload 111 | 112 | CSV payloads are supported by the [middlewares/csv-payload](https://packagist.org/packages/middlewares/csv-payload) package. 113 | 114 | 115 | ## XmlPayload 116 | 117 | Parses the XML payload of the request. Parsed body will return an instance of [SimpleXMLElement](https://www.php.net/manual/en/class.simplexmlelement.php). 118 | 119 | ### methods 120 | 121 | To configure the allowed methods. By default only the requests with the method `POST, PUT, PATCH, DELETE, COPY, LOCK, UNLOCK` are handled. 122 | 123 | ### contentType 124 | 125 | To configure all Content-Type headers allowed in the request. By default is `text/xml`, `application/xml` and `application/x-xml`. 126 | 127 | ### override 128 | 129 | To override the previous parsed body if exists (`false` by default) 130 | 131 | --- 132 | 133 | Please see [CHANGELOG](CHANGELOG.md) for more information about recent changes and [CONTRIBUTING](CONTRIBUTING.md) for contributing details. 134 | 135 | The MIT License (MIT). Please see [LICENSE](LICENSE) for more information. 136 | 137 | [ico-version]: https://img.shields.io/packagist/v/middlewares/payload.svg?style=flat-square 138 | [ico-license]: https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square 139 | [ico-ga]: https://github.com/middlewares/payload/workflows/testing/badge.svg 140 | [ico-downloads]: https://img.shields.io/packagist/dt/middlewares/payload.svg?style=flat-square 141 | 142 | [link-packagist]: https://packagist.org/packages/middlewares/payload 143 | [link-downloads]: https://packagist.org/packages/middlewares/payload 144 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "middlewares/payload", 3 | "type": "library", 4 | "description": "Middleware to parse the body of the request with support for json, csv and url-encode", 5 | "license": "MIT", 6 | "keywords": [ 7 | "psr-7", 8 | "psr-15", 9 | "middleware", 10 | "server", 11 | "http", 12 | "json", 13 | "url-encode", 14 | "payload" 15 | ], 16 | "homepage": "https://github.com/middlewares/payload", 17 | "support": { 18 | "issues": "https://github.com/middlewares/payload/issues" 19 | }, 20 | "require": { 21 | "php": "^7.2 || ^8.0", 22 | "middlewares/utils": "^2 || ^3 || ^4", 23 | "psr/http-server-middleware": "^1" 24 | }, 25 | "require-dev": { 26 | "phpunit/phpunit": "^8 || ^9", 27 | "friendsofphp/php-cs-fixer": "^3", 28 | "squizlabs/php_codesniffer": "^3", 29 | "oscarotero/php-cs-fixer-config": "^2", 30 | "phpstan/phpstan": "^1 || ^2", 31 | "laminas/laminas-diactoros": "^2 || ^3", 32 | "ext-simplexml": "*" 33 | }, 34 | "suggest": { 35 | "middlewares/csv-payload": "Adds support for parsing CSV body of request", 36 | "ext-simplexml": "Enable to use the XML payload parser." 37 | }, 38 | "autoload": { 39 | "psr-4": { 40 | "Middlewares\\": "src/" 41 | } 42 | }, 43 | "autoload-dev": { 44 | "psr-4": { 45 | "Middlewares\\Tests\\": "tests/" 46 | } 47 | }, 48 | "scripts": { 49 | "cs": "phpcs", 50 | "cs-fix": "php-cs-fixer fix", 51 | "phpstan": "phpstan analyse", 52 | "test": "phpunit", 53 | "coverage": "phpunit --coverage-text", 54 | "coverage-html": "phpunit --coverage-html=coverage" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /phpcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Middlewares coding standard 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | src 15 | tests 16 | 17 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | tests 21 | 22 | 23 | 24 | 25 | 26 | ./src 27 | 28 | ./tests 29 | ./vendor 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/JsonPayload.php: -------------------------------------------------------------------------------- 1 | associative = $associative; 40 | 41 | return $this; 42 | } 43 | 44 | /** 45 | * Configure the recursion depth. 46 | * 47 | * @see http://php.net/manual/en/function.json-decode.php 48 | */ 49 | public function depth(int $depth): self 50 | { 51 | $this->depth = $depth; 52 | 53 | return $this; 54 | } 55 | 56 | /** 57 | * Configure the decode options. 58 | * 59 | * @see http://php.net/manual/en/function.json-decode.php 60 | */ 61 | public function options(int $options): self 62 | { 63 | $this->options = $options; 64 | 65 | return $this; 66 | } 67 | 68 | /** 69 | * {@inheritdoc} 70 | * 71 | * @return array|object|null 72 | */ 73 | protected function parse(StreamInterface $stream) 74 | { 75 | $json = trim((string) $stream); 76 | 77 | if ($json === '') { 78 | return $this->associative ? [] : null; 79 | } 80 | 81 | $data = defined('JSON_THROW_ON_ERROR') ? $this->parseWithException($json) : $this->parseWithoutException($json); 82 | 83 | if ($this->associative) { 84 | return $data ?? []; 85 | } 86 | 87 | return $data; 88 | } 89 | 90 | /** 91 | 92 | * @return mixed 93 | */ 94 | protected function parseWithException(string $json) 95 | { 96 | /* @phpstan-ignore-next-line */ 97 | return json_decode($json, $this->associative, $this->depth, $this->options | JSON_THROW_ON_ERROR); 98 | } 99 | 100 | /** 101 | * @return mixed 102 | */ 103 | protected function parseWithoutException(string $json) 104 | { 105 | /** @phpstan-ignore-next-line */ 106 | $data = json_decode($json, $this->associative, $this->depth, $this->options); 107 | $code = json_last_error(); 108 | 109 | if ($code !== JSON_ERROR_NONE) { 110 | throw new Exception(sprintf('JSON: %s', json_last_error_msg()), $code); 111 | } 112 | 113 | return $data; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/Payload.php: -------------------------------------------------------------------------------- 1 | contentType = $contentType; 38 | 39 | return $this; 40 | } 41 | 42 | /** 43 | * Configure the methods allowed. 44 | * 45 | * @param string[] $methods 46 | */ 47 | public function methods(array $methods): self 48 | { 49 | $this->methods = $methods; 50 | 51 | return $this; 52 | } 53 | 54 | /** 55 | * Configure if the parsed body overrides the previous value. 56 | */ 57 | public function override(bool $override = true): self 58 | { 59 | $this->override = $override; 60 | 61 | return $this; 62 | } 63 | 64 | /** 65 | * Process a server request and return a response. 66 | */ 67 | public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface 68 | { 69 | if ($this->checkRequest($request)) { 70 | try { 71 | $request = $request->withParsedBody($this->parse($request->getBody())); 72 | } catch (Exception $exception) { 73 | throw HttpErrorException::create(400, [], $exception); 74 | } 75 | } 76 | 77 | return $handler->handle($request); 78 | } 79 | 80 | /** 81 | * Parse the body. 82 | * 83 | * @return mixed 84 | */ 85 | abstract protected function parse(StreamInterface $stream); 86 | 87 | /** 88 | * Check whether the request payload need to be processed 89 | */ 90 | private function checkRequest(ServerRequestInterface $request): bool 91 | { 92 | if ($request->getParsedBody() && !$this->override) { 93 | return false; 94 | } 95 | 96 | if (!in_array($request->getMethod(), $this->methods, true)) { 97 | return false; 98 | } 99 | 100 | $contentType = $request->getHeaderLine('Content-Type'); 101 | 102 | foreach ($this->contentType as $allowedType) { 103 | if (stripos($contentType, $allowedType) === 0) { 104 | return true; 105 | } 106 | } 107 | 108 | return false; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/UrlEncodePayload.php: -------------------------------------------------------------------------------- 1 | 21 | */ 22 | protected function parse(StreamInterface $stream): array 23 | { 24 | $string = trim((string) $stream); 25 | parse_str($string, $data); 26 | 27 | if (strlen($string) && empty($data)) { 28 | throw new DomainException('Invalid url encoded string'); 29 | } 30 | 31 | return $data ?: []; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/XmlPayload.php: -------------------------------------------------------------------------------- 1 |