Skip to content

Commit 68d4a12

Browse files
authored
Merge pull request #265 from clue-labs/multipart-names
Fix parsing multipart chunks with nested field names
2 parents f3eb11e + e708ab4 commit 68d4a12

2 files changed

Lines changed: 254 additions & 55 deletions

File tree

src/Io/MultipartParser.php

Lines changed: 29 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -116,36 +116,29 @@ private function parseChunk($chunk)
116116
return;
117117
}
118118

119-
if ($this->headerStartsWith($headers['content-disposition'], 'filename')) {
120-
$this->parseFile($headers, $body);
119+
if (!$this->headerContainsParameter($headers['content-disposition'], 'name')) {
121120
return;
122121
}
123122

124-
if ($this->headerStartsWith($headers['content-disposition'], 'name')) {
123+
if ($this->headerContainsParameter($headers['content-disposition'], 'filename')) {
124+
$this->parseFile($headers, $body);
125+
} else {
125126
$this->parsePost($headers, $body);
126-
return;
127127
}
128128
}
129129

130130
private function parseFile($headers, $body)
131131
{
132-
if (
133-
!$this->headerContains($headers['content-disposition'], 'name=') ||
134-
!$this->headerContains($headers['content-disposition'], 'filename=')
135-
) {
136-
return;
137-
}
138-
139132
$this->request = $this->request->withUploadedFiles($this->extractPost(
140133
$this->request->getUploadedFiles(),
141-
$this->getFieldFromHeader($headers['content-disposition'], 'name'),
134+
$this->getParameterFromHeader($headers['content-disposition'], 'name'),
142135
$this->parseUploadedFile($headers, $body)
143136
));
144137
}
145138

146139
private function parseUploadedFile($headers, $body)
147140
{
148-
$filename = $this->getFieldFromHeader($headers['content-disposition'], 'filename');
141+
$filename = $this->getParameterFromHeader($headers['content-disposition'], 'filename');
149142
$bodyLength = strlen($body);
150143

151144
// no file selected (zero size and empty filename)
@@ -217,33 +210,22 @@ private function parseHeaders($header)
217210
return $headers;
218211
}
219212

220-
private function headerStartsWith(array $header, $needle)
221-
{
222-
foreach ($header as $part) {
223-
if (strpos($part, $needle) === 0) {
224-
return true;
225-
}
226-
}
227-
228-
return false;
229-
}
230-
231-
private function headerContains(array $header, $needle)
213+
private function headerContainsParameter(array $header, $parameter)
232214
{
233215
foreach ($header as $part) {
234-
if (strpos($part, $needle) !== false) {
216+
if (strpos($part, $parameter . '=') === 0) {
235217
return true;
236218
}
237219
}
238220

239221
return false;
240222
}
241223

242-
private function getFieldFromHeader(array $header, $field)
224+
private function getParameterFromHeader(array $header, $parameter)
243225
{
244226
foreach ($header as $part) {
245-
if (strpos($part, $field) === 0) {
246-
preg_match('/' . $field . '="?(.*)"$/', $part, $matches);
227+
if (strpos($part, $parameter) === 0) {
228+
preg_match('/' . $parameter . '="?(.*)"$/', $part, $matches);
247229
return $matches[1];
248230
}
249231
}
@@ -268,30 +250,29 @@ private function extractPost($postFields, $key, $value)
268250
return $postFields;
269251
}
270252

271-
$chunkKey = $chunks[0];
272-
if (!isset($postFields[$chunkKey])) {
273-
$postFields[$chunkKey] = array();
274-
}
275-
253+
$chunkKey = rtrim($chunks[0], ']');
276254
$parent = &$postFields;
277-
for ($i = 1; $i < count($chunks); $i++) {
255+
for ($i = 1; isset($chunks[$i]); $i++) {
278256
$previousChunkKey = $chunkKey;
279-
if (!isset($parent[$previousChunkKey])) {
280-
$parent[$previousChunkKey] = array();
281-
}
282-
$parent = &$parent[$previousChunkKey];
283-
$chunkKey = $chunks[$i];
284257

285-
if ($chunkKey == ']') {
286-
$parent[] = $value;
287-
return $postFields;
258+
if ($previousChunkKey === '') {
259+
$parent[] = array();
260+
end($parent);
261+
$parent = &$parent[key($parent)];
262+
} else {
263+
if (!isset($parent[$previousChunkKey]) || !is_array($parent[$previousChunkKey])) {
264+
$parent[$previousChunkKey] = array();
265+
}
266+
$parent = &$parent[$previousChunkKey];
288267
}
289268

290-
$chunkKey = rtrim($chunkKey, ']');
291-
if ($i == count($chunks) - 1) {
292-
$parent[$chunkKey] = $value;
293-
return $postFields;
294-
}
269+
$chunkKey = rtrim($chunks[$i], ']');
270+
}
271+
272+
if ($chunkKey === '') {
273+
$parent[] = $value;
274+
} else {
275+
$parent[$chunkKey] = $value;
295276
}
296277

297278
return $postFields;

0 commit comments

Comments
 (0)