What I am trying to do:
Essentially I am trying to upload a file to a directory on the server that a user uploads via a HTML <input type="file">
element.
To do this I am creating a new XMLHttpRequest
on the <input>
element's change
event which should send the data of the uploaded file to the upload.php
file which would then handle the uploaded file and upload it to the server asynchronously.
My Code:
HTML
<form class="js-upload-form" method="POST" action="upload.php" enctype="multipart/form-data">
<input class="button js-uploaded-file" type="file" name="file" />
</form>
JS
document.querySelector('.js-uploaded-file').addEventListener('change', function() {
let file = this.files[0];
let formData = new FormData();
formData.append('file', file);
let xhr = new XMLHttpRequest();
xhr.open('POST', 'upload.php', true);
xhr.setRequestHeader('Content-type', 'multipart/form-data');
xhr.upload.onprogress = function(e) {
if (e.lengthComputable) {
let percentComplete = (e.loaded / e.total) * 100;
console.log(percentComplete + '% uploaded');
}
};
xhr.onload = function() {
if (this.status == 200) {
console.info(this.response);
}
};
xhr.send(formData);
}, false);
PHP (upload.php)
print_r($_FILES);
$currentDir = getcwd();
$uploadDirectory = "/uploads/";
$errors = []; // Store all foreseen and unforseen errors here
$fileName = preg_replace("/[^A-Z0-9._-]/i", "_", $_FILES['file']['name']);
$fileSize = $_FILES['file']['size'];
$fileTmpName = $_FILES['file']['tmp_name'];
$fileType = $_FILES['file']['type'];
$uploadPath = $currentDir . $uploadDirectory . $fileName;
if ($fileSize > 2000000) {
$errors[] = "This file is more than 2MB. Sorry, it has to be less than or equal to 2MB";
}
if (empty($errors)) {
$didUpload = move_uploaded_file($fileTmpName, $uploadPath);
if ($didUpload) {
echo "The file " . basename($fileName) . " has been uploaded";
} else {
echo "An error occurred somewhere. Try again or contact the admin";
}
} else {
foreach ($errors as $error) {
echo $error . "These are the errors" . "\n";
}
}
My Problem
This code is simply not working. Printing the $_FILES
array returns an empty array, and console logging the xhr.response
logs the error message set in the PHP ('An error occurred somewhere. Try again or contact the admin'). I would really appreciate any help on solving this issue as I have looked through countless other online resources regarding this issue and even though I feel like my code does exactly what they all say to do, it still doesn't work.
What I've tried:
I tried simply submitting the form instead of trying to do so using the FormData()
object and <input>
change event by adding a submit button and although the page redirected to ...url/upload.php and didn't work asynchronously, the $_FILES
array contained the correct data of the uploaded file and the file was uploaded to the server, which makes me think there must be an issue in my Javascript code, either relating to the XMLHttpRequest
or the FormData
object.
Normally, XMLHttpRequest will generate an appropriate Content-Type from the FormData object.
You, however, are overriding it with one you created manually:
xhr.setRequestHeader('Content-type', 'multipart/form-data');
However, the mandatory boundary
attribute is missing, so PHP can't find the points to split the parts of the request up.
Don't override the Content-Type. Remove the quoted line.