0

This should be a simple fix, but I must be missing something. I've been looking around on Stack Overflow and Google for a while with no luck. In a past project, I didn't use Ajax, but doing so would make my current project much better. I am able to submit other forms just fine through Ajax; the problem comes with the file upload.

Here's the problem: When Apache runs the PHP, it doesn't populate the $_POST and $_FILES variables as it normally would, but the raw data is present in php://input. My goal is to have Apache/PHP process this normally to be able to access the file(s) in $_FILES and the other form data in $_POST

Am I missing something here? Is there a way for this to work using Ajax/XHR or am I going to have to abandon that track for file uploads?

I have a simple HMTL form:

<form action="files/upload.php" method="post">
    <input type="file" name="file">
    <input type="text" name="text">
</form>

Here's my JavaScript that gets called when I send the form:

// ...
// (Code that populates the form, url, and type variables)
// ...

var data = new FormData(form);

$.ajax({
    url: url,
    type: type,
    data: data,
    dataType: 'json', // expected response type
    // cache: false, // this didn't change the outcome
    processData: false,
    contentType: false, // have also tried 'x-www-form-urlencoded' and 'multipart/form-data'
    success: function() { /* ...code... */ }
}

Here's my debugging PHP:

<?php
var_dump($_POST);
var_dump($_FILES);
var_dump(file_get_contents('php://input'));
?>

Entering "123456" in the "text" field, the resulting output is:

array(0) {
}
array(0) {
}
string(289) "------WebKitFormBoundaryqcOElDa6F9aoBlux
Content-Disposition: form-data; name="samples"; filename="test.txt"
Content-Type: text/plain

ABCDEFG
------WebKitFormBoundaryqcOElDa6F9aoBlux
Content-Disposition: form-data; name="text"

123456
------WebKitFormBoundaryqcOElDa6F9aoBlux--
"

Other (Potentially Important) Details:

  • I am running this on my VM (not on a publicly-available site)
  • OS: Ubuntu 16.04
  • Apache Vesion: 2.4.18
  • PHP Version: 7.0.32
  • JQuery Version: 3.3.1
  • Browser: Chrome 70
  • My user base is very small and uses modern browsers, so no worries about old browser compatibility.
  • I would like to avoid adding another plugin to do this as much as possible (trying to avoid unnecessary dependencies).
  • I would also like to avoid the "hidden-iframe-as-a-target-to-simulate-asynchronous-requests" solution if possible, just for the sake of cleanliness (but I am willing to resort to that if necessary).

Notable Sources Checked (among others):

Mitchell
  • 11
  • 3

1 Answers1

1

I found where my issue was! I'm using a variable to populate the contentType (contentType: contentType) in the ajax call. I was passing false as the value, but I had one step in the code between that checked to make sure it wasn't an empty string (''), assigning x-www-form-urlencoded if it was empty.

The problem is that I used the != operator instead of the !== operator in that check. Thus, false matched '' and it actually assigned the value of contentType to be x-www-form-urlencoded instead of false. I changed to the correct operator and it is working properly.

For others who have similar problems, use the sources listed above. If something isn't making sense with your call, make sure you use your debugging tools and pause at the ajax call to see the values of your variables before you spend too long getting frustrated. If you have the contentType: false, and there is a file in your FormData object, JQuery will automatically set the Content-Type header properly when it makes the call.

Mitchell
  • 11
  • 3