How to Asynchronously Upload Files Using HTML5 and Ajax

    Craig Buckler
    Craig Buckler
    Share

    In my previous posts, we discovered How to Use HTML5 File Drag & Drop, and Open Files Using HTML5 and JavaScript. Now we have a valid set of files, it possible to upload each one to the server. The process occurs asynchronously in the background so the user can complete other on-page tasks while it occurs.

    The HTML

    Let’s examine our HTML form again:
    
    <form id="upload" action="upload.php" method="POST" enctype="multipart/form-data">
    
    <fieldset>
    <legend>HTML File Upload</legend>
    
    <input type="hidden" id="MAX_FILE_SIZE" name="MAX_FILE_SIZE" value="300000" />
    
    <div>
    	<label for="fileselect">Files to upload:</label>
    	<input type="file" id="fileselect" name="fileselect[]" multiple="multiple" />
    	<div id="filedrag">or drop files here</div>
    </div>
    
    <div id="submitbutton">
    	<button type="submit">Upload Files</button>
    </div>
    
    </fieldset>
    
    </form>
    
    We’ll be uploading files to a PHP page, upload.php. The page will handle both the Ajax upload requests and standard form POSTs when the user clicks “Upload Files”. Our JavaScript will ensure that only JPG images are uploaded which are smaller than 300,000 bytes — the value specified in MAX_FILE_SIZE.

    The JavaScript

    First, we require an additional line within our FileSelectHandler() function which is called when one or more files is chosen or dropped. Within our File loop, we’ll call an additional function — UploadFile():
    
    // file selection
    function FileSelectHandler(e) {
    
    	// cancel event and hover styling
    	FileDragHover(e);
    
    	// fetch FileList object
    	var files = e.target.files || e.dataTransfer.files;
    
    	// process all File objects
    	for (var i = 0, f; f = files[i]; i++) {
    		ParseFile(f);
    		UploadFile(f);
    	}
    
    }
    
    File uploading requires the XMLHttpRequest2 object which is currently available in Firefox and Chrome. Before we make the Ajax call, we ensure an .upload() method is available and that we have a JPG with a file size less than the MAX_FILE_SIZE form value:
    
    // upload JPEG files
    function UploadFile(file) {
    
    	var xhr = new XMLHttpRequest();
    	if (xhr.upload && file.type == "image/jpeg" && file.size <= $id("MAX_FILE_SIZE").value) {
    
    The XMLHttpRequest .open() method is set to POST data to upload.php, the action attribute of our upload form. In addition, we set an HTTP header to the file’s name and pass the File object to the .send() method:
    
    		// start upload
    		xhr.open("POST", $id("upload").action, true);
    		xhr.setRequestHeader("X_FILENAME", file.name);
    		xhr.send(file);
    
    	}
    
    }
    

    The PHP

    Our PHP file, upload.php, now checks for the X_FILENAME HTTP header to differentiate between Ajax requests and standard form POSTs:
    
    <?php
    $fn = (isset($_SERVER['HTTP_X_FILENAME']) ? $_SERVER['HTTP_X_FILENAME'] : false);
    
    If a filename has been set, PHP can retrieve the posted data and output it to a new file in an ‘uploads’ folder. Amazingly, this can be achieved in a single line of code:
    
    if ($fn) {
    
    	// AJAX call
    	file_put_contents(
    		'uploads/' . $fn,
    		file_get_contents('php://input')
    	);
    	echo "$fn uploaded";
    	exit();
    	
    }
    
    Standard HTML multipart/form-data posts can be handled using the usual PHP $_FILE functions:
    
    else {
    
    	// form submit
    	$files = $_FILES['fileselect'];
    
    	foreach ($files['error'] as $id => $err) {
    		if ($err == UPLOAD_ERR_OK) {
    			$fn = $files['name'][$id];
    			move_uploaded_file(
    				$files['tmp_name'][$id],
    				'uploads/' . $fn
    			);
    			echo "<p>File $fn uploaded.</p>";
    		}
    	}
    
    }
    
    You can view the demonstration page, however, please note it is hosted on a server without PHP support and the upload will not occur. Therefore, please download the files to examine the code and install it on your own PHP server. The code above will work, but the user won’t know whether a file upload has started, finished or failed. You need to read the final instalment in this series: How to Create File Upload Progress Bars in HTML5 and JavaScript If you enjoyed reading this post, you’ll love Learnable; the place to learn fresh skills and techniques from the masters. Members get instant access to all of SitePoint’s ebooks and interactive online courses, like HTML5 & CSS3 For the Real World. Comments on this article are closed. Have a question about HTML5? Why not ask it on our forums?

    Frequently Asked Questions (FAQs) about HTML5 AJAX File Upload

    How can I handle multiple file uploads using HTML5 and AJAX?

    Handling multiple file uploads using HTML5 and AJAX is quite straightforward. You need to set the ‘multiple’ attribute in your input tag. This allows the user to select multiple files at once from the file dialog box. Then, in your JavaScript code, you can loop through the ‘files’ array of the input element to process each file individually. Each file can be sent to the server using an AJAX request. Remember to handle each file on the server-side appropriately.

    How can I display a progress bar during file upload?

    HTML5 provides a progress event that can be used to track the progress of an AJAX file upload. You can attach a listener to the ‘progress’ event of the XMLHttpRequest object. The event object passed to the listener has ‘loaded’ and ‘total’ properties, which can be used to calculate the percentage of the upload that has been completed. This percentage can then be used to update a progress bar in your HTML.

    How can I handle errors during file upload?

    Error handling during file upload can be achieved by listening to the ‘error’ event of the XMLHttpRequest object. If an error occurs during the file upload, this event will be fired. You can then handle the error appropriately, such as by displaying an error message to the user.

    How can I cancel an ongoing file upload?

    An ongoing file upload can be cancelled by calling the ‘abort’ method of the XMLHttpRequest object. This will immediately terminate the request and trigger the ‘abort’ event. You can listen to this event to perform any necessary cleanup, such as resetting the progress bar and displaying a message to the user.

    How can I restrict the types of files that can be uploaded?

    You can restrict the types of files that can be uploaded by setting the ‘accept’ attribute in your input tag. This attribute takes a comma-separated list of MIME types that are allowed. For example, to allow only JPEG and PNG images, you would set accept=”image/jpeg,image/png”. Then, in your JavaScript code, you can check the ‘type’ property of each file before sending it to the server.

    How can I limit the size of files that can be uploaded?

    Limiting the size of files that can be uploaded can be done in your JavaScript code. Each file in the ‘files’ array of the input element has a ‘size’ property, which gives the size of the file in bytes. You can check this property before sending the file to the server and reject any file that is too large.

    How can I upload files without refreshing the page?

    Uploading files without refreshing the page can be achieved using AJAX. AJAX allows you to send requests to the server and receive responses without reloading the page. When the user selects a file, you can create a new XMLHttpRequest object, set up a listener for the ‘load’ event, and then send the file to the server using the ‘send’ method.

    How can I read the contents of a file on the client side?

    Reading the contents of a file on the client side can be done using the FileReader API. This API provides methods for reading the contents of a file as a text string, a data URL, or an array buffer. You can use these methods in conjunction with the ‘files’ array of the input element to read the contents of a file before it is uploaded.

    How can I send additional data along with the file?

    Sending additional data along with the file can be done using the FormData API. This API allows you to append key-value pairs to a FormData object, which can then be sent to the server using the ‘send’ method of the XMLHttpRequest object. The server can then access these values in the same way as it would access form data.

    How can I handle the response from the server after a file upload?

    Handling the response from the server after a file upload can be done by listening to the ‘load’ event of the XMLHttpRequest object. When the server has finished processing the file and sends a response, this event will be fired. The response from the server can be accessed through the ‘responseText’ or ‘responseXML’ property of the XMLHttpRequest object, depending on whether the server sent a text or XML response.