AJAX file uploading in Javascript can be achieved using XMLHttpRequest & FormData objects.
Quick Sample Code
<input type="file" id="file-input" />
<button id="upload-button">Upload File</button>
<script>
document.querySelector('#upload-button').addEventListener('click', function() {
if(document.querySelector('#file-input').files.length == 0) {
alert('Error : No file selected');
return;
}
let file = document.querySelector('#file-input').files[0];
let allowed_mime_types = [ 'image/jpeg', 'image/png' ];
let allowed_size_mb = 2;
if(allowed_mime_types.indexOf(file.type) == -1) {
alert('Error : Incorrect file type');
return;
}
if(file.size > allowed_size_mb*1024*1024) {
alert('Error : Exceeded size');
return;
}
let data = new FormData();
data.append('file', document.querySelector('#file-input').files[0]);
let request = new XMLHttpRequest();
request.open('POST', 'upload.php');
request.addEventListener('load', function(e) {
console.log(request.response);
});
request.send(data);
});
</script>
How to handle the uploaded file in PHP ? See FAQs at the end of this page.
How is File Uploading Done ?
File uploading in Javascript can be achieved by :
- Choosing a file from the system using a <input type="file" /> tag.
- Validating chosen file for type and size.
- Sending a POST request using the XMLHttpRequest object with the file attached.
Step 1 — Choose a Local File
<input type="file" id="file-input" />
<button id="upload-button">Upload File</button>
To allow multiple files to be chosen, set the multiple attribute.
<input type="file" multiple />
Restrictions on file types can be set by specifying the required MIME type in the accept attribute (although it is possible for the user to override it). Each allowed MIME type needs to be separated by a comma.
<!-- Allow only JPEG & PNG files to choose --> <input type="file" accept="image/jpeg, image/png" />
Step 2 — Validate Chosen File for Type and Size
document.querySelector('#upload-button').addEventListener('click', function() {
// user has not chosen any file
if(document.querySelector('#file-input').files.length == 0) {
alert('Error : No file selected');
return;
}
// first file that was chosen
let file = document.querySelector('#file-input').files[0];
// allowed types
let allowed_mime_types = [ 'image/jpeg', 'image/png' ];
// allowed max size in MB
let allowed_size_mb = 2;
// validate file type
if(allowed_mime_types.indexOf(file.type) == -1) {
alert('Error : Incorrect file type');
return;
}
// validate file size
if(file.size > allowed_size_mb*1024*1024) {
alert('Error : Exceeded size');
return;
}
// validation is successful
alert('You have chosen the file ' + file.name);
// upload file now
});
- The files property of the file input DOM element is an array of file objects representing the files selected by the user.
- type property of chosen file object gives its MIME type.
- size property gives its size in bytes.
- name property gives its name.
Step 3 — Send an AJAX POST Request with File Attachment
let data = new FormData();
// file selected by the user
// in case of multiple files append each of them
data.append('file', document.querySelector('#file-input').files[0]);
let request = new XMLHttpRequest();
request.open('POST', 'upload.php');
// upload progress event
request.upload.addEventListener('progress', function(e) {
let percent_complete = (e.loaded / e.total)*100;
// percentage of upload completed
console.log(percent_complete);
});
// AJAX request finished event
request.addEventListener('load', function(e) {
// HTTP status message
console.log(request.status);
// request.response will hold the response from the server
console.log(request.response);
});
// send POST request to server side script
request.send(data);
- File uploading requires multipart/form-data HTTP POST request to the server. This can be achieved by sending a FormData object.
- The progress event of the XMLHttpRequest.upload object listens for upload progress. A upload progress bar can be created utilizing this.
- The load event handles competition of the AJAX request.
Other FAQs
<?php
$allowed_file_types = ['image/jpeg', 'image/png'];
$allowed_size_mb = 2;
// validate upload error
switch($_FILES['file']['error']) {
// no error
case UPLOAD_ERR_OK:
break;
// no file
case UPLOAD_ERR_NO_FILE:
exit('Error : No file send as attachment');
// php.ini file size exceeded
case UPLOAD_ERR_INI_SIZE:
exit('Error : File size exceeded as set in php.ini');
// other upload error
default:
exit('Error : File upload failed');
}
// validate file type from file data
$finfo = finfo_open();
$file_type = finfo_buffer($finfo, file_get_contents($_FILES['file']['tmp_name']), FILEINFO_MIME_TYPE);
if(!in_array($file_type, $allowed_file_types))
exit('Error : Incorrect file type');
// validate file size
$file_size = $_FILES['file']['size'];
if($file_size > $allowed_size_mb*1024*1024)
exit('Error : Exceeded size');
// safe unique name from file data
$file_unique_name = sha1_file($_FILES['file']['tmp_name']);
$file_extension = strtolower(pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION));
$file_name = $file_unique_name . '.' . $file_extension;
$destination = 'uploads/' . $file_name;
// save file to destination
if(move_uploaded_file($_FILES['file']['tmp_name'], $destination) === TRUE)
echo 'File uploaded successfully';
else
echo 'Error: Uploaded file failed to be saved';
?>