Skip to content

Commit e708ab4

Browse files
committed
Fix overwriting existing nested array structures
1 parent 8496516 commit e708ab4

2 files changed

Lines changed: 140 additions & 13 deletions

File tree

src/Io/MultipartParser.php

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -252,26 +252,27 @@ private function extractPost($postFields, $key, $value)
252252

253253
$chunkKey = rtrim($chunks[0], ']');
254254
$parent = &$postFields;
255-
for ($i = 1; $i < count($chunks); $i++) {
255+
for ($i = 1; isset($chunks[$i]); $i++) {
256256
$previousChunkKey = $chunkKey;
257-
if ($previousChunkKey !== '' && !isset($parent[$previousChunkKey])) {
258-
$parent[$previousChunkKey] = array();
259-
}
260257

261258
if ($previousChunkKey === '') {
262-
$parent = &$parent[0];
259+
$parent[] = array();
260+
end($parent);
261+
$parent = &$parent[key($parent)];
263262
} else {
263+
if (!isset($parent[$previousChunkKey]) || !is_array($parent[$previousChunkKey])) {
264+
$parent[$previousChunkKey] = array();
265+
}
264266
$parent = &$parent[$previousChunkKey];
265267
}
266268

267269
$chunkKey = rtrim($chunks[$i], ']');
268-
if ($i == count($chunks) - 1) {
269-
if ($chunkKey === '') {
270-
$parent[] = $value;
271-
} else {
272-
$parent[$chunkKey] = $value;
273-
}
274-
}
270+
}
271+
272+
if ($chunkKey === '') {
273+
$parent[] = $value;
274+
} else {
275+
$parent[$chunkKey] = $value;
275276
}
276277

277278
return $postFields;

tests/Io/MultipartParserTest.php

Lines changed: 127 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ public function testPostKey()
2222
$data .= "second\r\n";
2323
$data .= "--$boundary--\r\n";
2424

25-
2625
$request = new ServerRequest('POST', 'http://example.com/', array(
2726
'Content-Type' => 'multipart/mixed; boundary=' . $boundary,
2827
), $data, 1.1);
@@ -41,6 +40,133 @@ public function testPostKey()
4140
);
4241
}
4342

43+
public function testPostStringOverwritesMap()
44+
{
45+
$boundary = "---------------------------5844729766471062541057622570";
46+
47+
$data = "--$boundary\r\n";
48+
$data .= "Content-Disposition: form-data; name=\"users[one]\"\r\n";
49+
$data .= "\r\n";
50+
$data .= "ignored\r\n";
51+
$data .= "--$boundary\r\n";
52+
$data .= "Content-Disposition: form-data; name=\"users\"\r\n";
53+
$data .= "\r\n";
54+
$data .= "2\r\n";
55+
$data .= "--$boundary--\r\n";
56+
57+
$request = new ServerRequest('POST', 'http://example.com/', array(
58+
'Content-Type' => 'multipart/mixed; boundary=' . $boundary,
59+
), $data, 1.1);
60+
61+
$parsedRequest = MultipartParser::parseRequest($request);
62+
63+
$this->assertEmpty($parsedRequest->getUploadedFiles());
64+
$this->assertSame(
65+
array(
66+
'users' => '2'
67+
),
68+
$parsedRequest->getParsedBody()
69+
);
70+
}
71+
72+
public function testPostMapOverwritesString()
73+
{
74+
$boundary = "---------------------------5844729766471062541057622570";
75+
76+
$data = "--$boundary\r\n";
77+
$data .= "Content-Disposition: form-data; name=\"users\"\r\n";
78+
$data .= "\r\n";
79+
$data .= "ignored\r\n";
80+
$data .= "--$boundary\r\n";
81+
$data .= "Content-Disposition: form-data; name=\"users[two]\"\r\n";
82+
$data .= "\r\n";
83+
$data .= "2\r\n";
84+
$data .= "--$boundary--\r\n";
85+
86+
$request = new ServerRequest('POST', 'http://example.com/', array(
87+
'Content-Type' => 'multipart/mixed; boundary=' . $boundary,
88+
), $data, 1.1);
89+
90+
$parsedRequest = MultipartParser::parseRequest($request);
91+
92+
$this->assertEmpty($parsedRequest->getUploadedFiles());
93+
$this->assertSame(
94+
array(
95+
'users' => array(
96+
'two' => '2',
97+
),
98+
),
99+
$parsedRequest->getParsedBody()
100+
);
101+
}
102+
103+
public function testPostVectorOverwritesString()
104+
{
105+
$boundary = "---------------------------5844729766471062541057622570";
106+
107+
$data = "--$boundary\r\n";
108+
$data .= "Content-Disposition: form-data; name=\"users\"\r\n";
109+
$data .= "\r\n";
110+
$data .= "ignored\r\n";
111+
$data .= "--$boundary\r\n";
112+
$data .= "Content-Disposition: form-data; name=\"users[]\"\r\n";
113+
$data .= "\r\n";
114+
$data .= "2\r\n";
115+
$data .= "--$boundary--\r\n";
116+
117+
$request = new ServerRequest('POST', 'http://example.com/', array(
118+
'Content-Type' => 'multipart/mixed; boundary=' . $boundary,
119+
), $data, 1.1);
120+
121+
$parsedRequest = MultipartParser::parseRequest($request);
122+
123+
$this->assertEmpty($parsedRequest->getUploadedFiles());
124+
$this->assertSame(
125+
array(
126+
'users' => array(
127+
'2',
128+
),
129+
),
130+
$parsedRequest->getParsedBody()
131+
);
132+
}
133+
134+
public function testPostDeeplyNestedArray()
135+
{
136+
$boundary = "---------------------------5844729766471062541057622570";
137+
138+
$data = "--$boundary\r\n";
139+
$data .= "Content-Disposition: form-data; name=\"users[][]\"\r\n";
140+
$data .= "\r\n";
141+
$data .= "1\r\n";
142+
$data .= "--$boundary\r\n";
143+
$data .= "Content-Disposition: form-data; name=\"users[][]\"\r\n";
144+
$data .= "\r\n";
145+
$data .= "2\r\n";
146+
$data .= "--$boundary--\r\n";
147+
148+
$request = new ServerRequest('POST', 'http://example.com/', array(
149+
'Content-Type' => 'multipart/mixed; boundary=' . $boundary,
150+
), $data, 1.1);
151+
152+
$parsedRequest = MultipartParser::parseRequest($request);
153+
154+
$this->assertEmpty($parsedRequest->getUploadedFiles());
155+
$this->assertSame(
156+
array(
157+
'users' => array(
158+
array(
159+
'1'
160+
),
161+
array(
162+
'2'
163+
)
164+
),
165+
),
166+
$parsedRequest->getParsedBody()
167+
);
168+
}
169+
44170
public function testEmptyPostValue()
45171
{
46172
$boundary = "---------------------------5844729766471062541057622570";

0 commit comments

Comments
 (0)