New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Input from PUT requests sent as multipart/form-data is unavailable #13457

Closed
slavicd opened this Issue May 6, 2016 · 43 comments

Comments

Projects
None yet
@slavicd

slavicd commented May 6, 2016

$request->all() returns empty for HTTP PUT requests encoded as multipart/form-data. Since Laravel supports restfull controllers, I reckon it should address this PHP issue and provide a kind of wrapper fix for this.

@fernandobandeira

This comment has been minimized.

Contributor

fernandobandeira commented May 6, 2016

+1 to this

This is actually an old issue, there's even a topic on laravel.io:
http://laravel.io/forum/02-13-2014-i-can-not-get-inputs-from-a-putpatch-request

"The problem looks like lies in Symfony it can't parse the data if it's multipart/form-data, as an alternative try using x-www-form-urlencoded content disposition." by tlgreg

@slavicd

This comment has been minimized.

slavicd commented Jul 1, 2016

How is this closed? Any comments?

@ucheng

This comment has been minimized.

ucheng commented Aug 12, 2016

I also want to know why this is closed.

@mnabialek

This comment has been minimized.

Contributor

mnabialek commented Aug 12, 2016

You should send POST and set _method to PUT (same as sending forms) to make your files visible

@slavicd

This comment has been minimized.

slavicd commented Aug 30, 2016

As far as I know method spoofing is there to address a limitation of the HTML markup, otherwise it would be meaningless.

@rny

This comment has been minimized.

rny commented Sep 11, 2016

cant believe it is a two years old bug and never get fixed.

@schleumer

This comment has been minimized.

Contributor

schleumer commented Jan 18, 2017

I can relate to that, when sending PUT with multipart/form-data via AJAX with files i can't get the files on Laravel's Request. And i checked file_get_contents('php://input'), everything is on php://input, but this is not getting parsed by Laravel.

@gabrielalan

This comment has been minimized.

gabrielalan commented Feb 6, 2017

I'm having this same issue. Any solution???

@jenalgit

This comment has been minimized.

jenalgit commented Feb 26, 2017

send with post and add _method:put on form-data like @mnabialek said., it save me for restful resource put method
image

image
and the result
image
this my route:
image

sorry for my bad english

@shyandsy

This comment has been minimized.

shyandsy commented May 29, 2017

so bug is still there even event though its May, 2017?

@shyandsy

This comment has been minimized.

shyandsy commented May 29, 2017

@jenalgit
how to do this in JQuery? failed when i try

@shyandsy

This comment has been minimized.

shyandsy commented May 29, 2017

@mnabialek
do u know how to to this by JQuery?
could you show some code?

@shaklev

This comment has been minimized.

shaklev commented Jul 7, 2017

Will this issue ever gonna be fix ? I'm making a list "laravel/php acts weird" , should i put this in ? thanks in advance.

@mdaliyan

This comment has been minimized.

mdaliyan commented Jul 9, 2017

I was struggling this problem with axios and laravel on patch method for 2 days. @mnabialek 's solution fixed my problem. Thanks.

For any one who has this problem... Don't forget to use FormData() object:

let Data = new FormData();

// for other types
Data.append( 'notmal_data', 'some data' );

// for files (in vuejs)
Data.append( 'your_file', this.$refs.input.files[0], this.$refs.input.files[0].name ); 

// for files (in jQuery)
Data.append( 'your_file', $('input').files[0], $('input').files[0].name ); 


// Send Patch request to laravel
Data.append('_method', 'PATCH');
axios.post('/url' , Data ). then( Response => { 
   // do stuff
});
@robbiemu

This comment has been minimized.

robbiemu commented Sep 24, 2017

the solution (actually, no, it's a workaround, it doesn't qualify as a solution) of using "_method: put" has a very significant problem for any non-trivial uses: You now are consuming your POST endpoint with what otherwise would be your PUT endpoint. In my case its not the end of the world: there is no POST endpoint yet for this URI, and so the only problem I have is CORS (I have to open POST for the PUT endpoint or else the preflight fails).

This needs to be reopened and resolved.

@libasoles

This comment has been minimized.

libasoles commented Sep 27, 2017

Using Data.append('_method', 'PATCH'); or Data.append('_method', 'PUT');, and then using axios.post may not be the best solution. Because I'm working with an API, and already defining a "PUT" endpoint. If I want this to work I have to define a new endpoint, like:

Route::post('/sales/{id}', 'SaleController@update')->where('id', '[0-9]+'); <- workaround
Route::put('/sales/{id}', 'SaleController@update')->where('id', '[0-9]+'); <- original one

Anyway, it works.

@mdaliyan

This comment has been minimized.

mdaliyan commented Sep 30, 2017

Well, somehow laravel sees the _method = PUT and matches the request to the PUT route even if it's a post request. You didn't need to change your routes at all. @robbiemu @lianguan
But you're right. It only works in laravel, I still have this problem in other frameworks.

@robbiemu

This comment has been minimized.

robbiemu commented Sep 30, 2017

Mdaliyan, it appears to be working because you are not securing your endpoints. If you disallow connections that you do not define, then the Post will be rejected in preflight before a browser will even try to send it,... So even though laravel will treat such a post as a put, the request will never happen because of preflight checks.

As has been noted by multiple people, not just me, this also conflicts with a true post endpoint. That does not appear to be a problem within laravel, I think you've got that right. It can't conflict. But it still could be a problem with audits and external means of network security

@vms82

This comment has been minimized.

vms82 commented Oct 3, 2017

shameless bump, is it posible to proccess the request in different way somehow so we can use libs like axios and consume our endpoints without having to use method spoofing?

@defenestrator

This comment has been minimized.

defenestrator commented Oct 3, 2017

@vms82 yes. This might be what you're after axios/axios#350 (comment)

santigarcor added a commit to santigarcor/laravel-form-js that referenced this issue Oct 11, 2017

@hafezdivandari

This comment has been minimized.

hafezdivandari commented Oct 28, 2017

When sending formData with null properties and formData.append('_method', 'PUT') validation fails (even with nullable rule).

http method _method $request->all() validation
PUT - is empty -
POST post null values are null validation works fine
POST put null values are 'null' (string) validation fails and ignores nullable validation rule and errors on null values

any solution?

@vms82

This comment has been minimized.

vms82 commented Oct 29, 2017

@hafezdivandari you can manualy build the formdata and if the value is falsey false, 0, -0, "", null, undefined or NaN) append empty value
let formdata = new FormData()
!obj.value ? : formdata.set(obj.whatever, '') : formdata.set(obj.whatver, obj.value)
this way laravel will catch it in the middleware as empty and cast it to null etc.., dont forget it comes like string in the request from the formdata obj

@devmycloud

This comment has been minimized.

devmycloud commented Nov 1, 2017

This is a major embarrassment for API developers.
The RESTful standard defines PUT for a reason, and browsers are no excuse here.
What is worse is that our API client developers are forced to code this "magic" _method parameter with the POST verb into their code, meaning that the embarrassment is being propagated into client code. Even if the bug is fixed on the server side, we then have to go to N clients and tell them they need to change their code to work the way it should have from the beginning. In other words, API v2. Can anyone point to the place this is broken? We would like to fix it before N becomes a large number.

@slavicd

This comment has been minimized.

slavicd commented Nov 2, 2017

@devmycloud this goes as deep as PHP itself. If I remember right - multipart/form-data is not visible in php://input if the method is PUT.

@devcircus

This comment has been minimized.

Contributor

devcircus commented Nov 2, 2017

I'm not sure why we keep flogging the Laravel issue board about this as it is a PHP issue. A bug report was filed here with PHP in 2011. There are issues reported on the Slim repo, the Symfony repo, and of course this issue with Laravel. There are reddit threads, blog posts, etc., etc.
If you want to read comments and theories from the past 10 years or more, click this google search.

@devmycloud

This comment has been minimized.

devmycloud commented Nov 5, 2017

@devcircus - Thank you!

There were comments with references to where this problem originates, and those references suggested the problem lies in Laravel, but you have clarified it. PHP simply does not process the incoming data for PUT or PATCH requests. However, the data is available via 'php://input' and using code developed to process that input, we have managed to properly implement PATCH methods with Laravel!

Here is a gist for our code that processes the input:
https://gist.github.com/devmycloud/df28012101fbc55d8de1737762b70348

We now have PATCH methods are RESTful with no 'POST/_method' magic required.

@devcircus

This comment has been minimized.

Contributor

devcircus commented Nov 5, 2017

I've been working on something similar recently. Thanks for the gist.

@t202wes

This comment has been minimized.

t202wes commented Mar 9, 2018

I implemented @devmycloud's solution, and wrapped the fix in a middleware.

https://gist.github.com/devmycloud/df28012101fbc55d8de1737762b70348#gistcomment-2374843

@crhg

This comment has been minimized.

Contributor

crhg commented Mar 13, 2018

I found a php extension pecl/apfd, which lets PHP's post handler parse multipart/form-data and application/x-www-form-urlencoded without regard to the request's request method.

It seems to work well in combination with Laravel.

@luizguilhermefr

This comment has been minimized.

luizguilhermefr commented Apr 12, 2018

Is crazy, but this unexpected behavior still occurs. Yes, until now.

@yooouuri

This comment has been minimized.

yooouuri commented Apr 25, 2018

Im getting the same error (in VueJS)

let id = 13123123 // some id

const data = new FormData()
data.append('somedata', 'hey')

this.$http.put(`http://homestead.test/api/customers/${id}`, data).then(response => {
  console.log(response)
}, response => {
  console.log(response)
});

And in my PUT endpoint I return $request->all()

My console.log shows me an empty array [] No properties

@Delindel

This comment has been minimized.

Delindel commented Apr 26, 2018

PUT and POST work for me in terms of receiving data in my routes, however if we talk about file uploads, the story differs:

POST: Files are seen correctly using application/x-www-form-urlencoded.

PUT: File is simply nulled.

Some header processing is differing under the hood that we are simply not aware of.

@yooouuri

This comment has been minimized.

yooouuri commented Apr 26, 2018

@Delindel PATCH/PUT is working if I don't use FormData

let data = `name=Youri`

fetch('some_url', {
  method: 'PATCH',
  headers: {
    'Content-type': 'application/x-www-form-urlencoded'
  },
  body: data
})
  .then((response) => response.json())
  .then((response) => {
    console.log(response)
  });

Works but

let data = new FormData()
data.append('name', 'Youri')

fetch('some_url', {
  method: 'PATCH',
  headers: {
    'Content-type': 'application/x-www-form-urlencoded'
  },
  body: data
})
  .then((response) => response.json())
  .then((response) => {
    console.log(response)
  });

Does not

@skeeith

This comment has been minimized.

skeeith commented May 25, 2018

it's May 26, 2018 and this freaking bug STILL EXISTS!!! WOW.

I just tested this. Laravel request->all() can't parse any of the form data.

@slavicd

This comment has been minimized.

slavicd commented May 25, 2018

How much research, other than looking at the calendar, have you done, before posting this, skeith? The bug is not in Laravel. Please see the thread and pertaining links for an in depth view.

@lksnmnn

This comment has been minimized.

lksnmnn commented Aug 7, 2018

I had this issue with POST and multipart/form-data from an Angular 4 client.

Calling

$request->replace($request->all()); 

"fixed" this for me for now. All parts where accessible then.

@skeeith

This comment has been minimized.

skeeith commented Aug 7, 2018

@lksnmnn my issue was I was sending PUT/PATCH Request instead of POST with a data of _method.
because Laravel doesn't recognize PUT or PATCH but only GET or POST with a field name of _method that has a value of PUT or PATCH.

@joleenshook

This comment has been minimized.

joleenshook commented Oct 19, 2018

This was a ridiculously hard bug to track down. Mostly because I couldn't believe that something this dumb could actually be the problem. But I just ran into it, so still an issue in PHP 7. Glad I'm working in Laravel, at least this workaround fixed it. I feel for anyone with a different framework.

@spmsupun

This comment has been minimized.

spmsupun commented Oct 22, 2018

@taylorotwell

@Stunext

This comment has been minimized.

Stunext commented Oct 29, 2018

I created a middleware for this:
https://gist.github.com/Stunext/9171b7a8f3633b0b601a0feb8088dca1

Just add this middleware in "App\Http\Kernel" file in the middleware api group.

Some methods like "isValid()" maybe not work since the files that this middleware creates are not done so through PHP's usual uploaded file mechanisms.

@Conrekatsu

This comment has been minimized.

Conrekatsu commented Oct 30, 2018

@devcircus - Thank you!

There were comments with references to where this problem originates, and those references suggested the problem lies in Laravel, but you have clarified it. PHP simply does not process the incoming data for PUT or PATCH requests. However, the data is available via 'php://input' and using code developed to process that input, we have managed to properly implement PATCH methods with Laravel!

Here is a gist for our code that processes the input:
https://gist.github.com/devmycloud/df28012101fbc55d8de1737762b70348

We now have PATCH methods are RESTful with no 'POST/_method' magic required.

This fixed my problem thank you very much!

@vickymessii

This comment has been minimized.

vickymessii commented Nov 20, 2018

still bug has not resolved 2018, 👎
a working example with Laravel 5.7 & Vue JS

`
       let xhttp = new XMLHttpRequest();
        let formData = new FormData();
        let file = document.getElementById('legal_reg_number');
        formData.append('_method', 'PATCH');
        formData.append('legal_reg_number', file.files[0]);
        xhttp.open("POST", "http://localhost/tur/api/v1/submit_from", true);
        xhttp.send(formData)

Route::any('submit_from','UserController@StoreUserForm')->name('submit_from');`
@fauzipadlaw

This comment has been minimized.

fauzipadlaw commented Dec 5, 2018

I created a middleware for this:
https://gist.github.com/Stunext/9171b7a8f3633b0b601a0feb8088dca1

Just add this middleware in "App\Http\Kernel" file in the middleware api group.

Some methods like "isValid()" maybe not work since the files that this middleware creates are not done so through PHP's usual uploaded file mechanisms.

Thanks! ❤️ 🍺

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment