13

I'm uploading a file with XMLHttprequest. Here is the JS function, that uploads a file:

var upload = function(file) {
    // Create form data
    var formData = new FormData();
    formData.append('file', file);

    var xhr = new XMLHttpRequest();

    // Open
    xhr.open('POST', this.options.action);

    // Set headers
    xhr.setRequestHeader("Cache-Control", "no-cache");
    xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
    xhr.setRequestHeader("Content-Type", "multipart/form-data");
    xhr.setRequestHeader("X-File-Name", file.fileName);
    xhr.setRequestHeader("X-File-Size", file.fileSize);
    xhr.setRequestHeader("X-File-Type", file.type);

    // Send
    xhr.send(formData);
}

On the server side, in upload.php I read the file this way:

file_put_contents($filename, (file_get_contents('php://input')));

Everything works fine, except that I get a PHP Warning:

Missing boundary in multipart/form-data POST data in Unknown on line 0.

If I remove this line: xhr.setRequestHeader("Content-Type", "multipart/form-data"); the warning goes away.

What should be the problem here?

Tamás Pap
  • 17,777
  • 15
  • 70
  • 102
  • 1
    Try using `application/x-www-form-urlencoded` as content type. Or leave it out, since this is the default content-type sent by an ajax request. – Elias Van Ootegem Sep 10 '12 at 09:43
  • 1
    This can work, but for large files (even 5-600 KB) the browser will freeze because it has to send the file in a "text" format. I have to use the `multipart/form data`. – Tamás Pap Sep 10 '12 at 09:55
  • 3
    Sorry, overlooked the file-upload bit (don't know how), but [I think this might answer your queston](http://stackoverflow.com/questions/5933949/how-to-send-multipart-form-data-form-content-by-ajax-no-jquery), more specifically: `xhr.setRequestHeader("content-type","multipart/form-data; charset=utf-8; boundary=" + Math.random().toString().substr(2));` should do the trick – Elias Van Ootegem Sep 10 '12 at 10:00
  • Also tried this solution. The warning dissapears, but in this case no data is coming: file_get_contents('php://input') is empty. Appreciate your help Elias, and if you have any other idea, please tell me. – Tamás Pap Sep 10 '12 at 10:10
  • I believe the issue is that you're missing boundary in your "Content-Type" header. It should look something like: Content-Type: multipart/form-data; boundary="same-as-the-boundary-in-request-body" This is usually created for you if you omit setting the "Content-Type" header – Alexis Kalyvitis May 10 '13 at 12:10
  • @TamásPap: if you get rid of all the headers code, do you have content like '------WebKitFormBoundaryklb8qUzyCQJSI440 Content-Disposition: form-data; name="file"' be added to the file after uploaded? I have these extra data, it bothers me a lot as it changes sha1 of file during transmission. – Ng2-Fun Apr 29 '16 at 19:40

1 Answers1

20

Well this is strange a little bit for me, but this is what worked:

// Open
xhr.open('POST', this.options.action, true);

// !!! REMOVED ALL HEADERS

// Send
xhr.send(formData);

In this case, on server side I don't read the file sent via php://input but the file will be in the $_FILES array.

This solved my problem, but I'm still curious why appears now the file in $_FILES?

Tested in Chrome, Mozilla, Safari, and IE10.

Tamás Pap
  • 17,777
  • 15
  • 70
  • 102
  • 12
    [The spec](http://www.w3.org/TR/XMLHttpRequest/#the-send-method) explains (point 3) that the browser sets the correct headers (including the correct multipart boundary indication in the Content-Type) if you haven't manually specified anything. The file appears in `$_FILES` because PHP [automatically puts files from multipart form uploads in that superglobal](http://www.php.net/manual/en/features.file-upload.post-method.php). – Gijs Sep 10 '12 at 10:54
  • 1
    I had to comment out this for it to work `xhr.setRequestHeader('Content-Type', 'multipart/form-data');`...... (but kept `xhr.setRequestHeader('Accept', 'multipart/form-data')`) – MCH Jul 23 '20 at 10:55