PHP Multipart Form Data Put Request

PHP multipart form data PUT request?

First of all, $_FILES is not populated when handling PUT requests. It is only populated by PHP when handling POST requests.

You need to parse it manually. That goes for "regular" fields as well:

// Fetch content and determine boundary
$raw_data = file_get_contents('php://input');
$boundary = substr($raw_data, 0, strpos($raw_data, "\r\n"));

// Fetch each part
$parts = array_slice(explode($boundary, $raw_data), 1);
$data = array();

foreach ($parts as $part) {
// If this is the last part, break
if ($part == "--\r\n") break;

// Separate content from headers
$part = ltrim($part, "\r\n");
list($raw_headers, $body) = explode("\r\n\r\n", $part, 2);

// Parse the headers list
$raw_headers = explode("\r\n", $raw_headers);
$headers = array();
foreach ($raw_headers as $header) {
list($name, $value) = explode(':', $header);
$headers[strtolower($name)] = ltrim($value, ' ');
}

// Parse the Content-Disposition to get the field name, etc.
if (isset($headers['content-disposition'])) {
$filename = null;
preg_match(
'/^(.+); *name="([^"]+)"(; *filename="([^"]+)")?/',
$headers['content-disposition'],
$matches
);
list(, $type, $name) = $matches;
isset($matches[4]) and $filename = $matches[4];

// handle your fields here
switch ($name) {
// this is a file upload
case 'userfile':
file_put_contents($filename, $body);
break;

// default for all other files is to populate $data
default:
$data[$name] = substr($body, 0, strlen($body) - 2);
break;
}
}

}

At each iteration, the $data array will be populated with your parameters, and the $headers array will be populated with the headers for each part (e.g.: Content-Type, etc.), and $filename will contain the original filename, if supplied in the request and is applicable to the field.

Take note the above will only work for multipart content types. Make sure to check the request Content-Type header before using the above to parse the body.

Empty $request-request and $request-files with multipart/form-data

DO NOT specify the Content-Type header yourself, when trying to make such a multipart request. That header needs to include the boundary value (so that the receiver will know how to parse this request) - if you specify it yourself, as just multipart/form-data, then that will be missing.

These request libraries usually know how to properly set it on their own, based on that you are passing in a FormData instance.

Sending multipart/form-data with PUT request doesn't work in Laravel

Laravel (HTML Forms) do not work great with Put requests so you'll need to spoof a POST request as if it was a PUT or PATCH request. On Axios you use the .post verb but within your form data you append

_method: "put"

Information from the official documentation:
https://laravel.com/docs/8.x/routing#form-method-spoofing


Excerpt from the documentation:

HTML forms do not support PUT, PATCH, or DELETE actions. So, when defining PUT, PATCH, or DELETE routes that are called from an HTML form, you will need to add a hidden _method field to the form. The value sent with the _method field will be used as the HTTP request method

Read raw request body for multipart/form-data with php in PUT, PATCH, DELETE ... request

But what if there is a PUT, PATCH, or whatever request type, other
than POST?

Well, since you are the one designing the API, then you are the one who decides whether it accepts only POST, PUT, POST + PUT or any other combination of request headers.

The API should not be designed to "accept-and-try-to-handle" everything a third-party app is submitting to your API. It's the app's job (I mean, the app that connects to API) to prepare a request in such a way, that the API accepts it.

Keep in mind, that enabling multiple request methods (especially those which have to be treated differently) comes with multiple ways to treat a request (e.g. security, types etc).
It basically means that either you have to smartly design a request-handling process, or you'll encounter problems with API methods called with different request-types differently, which will be troublesome.

If you need to get raw contents of the request - @Adil Abbasi seems to be on the right track (as far as parsing php://input is concerned). But note that php://input is not available with enctype="multipart/form-data" as described in the docs.

<?php
$input = file_get_contents('php://input');
// assuming it's JSON you allow - convert json to array of params
$requestParams = json_decode($input, true);
if ($requestParams === FALSE) {
// not proper JSON received - set response headers properly
header("HTTP/1.1 400 Bad Request");
// respond with error
die("Bad Request");
}

// proceed with API call - JSON parsed correctly

If you need to use enctype="multipart/form-data" - read about STDIN in I/O Streams docs, and try it like this:

<?php
$bytesToRead = 4096000;
$input = fread(STDIN, $bytesToRead ); // reads 4096K bytes from STDIN
if ($input === FALSE) {
// handle "failed to read STDIN"
}
// assuming it's json you accept:
$requestParams = json_decode($input , true);
if ($requestParams === FALSE) {
// not proper JSON received - set response headers properly
header("HTTP/1.1 400 Bad Request");
// respond with error
die("Bad Request");
}

Send file using multipart/form-data request in php

If you work with CURL, you have to just:

1, set header 'Content-Type' as 'multipart/form-data;'

2, set option 'RETURNTRANSFER' of curl to true (use option method of curl)

3, set option 'POST' of curl to true (use option method of curl)

4, get source of your file (what you get from fopen in PHP):

$tempFile = tempnam(sys_get_temp_dir(), 'File_');                
file_put_contents($tempFile, $source);
$post = array(
"uploadedFile" => "@" . $tempFile, //"@".$tempFile.";type=image/jpeg",
);

5, use post method of CURL with parameter in $post variable



Related Topics



Leave a reply



Submit