Skip to content

Commit 21fd349

Browse files
committed
Respect max_input_vars and max_input_nesting_level ini settings
1 parent 2db0c91 commit 21fd349

3 files changed

Lines changed: 79 additions & 1 deletion

File tree

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,12 @@ See also [example #12](examples) for more details.
789789

790790
> PHP's `MAX_FILE_SIZE` hidden field is respected by this middleware.
791791
792+
> This middleware respects the
793+
[`max_input_vars`](http://php.net/manual/en/info.configuration.php#ini.max-input-vars)
794+
(default `1000`) and
795+
[`max_input_nesting_level`](http://php.net/manual/en/info.configuration.php#ini.max-input-nesting-level)
796+
(default `64`) ini settings.
797+
792798
#### Third-Party Middleware
793799

794800
A non-exhaustive list of third-party middleware can be found at the [`Middleware`](https://github.com/reactphp/http/wiki/Middleware) wiki page.

src/Middleware/RequestBodyParserMiddleware.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@ public function __invoke(ServerRequestInterface $request, $next)
2525

2626
private function parseFormUrlencoded(ServerRequestInterface $request)
2727
{
28+
// parse string into array structure
29+
// ignore warnings due to excessive data structures (max_input_vars and max_input_nesting_level)
2830
$ret = array();
29-
parse_str((string)$request->getBody(), $ret);
31+
@parse_str((string)$request->getBody(), $ret);
3032

3133
return $request->withParsedBody($ret);
3234
}

tests/Middleware/RequestBodyParserMiddlewareTest.php

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,76 @@ function (ServerRequestInterface $request) {
107107
$this->assertSame('foo=bar&baz[]=cheese&bar[]=beer&bar[]=wine&market[fish]=salmon&market[meat][]=beef&market[meat][]=chicken&market[]=bazaar', (string)$parsedRequest->getBody());
108108
}
109109

110+
public function testFormUrlencodedIgnoresBodyWithExcessiveNesting()
111+
{
112+
// supported in all Zend PHP versions and HHVM
113+
// ini setting does exist everywhere but HHVM: https://3v4l.org/hXLiK
114+
// HHVM limits to 64 and returns an empty array structure: https://3v4l.org/j3DK2
115+
if (defined('HHVM_VERSION')) {
116+
$this->markTestSkipped('Not supported on HHVM (limited to depth 64, but keeps empty array structure)');
117+
}
118+
119+
$allowed = (int)ini_get('max_input_nesting_level');
120+
121+
$middleware = new RequestBodyParserMiddleware();
122+
$request = new ServerRequest(
123+
'POST',
124+
'https://example.com/',
125+
array(
126+
'Content-Type' => 'application/x-www-form-urlencoded',
127+
),
128+
'hello' . str_repeat('[]', $allowed + 1) . '=world'
129+
);
130+
131+
/** @var ServerRequestInterface $parsedRequest */
132+
$parsedRequest = $middleware(
133+
$request,
134+
function (ServerRequestInterface $request) {
135+
return $request;
136+
}
137+
);
138+
139+
$this->assertSame(
140+
array(),
141+
$parsedRequest->getParsedBody()
142+
);
143+
}
144+
145+
public function testFormUrlencodedTruncatesBodyWithExcessiveLength()
146+
{
147+
// supported as of PHP 5.3.11, no HHVM support: https://3v4l.org/PiqnQ
148+
// ini setting already exists in PHP 5.3.9: https://3v4l.org/VF6oV
149+
if (defined('HHVM_VERSION') || PHP_VERSION_ID < 50311) {
150+
$this->markTestSkipped('Not supported on HHVM and PHP < 5.3.11 (unlimited length)');
151+
}
152+
153+
$allowed = (int)ini_get('max_input_vars');
154+
155+
$middleware = new RequestBodyParserMiddleware();
156+
$request = new ServerRequest(
157+
'POST',
158+
'https://example.com/',
159+
array(
160+
'Content-Type' => 'application/x-www-form-urlencoded',
161+
),
162+
str_repeat('a[]=b&', $allowed + 1)
163+
);
164+
165+
/** @var ServerRequestInterface $parsedRequest */
166+
$parsedRequest = $middleware(
167+
$request,
168+
function (ServerRequestInterface $request) {
169+
return $request;
170+
}
171+
);
172+
173+
$body = $parsedRequest->getParsedBody();
174+
175+
$this->assertCount(1, $body);
176+
$this->assertTrue(isset($body['a']));
177+
$this->assertCount($allowed, $body['a']);
178+
}
179+
110180
public function testDoesNotParseJsonByDefault()
111181
{
112182
$middleware = new RequestBodyParserMiddleware();

0 commit comments

Comments
 (0)