Added multipart data process for PUT, PATCH, DELETE methods

pull/628/head
KnifeLemon 5 days ago
parent 2bb058e6b7
commit e4d003034c

@ -211,14 +211,9 @@ class Request
$this->data->setData($data);
}
}
// Check PUT, PATCH, DELETE for application/x-www-form-urlencoded data
// Check PUT, PATCH, DELETE for data
} else if (in_array($this->method, [ 'PUT', 'DELETE', 'PATCH' ], true) === true) {
$body = $this->getBody();
if ($body !== '') {
$data = [];
parse_str($body, $data);
$this->data->setData($data);
}
$this->getUnSupportMethodBodyData();
}
return $this;
@ -481,4 +476,190 @@ class Request
return $fileArray;
}
/**
* Get the body data for unsupport methods. (PUT, DELETE, PATCH)
* @return void
*/
protected function getUnSupportMethodBodyData() {
$body = $this->getBody();
// Check Content-Type for multipart/form-data
$isMultipart = preg_match('/boundary=(.*)$/is', $this->type, $matches) === 1;
$boundary = $matches[1] ?? null;
// Empty body
if ($body === '') {
return;
}
$data = [];
$file = [];
// Parse application/x-www-form-urlencoded
if ($isMultipart === false) {
parse_str($body, $data);
$this->data->setData($data);
return;
}
// Parse multipart/form-data
$bodyParts = preg_split('/\\R?-+' . preg_quote($boundary, '/') . '/s', $body);
array_pop($bodyParts); // Remove last element (empty)
foreach ($bodyParts as $bodyPart) {
if (empty($bodyPart)) {
continue;
}
// Get the headers and value
[$header, $value] = preg_split('/\\R\\R/', $bodyPart, 2);
// Check if the header is normal
if (strpos(strtolower($header), 'content-disposition') === false) {
continue;
}
$value = ltrim($value, "\r\n");
/**
* Process Header
*/
$headers = [];
// split the headers
$headerParts = preg_split('/\\R/', $header);
foreach ($headerParts as $headerPart) {
if (strpos($headerPart, ':') === false) {
continue;
}
// Process the header
[$headerKey, $headerValue] = explode(':', $headerPart, 2);
$headerKey = strtolower(trim($headerKey));
$headerValue = trim($headerValue);
if (strpos($headerValue, ';') !== false) {
$headers[$headerKey] = [];
foreach (explode(';', $headerValue) as $headerValuePart) {
preg_match_all('/(\w+)=\"?([^";]+)\"?/', $headerValuePart, $headerMatches, PREG_SET_ORDER);
foreach ($headerMatches as $headerMatch) {
$headerSubKey = strtolower($headerMatch[1]);
$headerSubValue = $headerMatch[2];
$headers[$headerKey][$headerSubKey] = $headerSubValue;
}
}
} else {
$headers[$headerKey] = $headerValue;
}
}
/**
* Process Value
*/
if (!isset($headers['content-disposition']) || !isset($headers['content-disposition']['name'])) {
continue;
}
$keyName = str_replace("[]", "", $headers['content-disposition']['name']);
// if is not file
if (!isset($headers['content-disposition']['filename'])) {
if (isset($data[$keyName])) {
if (!is_array($data[$keyName])) {
$data[$keyName] = [$data[$keyName]];
}
$data[$keyName][] = $value;
}
else {
$data[$keyName] = $value;
}
continue;
}
$tmpFile = [
'name' => $headers['content-disposition']['filename'],
'type' => $headers['content-type'] ?? 'application/octet-stream',
'size' => mb_strlen($value, '8bit'),
'tmp_name' => null,
'error' => UPLOAD_ERR_OK,
];
if ($tmpFile['size'] > $this->getUploadMaxFileSize()) {
$tmpFile['error'] = UPLOAD_ERR_INI_SIZE;
} else {
// Create a temporary file
$tmpName = tempnam(sys_get_temp_dir(), 'flight_tmp_');
if ($tmpName === false) {
$tmpFile['error'] = UPLOAD_ERR_CANT_WRITE;
} else {
// Write the value to a temporary file
$bytes = file_put_contents($tmpName, $value);
if ($bytes === false) {
$tmpFile['error'] = UPLOAD_ERR_CANT_WRITE;
}
else {
// delete the temporary file before ended script
register_shutdown_function(function () use ($tmpName): void {
if (file_exists($tmpName)) {
unlink($tmpName);
}
});
$tmpFile['tmp_name'] = $tmpName;
}
}
}
foreach ($tmpFile as $key => $value) {
if (isset($file[$keyName][$key])) {
if (!is_array($file[$keyName][$key])) {
$file[$keyName][$key] = [$file[$keyName][$key]];
}
$file[$keyName][$key][] = $value;
} else {
$file[$keyName][$key] = $value;
}
}
}
$this->data->setData($data);
$this->files->setData($file);
}
/**
* Get the maximum file size that can be uploaded.
* @return int The maximum file size in bytes.
*/
protected function getUploadMaxFileSize() {
$value = ini_get('upload_max_filesize');
$unit = strtolower(preg_replace('/[^a-zA-Z]/', '', $value));
$value = preg_replace('/[^\d.]/', '', $value);
switch ($unit) {
case 'p': // PentaByte
case 'pb':
$value *= 1024;
case 't': // Terabyte
case 'tb':
$value *= 1024;
case 'g': // Gigabyte
case 'gb':
$value *= 1024;
case 'm': // Megabyte
case 'mb':
$value *= 1024;
case 'k': // Kilobyte
case 'kb':
$value *= 1024;
case 'b': // Byte
return $value *= 1;
default:
return 0;
}
}
}

@ -315,7 +315,9 @@ class RequestTest extends TestCase
'error' => 0
];
$request = new Request();
$request = new Request([
'method' => 'PATCH'
]);
$file = $request->getUploadedFiles()['file'];
@ -336,7 +338,9 @@ class RequestTest extends TestCase
'error' => [0, 0]
];
$request = new Request();
$request = new Request([
'method' => 'PATCH'
]);
$files = $request->getUploadedFiles()['files'];

Loading…
Cancel
Save