Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

michaeldzjap's avatar

Ajax FormData and PUT fails

I'm trying to update some form data using the @update action of a resource controller, but along the way learned that apparently it is not possible to use PUT in an ajax call together with a FormData object, i.e. it will result in an empty request on the server side. source: http://stackoverflow.com/questions/26630923/angularjs-service-file-upload-laravel/26631348#26631348

So in my controller I am simply returning all request data like so:

public function update(Request $request, $id)
{
    return Response::json($request->all(), 200);
}

So this doesn't work:

// seems no request data makes it to the server
...
var formData = new FormData(this);

$ajax({
    method: PUT,
    url: $(this).prop('action'),
    data: formData,
    processData: false,
    contentType: false,
    headers: { 'X-CSRF-TOKEN': token },
    success: function(data, textStatus, jqXHR) {
        console.log(data);    // prints out an empty array
    }
});
...

Now I found a couple of workarounds. The first one sticking to PUT and instead of FormData using a simple JSON approach:

// this seems to work fine for PUT
$ajax({
    method: PUT,
    url: $(this).prop('action'),
    data: { testData: 'this is a test' },
    headers: { 'X-CSRF-TOKEN': token },
    success: function(data, textStatus, jqXHR) {
        console.log(data);    // prints out the data
    }
});

I am not really sure why the above does work. I mean, why is this allowed, but the use of FormData isn't???

The other workaround I haven't tried yet, but I guess it will work, is to simply add an additional route before my resource controller:

Route::post(some/route, MyController@update);

However, this seems a little hacky to me, since the @update route already exists. Or is this fine? What is the recommended approach here?

Any advice is much appreciated.

0 likes
20 replies
Curdal's avatar

Why not just serialize the form data?

$.ajax({
    ...
    data: $(this).serialize(),
    ...
});
Snapey's avatar

FormData Seems a bit risky still as its IE10+ only.

Are you sure that the object is being filled by your form data var formData = new FormData(this); ?

1 like
michaeldzjap's avatar

Quite sure, although as far as I understand there is not really a way to tell if it is filled or not. formData.get('someFieldName') throws a

TypeError: formData.get is not a function

in Chrome. Haven't tried in any other browsers I have to confess, but if Chrome already chokes on this than it's no use to try another browser as far as I am concerned.

So I've decided to ditch FormData and just go with .serialize() for now, as it seems to do the job just fine.

hotrod's avatar

I ran into this problem as well,

formData works just fine with POST, but it won't work with PUT.

Could anybody explain why?

2 likes
sirajasoftwarehouse16's avatar

I have been trying to find the problem in axios and ajax headers for the whole day, but the problem is actually about FormData cannot work on PUT and PATCH method..

Is this problem have a solution or do I really need to change all the put/patch routes to post?

1 like
MustafaKhaledDev's avatar

The Best Method of this problem is to use post method with input _method

$ajax({
    method: POST,
    url: $(this).prop('action'),
    data: { testData: 'this is a test' , '_method':'PUT'},
    headers: { 'X-CSRF-TOKEN': token },
    success: function(data, textStatus, jqXHR) {
        console.log(data);    // prints out the data
    }
});

this works for me

3 likes
Niks's avatar

i wasted my whole day with put method on formData. Thanks guys, i changed to post method. Is there any other way to upload image than formData?

1 like
gabelbart's avatar

@Niks maybe to late but there is, you can send the raw image as payload (as JS Blob object) and set payload to whatever type of image this is.

Example HTTP request for PHP-Storm builtin Http-Client:

PUT https://my-api.tld/api/images/1
Content-Type: image/jpg

<<< 'my-example-picture.png'

Send data with JS:

canvas.toBlob(blob => {
  axios.put('https://my-api.tld/api/images/1', blob, { headers: {
     'Content-Type': blob.type
  } })
}, 'image/webp', 0.7)

(In this case the image was read from a canvas, but you can easily derive your own use-case with the JS-File API)

You would then read the data this way:

use Illuminate\Http\Request;
use Illuminate\Http\UploadedFile;

function getTmpFileFromRaw(Request $request)
{
  // the true parameter is IMPORTANT to not kill your PHP memory limit
  $src = $request->getContent(true);

  $path = tempnam(sys_get_temp_dir(), 'laravel_raw_file_upload');
  $dst = fopen($path, 'wb');
  if ($dst === false || $src === false) {
    if ($dst === false) {
      unlink($dst);
    }
      return null;
  } else {
    // read the file in chunks to prevent high memory usage for large files
    while (!feof($src)) {
      $chunk = fread($src, 4096);
        if (fwrite($dst, $chunk) === false) {
          @fclose($src) ;
          @fclose($dst) ;
          @unlink($path) ;
          return null ;
        }
      }

      if (fclose($src) === false || fclose($dst) === false) {
        @unlink($path) ;
        return null ;
      } else {
        return new UploadedFile($path, basename($path));
     }
  }
}

The downside: this way you can only send one file and nothing else, no text, no other files, no json. However if you need this you can convert to base64 in JS, send it as JSON-string-property, and convert back on the Laravel side....

mohitpawar's avatar

This is real solution. Method spoofing using ajax.

artytech's avatar

Prior to finding this post, I spent about two hours trying to figure out why Laravel resource routes using the PUT method didn't work with ajax file uploads. I switched to POST, and everything is working now.

Please or to participate in this conversation.