Skip to content

Commit

Permalink
Merge pull request #265 from clue-labs/multipart-names
Browse files Browse the repository at this point in the history
Fix parsing multipart chunks with nested field names
  • Loading branch information
jsor authored Nov 25, 2017
2 parents f3eb11e + e708ab4 commit 68d4a12
Show file tree
Hide file tree
Showing 2 changed files with 254 additions and 55 deletions.
77 changes: 29 additions & 48 deletions src/Io/MultipartParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -116,36 +116,29 @@ private function parseChunk($chunk)
return;
}

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

if ($this->headerStartsWith($headers['content-disposition'], 'name')) {
if ($this->headerContainsParameter($headers['content-disposition'], 'filename')) {
$this->parseFile($headers, $body);
} else {
$this->parsePost($headers, $body);
return;
}
}

private function parseFile($headers, $body)
{
if (
!$this->headerContains($headers['content-disposition'], 'name=') ||
!$this->headerContains($headers['content-disposition'], 'filename=')
) {
return;
}

$this->request = $this->request->withUploadedFiles($this->extractPost(
$this->request->getUploadedFiles(),
$this->getFieldFromHeader($headers['content-disposition'], 'name'),
$this->getParameterFromHeader($headers['content-disposition'], 'name'),
$this->parseUploadedFile($headers, $body)
));
}

private function parseUploadedFile($headers, $body)
{
$filename = $this->getFieldFromHeader($headers['content-disposition'], 'filename');
$filename = $this->getParameterFromHeader($headers['content-disposition'], 'filename');
$bodyLength = strlen($body);

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

private function headerStartsWith(array $header, $needle)
{
foreach ($header as $part) {
if (strpos($part, $needle) === 0) {
return true;
}
}

return false;
}

private function headerContains(array $header, $needle)
private function headerContainsParameter(array $header, $parameter)
{
foreach ($header as $part) {
if (strpos($part, $needle) !== false) {
if (strpos($part, $parameter . '=') === 0) {
return true;
}
}

return false;
}

private function getFieldFromHeader(array $header, $field)
private function getParameterFromHeader(array $header, $parameter)
{
foreach ($header as $part) {
if (strpos($part, $field) === 0) {
preg_match('/' . $field . '="?(.*)"$/', $part, $matches);
if (strpos($part, $parameter) === 0) {
preg_match('/' . $parameter . '="?(.*)"$/', $part, $matches);
return $matches[1];
}
}
Expand All @@ -268,30 +250,29 @@ private function extractPost($postFields, $key, $value)
return $postFields;
}

$chunkKey = $chunks[0];
if (!isset($postFields[$chunkKey])) {
$postFields[$chunkKey] = array();
}

$chunkKey = rtrim($chunks[0], ']');
$parent = &$postFields;
for ($i = 1; $i < count($chunks); $i++) {
for ($i = 1; isset($chunks[$i]); $i++) {
$previousChunkKey = $chunkKey;
if (!isset($parent[$previousChunkKey])) {
$parent[$previousChunkKey] = array();
}
$parent = &$parent[$previousChunkKey];
$chunkKey = $chunks[$i];

if ($chunkKey == ']') {
$parent[] = $value;
return $postFields;
if ($previousChunkKey === '') {
$parent[] = array();
end($parent);
$parent = &$parent[key($parent)];
} else {
if (!isset($parent[$previousChunkKey]) || !is_array($parent[$previousChunkKey])) {
$parent[$previousChunkKey] = array();
}
$parent = &$parent[$previousChunkKey];
}

$chunkKey = rtrim($chunkKey, ']');
if ($i == count($chunks) - 1) {
$parent[$chunkKey] = $value;
return $postFields;
}
$chunkKey = rtrim($chunks[$i], ']');
}

if ($chunkKey === '') {
$parent[] = $value;
} else {
$parent[$chunkKey] = $value;
}

return $postFields;
Expand Down
Loading

0 comments on commit 68d4a12

Please sign in to comment.