Skip to content

Commit

Permalink
Merge pull request #16387 from sinbadxiii/issue-16271
Browse files Browse the repository at this point in the history
Parse multipart/form-data  from PUT - Issue 16271
  • Loading branch information
niden authored Jul 28, 2023
2 parents 3c1ad54 + 582bf57 commit 60cf4ae
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 2 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG-5.0.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## [5.2.4](https://github.com/phalcon/cphalcon/releases/tag/v5.2.4) (xxxx-xx-xx)

### Fixed

- Parse multipart/form-data from PUT request [#16271](https://github.com/phalcon/cphalcon/issues/16271)


## [5.2.3](https://github.com/phalcon/cphalcon/releases/tag/v5.2.3) (2023-07-26)

### Fixed
Expand Down
85 changes: 83 additions & 2 deletions phalcon/Http/Request.zep
Original file line number Diff line number Diff line change
Expand Up @@ -1721,12 +1721,20 @@ class Request extends AbstractInjectionAware implements RequestInterface, Reques
if null === cached {
let contentType = this->getContentType();

if typeof contentType == "string" && stripos(contentType, "json") != false {
let cached = this->getJsonRawBody(true);
if typeof contentType == "string" {

if (stripos(contentType, "json") != false) {
let cached = this->getJsonRawBody(true);
}

if (stripos(contentType, "multipart/form-data") !== false) {
let cached = this->getFormData();
}

if typeof cached != "array" {
let cached = [];
}

} else {
let cached = [];

Expand All @@ -1745,4 +1753,77 @@ class Request extends AbstractInjectionAware implements RequestInterface, Reques
noRecursive
);
}

/**
* parse multipart/form-data from raw data
*/
private function getFormData() -> array
{
var boundary, matches;

preg_match("/boundary=(.*)$/is", this->getContentType(), matches);

let boundary = matches[1];

var bodyParts;

let bodyParts = preg_split("/\\R?-+" . preg_quote(boundary, "/") . "/s", this->getRawBody());

array_pop(bodyParts);

array dataset = [];
var bodyPart;

for bodyPart in bodyParts {
if empty(bodyPart) {
continue;
}

var splited;
let splited = preg_split("/\\R\\R/", bodyPart, 2);

array headers = [];
var headerParts, headerPart;

let headerParts = preg_split("/\\R/s", splited[0], -1, PREG_SPLIT_NO_EMPTY);

for headerPart in headerParts {
if (strpos(headerPart, ":") === false) {
continue;
}

var exploded, headerName, headerValue;

let exploded = explode(":", headerPart, 2),
headerName = strtolower(trim(exploded[0])),
headerValue = trim(exploded[1]);

if strpos(headerValue, ";") !== false {
var explodedHeader, part;
let explodedHeader = explode(";", headerValue);

for part in explodedHeader {
let part = preg_replace("/\"/", "", trim(part));

if strpos(part, "=") !== false {
var explodedPart, namePart, valuePart;
let explodedPart = explode("=", part, 2),
namePart = strtolower(trim(explodedPart[0])),
valuePart = trim(trim(explodedPart[1]), '"'),
headers[headerName][namePart] = valuePart;

} else {
let headers[headerName][] = part;
}
}
} else {
let headers[headerName] = headerValue;
}
}

let dataset[headers["content-disposition"]["name"]] = splited[1];
}

return dataset;
}
}
62 changes: 62 additions & 0 deletions tests/unit/Http/Request/GetPutCest.php
Original file line number Diff line number Diff line change
Expand Up @@ -127,4 +127,66 @@ public function httpRequestGetPutJson(UnitTester $I)

$_SERVER = $store;
}

/**
* Tests Phalcon\Http\Request :: getPut() - multipart/form-data
*
* @issue @16271
* @author Phalcon Team <[email protected]>
* @since 2023-07-28
*/
public function httpRequestGetPutMultipartFormData(UnitTester $I)
{
$I->wantToTest('Http\Request - getPut() - multipart/form-data');

stream_wrapper_unregister('php');
stream_wrapper_register('php', PhpStream::class);

$boundary = md5(microtime());

$data = <<<EOF
----------------------------{$boundary}
Content-Disposition: form-data; name="fruit"
orange
----------------------------$boundary
Content-Disposition: form-data; name="quantity"
4
----------------------------$boundary
EOF;

file_put_contents(
'php://input',
$data
);

$store = $_SERVER ?? [];
$time = $_SERVER['REQUEST_TIME_FLOAT'];
$_SERVER = [
'REQUEST_TIME_FLOAT' => $time,
'REQUEST_METHOD' => 'PUT',
'CONTENT_TYPE' => "multipart/form-data; boundary={$boundary}",
];

$request = new Request();

$expected = [
'fruit' => 'orange',
'quantity' => '4',
];

$actual = file_get_contents('php://input');

$I->assertSame($data, $actual);

$I->assertSame(
$expected,
$request->getPut()
);

stream_wrapper_restore('php');

$_SERVER = $store;
}
}

0 comments on commit 60cf4ae

Please sign in to comment.