Pure Ajax File Upload with No Frameworks

Sometimes you need to upload files or submit a form using an XHR request (asynchronous). This is easily handled in frameworks like jQuery or Angular, but let’s check this example that showcases ajax file upload with no frameworks.

Ajax File Upload with No Frameworks

Steps to achieve this:

  1. Code a HTML form.
  2. Code a PHP upload script.
  3. Code an Ajax submit function.

The HTML Form

Create a file called index.php. Write in it the following HTML. We must use enctype=”multipart/form-data” attribute on the form to instruct browser that we will also send some binary (the file) with our request. This is mandatory with all forms containing files as inputs. You cannot send a file encoded as a string.

I also added an onsubmit attribute that will call our ajax file upload function. We will create it later.

<!DOCTYPE html>
<html>
    <body>

        <form action="index.php" method="post" enctype="multipart/form-data" onsubmit="ajax_upload(this); return false;">
            Select image to upload:
            <input type="file" id="file" name="fileToUpload"><br/>
            <label>Max age</label>
            <input type="text" name="max_age"><br/>
            <input type="submit" value="Upload Image" name="submit">
        </form>
    </body>
</html>

The PHP upload script

Right below the

</html>

closing tag add this script. We basically made up some requirements such as the request not only needing a file, but also a parameter max_age and the user agent must be Chrome browser.

<?php
if(isset($_POST["submit"])) {
	$user_agent = $_SERVER['HTTP_USER_AGENT'];
	if (!preg_match('/Chrome/i', $user_agent)) { 
	   http_response_code(400);
       echo "user agent not allowed!";
	   die();
    }
	// check for existance of mandatory field max_age
	if (!isset($_POST["max_age"]) || empty($_POST["max_age"])) {
		http_response_code(400);
		echo "please specify max age for file";
		die();
	}
	$max_age = $_POST["max_age"];
	
	$target_dir = "uploads/";
	// check if a file was actually selected
	if (empty($_FILES["fileToUpload"]["tmp_name"])) {
		http_response_code(400);
		echo "no file found";
		die();
	}
	
	$target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]);
	$imageFileType = strtolower(pathinfo($target_file,PATHINFO_EXTENSION));
	
    $check = getimagesize($_FILES["fileToUpload"]["tmp_name"]);
    if($check !== false) {
        echo "Image is OK.";
    } else {
		http_response_code(400);
        echo "File is not an image.";
    }
	
	if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) {
        echo "File ". basename( $_FILES["fileToUpload"]["name"]). " uploaded OK.";
    } else {
		http_response_code(500);
        echo "Error uploading file";
    }
}
?>

The Ajax file upload function

Inside

<body> just after </form>

closing tag add this javascript. We use FormData Api to "serialize" our form. We cannot simply write the value of the file input element (that would be a security breach, no? to just let javascript upload arbitrary files from the computer it runs on...).

Further more we use the append method on the FormData object to add the extra parameter "submit", required in our PHP file, but which apparently FormData forgets to "serialize". Finally we show how you can also add a header to this request not only params.

<script>
	function ajax_upload(form) {
		if (form.fileToUpload.value === "") {
			alert('select file!');
			return;
		}
		if (form.max_age.value === "") {
			alert('input max age!');
			return;
		}
		
		var xhr = new XMLHttpRequest();
		xhr.addEventListener("readystatechange", function () {
		  if (this.readyState === 4) {
			console.log(this.responseText);
		  }
		});
		var formData = new FormData(form);
		formData.append('submit', 'Upload Image');
		xhr.open('post', form.action);
		xhr.setRequestHeader('user-agent', 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36');
		xhr.send(formData);
	}
</script>

Run this file in a xampp or apache server and try it out. Do not forget to make a folder named uploads in the same folder your index.php resides.
Comment xhr.setRequestHeader line and try it out in Firefox or other non-Chrome browser. Check the console for the results.

FacebookTwitterLinkedin