How to Create an Ajax Style File Uploader

How to Create an Ajax Style File Uploader
September 5, 200928 Comments

In this tutorial we will be creating a simple Ajax style file uploader using jQuery, Ajax and Php. Something you can easily implement on your site, complete with front and backend validation.

Introduction

The application we are going to build will use jQuery's versatility to allow multiple file uploads without refreshing the page or redirecting, complete with front and back end validation to prevent unwanted files being uploaded to your server. Each section will be broken down to describe what it does and why to help you understand it easier.

Ajax uploader example

Ajax uploader example

Step 1 : HTML Markup

Start out by creating your html document and setting up the form that will be used for the file uploader. Save this as index.html.

index.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Ajax Uploader</title>
<link rel="stylesheet" href="style.css" type="text/css" media="screen" title="Main" />
<script type=''text/javascript'' src="path/to/jquery.js">&lt/script>
<script type="text/javascript" src="path/to/ajax/ajaxupload.3.5.js"></script>
<script type="text/javascript">
$(document).ready(function() {
   // do stuff when DOM is ready
 });
</script>
</head>

<body>
  <div id="file_holder">
 <form action="upload.php" method="post" enctype="multipart/form-data">

<p><label for="userfile">Choose file(s) to upload:</label>
 <input id="userfile" class="input" type="file" name="userfile" /></p>
 <div id="loading"><img src="ajax-loader.gif" alt="Loading"/> Loading, please wait...</div>
 <div id="errormes"></div>

<noscript>
<input type="submit" value="submit" class="button2" />
</noscript>
</form>
</div>
</body>
</html>

We start our html document by adding the usual doctype, html, head and body tags. In the head we add the title, link to the stylesheet, a link to the Google jQuery CDN and our Ajax plug-in. Our second script tag is where we will load all of our code after the document is ready.

Inside the body, we layout our page with the #file_holder div which will be our wrapper, the form and the noscript submit button that will help retain usability if the user doesn't have javascript enabled in their browser, our file upload input and the two divs that will hold our loading image as well as the error messages.

Browser with javascript turned off

Browser with javascript turned off

If our user doesn't have javascript enabled, the form action will take care of passing the file to upload.php and the user will simply be re-directed to it and the success or error message displayed instead of remaining on the same page.

Dependent Files

For the loading image, I used "arrows" from http://www.ajaxload.info/.
Choose the image you prefer, save it as ajax-loader.gif and upload it to your server.

We're also going to need the Ajax upload plug-in. You can download it from http://valums.com/ajax-upload/. Save it as ajaxupload.js and upload it to your server in a folder called "ajax".

Step 2 : CSS Styling

This simple form only requires three lines of styling for functionality, to hide the loading div on page load and to color the success and error messages text. You can of course expand on it and make it look prettier than my plain old uploader example. Save this as style.css

style.css

/* CSS Document */
#loading {display:none;}
.error {color:#900000;}
.success {color:#009900;}

Step 3 : The Javascript

Now we can get down to creating the jQuery functions that make this uploader work. Breaking down the sections by action will help outline how the whole thing works a little easier as we go along.

Defining variables

var upload = new AjaxUpload('#userfile', {
		//upload script
		action: 'upload.php',

First we start out by defining the variables for our Ajax uploader by setting our #userfile input as the upload variable and then defining the action the input will take when a file is chosen.

Defining onSubmit

onSubmit : function(file, extension){
		//show loading animation
		$("#loading").show();
		//check file extension
		if (! (extension && /^(jpg|png|jpeg|gif)$/.test(extension))){
       // if extension is not allowed
			 $("#loading").hide();
			 $("Error: Not a valid file extension").appendTo("#file_holder
			 #errormes");
			// cancel upload
       return false;
			} else {
			  // get rid of error
			$('.error').hide();
			}
			//send the data
			upload.setData({'file': file});
		},

The above section tells our uploader what to do as soon as a file is chosen from our file input. First, our loading animation is shown while the file extension is checked. If the file extension doesn't match the predefined ones, the upload is stopped and the user is shown an error message. Once the user tries again with a correct file extension the error is removed and the file data is passed to our upload.php file by our setData command.

Defining onComplete

onComplete : function(file, response){
		//hide the loading animation
		$("#loading").hide();
		//add display:block to success message holder
		$(".success").css("display", "block");
//find the div in the iFrame and append to error message
		var oBody = $(".iframe").contents().find("div");
		//add the iFrame to errormes
		$(oBody).appendTo("#file_holder #errormes");
}

Once our file has been passed to the upload.php file which we will get to soon, the loading image is hidden and the error or success message is shown by grabbing the status from an iframe that the ajaxupload plug-in creates.

The complete script

Copy and paste this entire code in the head section of your document.

<script type="text/javascript">
$(document).ready(function() {
var upload = new AjaxUpload('#userfile', {
		//upload script
		//action: 'upload.php', //uploads disabled for security
		action: 'upload.htm',
		onSubmit : function(file, extension){
		//show loading animation
		$("#loading").show();
		//check file extension
		if (! (extension && /^(jpg|png|jpeg|gif)$/.test(extension))){
       // extension is not allowed
			 $("#loading").hide();
			 $("Error: Not a valid file extension").appendTo("#file_holder #errormes");
			// cancel upload
       return false;
			} else {
			  // get rid of error
			$('.error').hide();
			}
			//send the data
			upload.setData({'file': file});
		},
		onComplete : function(file, response){
		//hide the laoding animation
		$("#loading").hide();
		//add display:block to success message holder
		$(".success").css("display", "block");

		//find the div in the iFrame and append to error message
		var oBody = $(".iframe").contents().find("div");
		//add the iFrame to the errormes td
		$(oBody).appendTo("#file_holder #errormes");
}
	});
});
		</script>

Step 4 : The Php

The php file does the actual uploading to our server while the functions we will implement provide validation to make sure the uploaded file stays within our set guidelines. Breaking this file down by sections will aid in explaining it a little easier.

Setting up variables

$max_filesize = 2097152; // Maximum filesize in BYTES.
$allowed_filetypes = array('.jpg','.jpeg','.gif','.png'); // These will be the types of file that will pass the validation.
$filename = $_FILES['userfile']['name']; // Get the name of the file (including file extension).
$ext = substr($filename, strpos($filename,'.'), strlen($filename)-1); // Get the extension from the filename.
$file_strip = str_replace(" ","_",$filename); //Strip out spaces in filename
$upload_path = '/path/to/uploads/'; //Set upload path

Although some of these are pretty self explanatory, I will explain what everything in the above section does.

The $max_filesize variable determines the maximum size allowed for upload, currently set to 2mb (which is what most hosting providers set their servers to by default), set in bytes.

The $filename variable gets the complete name of the file including extension from our #userfile input.

The $ext variable checks for the correct extension against the $allowed_filetypes array.

The $allowed_filetypes variable builds and array of allowed file types for reference when our check is run in the lower part of the code that we will get to shortly.

The $file_strip replaces any spaces in the file name with underscores, why? If the file name is used in a url such as a link to an image, etc. the spaces are often replaced with %20 making for a sloppy address and hard for search engines to index.

Finally, $upload_path defines the folder which the uploads will be moved into relative to home on your server. In other words, most servers are configured with a file structure like this: /home/yourusername/yoursite.com/path/to/uploads/. Make sure you use the complete path with beginning and ending "/" marks.

Find Server root

To easily find the path you should enter here, try uploading the php script below to your server, name it root.php and access it from your browser. Make sure after you find your server root to delete the file as to not expose it publicly.

<?php $server = $_SERVER['DOCUMENT_ROOT']; ?>
<?php echo $server; ?>

For the rest of the script, it simply processes functions based on our parameters that we set in the code above.

Processing the upload

// Check if the filetype is allowed, if not DIE and inform the user.
 if(!in_array($ext,$allowed_filetypes)) {
  die('<div class="error">The file you attempted to upload is not allowed.</div>');
}

Starting out, the array of file types is checked and if the extension isn't there the script stops execution (die) and outputs a message about the error.

// Now check the filesize, if it is too large then DIE and inform the user.
  if(filesize($_FILES['userfile']['tmp_name']) > $max_filesize) {
     die('<div class="error">The file you attempted to upload is too large.</div>');
}

Check the file size against the variable set, if larger, the script stops execution (die) and outputs a message about the error.

 // Check if we can upload to the specified path, if not DIE and inform the user.
  if(!is_writable($upload_path)) {
     die('<div class="error">You cannot upload to the /uploads/ folder. The permissions must be changed.</div>');
}

This portion checks the folder on the server to make sure it is writable, or able to have our script move a file into it. If not, we use (die) again and output a message to our user.

// Move the file if everything checks out.
  if(move_uploaded_file($_FILES['userfile']['tmp_name'],$upload_path . $file_strip)) {
     echo '<div class="success">'. $file_strip .' uploaded successfully</div>'; // It worked.
 } else {
     echo '<div class="error">'. $file_strip .' was not uploaded.  Please try again.</div>>'; // It failed :(.
 }

If our file has passed all of our backend checks it is then moved into our uploads folder. If something else goes wrong, our user is notified to try again.

upload.php

Copy and paste this entire code into a new file and save it as upload.php

<?php

   $max_filesize = 2097152; // Maximum filesize in BYTES.
	 $allowed_filetypes = array('.jpg','.jpeg','.gif','.png'); // These will be the types of file that will pass the validation.
	 $filename = $_FILES['userfile']['name']; // Get the name of the file (including file extension).
         $ext = substr($filename, strpos($filename,'.'), strlen($filename)-1); // Get the extension from the filename.
	 $file_strip = str_replace(" ","_",$filename); //Strip out spaces in filename
	 $upload_path = '/path/to/uploads/'; //Set upload path

	 // Check if the filetype is allowed, if not DIE and inform the user.
	if(!in_array($ext,$allowed_filetypes)) {
	 		die('<div class="error">The file you attempted to upload is not allowed.</div>');
	}
   // Now check the filesize, if it is too large then DIE and inform the user.
   if(filesize($_FILES['userfile']['tmp_name']) > $max_filesize) {
      die('<div class="error">The file you attempted to upload is too large.</div>');
 	}
   // Check if we can upload to the specified path, if not DIE and inform the user.
   if(!is_writable($upload_path)) {
      die('<div class="error">You cannot upload to the /uploads/ folder. The permissions must be changed.</div>');
	}
	 // Move the file if eveything checks out.
	 if(move_uploaded_file($_FILES['userfile']['tmp_name'],$upload_path . $file_strip)) {
      echo '<div class="success">'. $file_strip .' uploaded successfully</div>>'; // It worked.
    } else {
      echo '<div class="error">'. $file_strip .' was not uploaded.  Please try again.</div>'; // It failed :(.
 }
?>

Setting File Permissons

Before we can test out our uploader, we need to make sure the folder in which our uploads will go is writable. I'll spare you the usual CHMOD to 777 stuff and quickly moving on. If you are familiar with using a telnet client this part isn't for you, it's for the people who were just like me when I was starting out, eager to learn and read the CHMOD part and immediately thought wtf?

Basically, open your ftp client and navigate to the folder where the downloads go from this uploader. Right click on the folder and select properties, and make sure all the check boxes are set to read, write and execute, (777) hit OK and close the window.

In Dreamweaver, navigate to the uploads folder while in remote view and right click on the file and select Set permissions and follow the instructions above.

Changing file permissions on the server

Changing file permissions on the server

Step 5 : Give it a try

The last and final step is to try it out and see if it works. If nothing happens or something breaks, go back and follow the steps I've laid out carefully and figure out what went wrong. feel free to download the source files and check out the demo to get a better feel for how it works.

Thanks for reading!

Author: Jason

Hi, I'm Jason. A front end developer from Grand Rapids, Michigan, and founder of VagrantRadio. I enjoy working with Css, jQuery, Php, learning new techniques in Photoshop and you should follow me on Twitter or Snipplr.

Mojo Themes
  • http://www.productivedreams.com Gopal Raju

    Awesome! Guess I am the first one to comment :)

  • http://www.vagrantradio.com Jason

    First you are! Thanks for checking it out, Gopal.

  • http://www.eyeconimaging.com Philip

    Nice, Maybe as a 2.0 you could have a multiple upload kind of like the interface on
    Animoto.com ?

  • http://www.vagrantradio.com Jason

    Philip,

    I didn’t get to check out the uploader on animoto, but this one does support multiple uploads.

  • http://pchelpforum.ru/u9448/ CerviaK

    Блог отличный. Вручить бы Вам награду за него или просто орден почета. +)

    [Editor] Roughly translated: Blog excellent. Would hand you the award for him, or simply the Order of Honor. +)

    • http://www.vagrantradio.com Jason

      Thanks Cerviak, glad you liked it.

  • http://polprav.blogspot.com/ Polprav

    Hello from Russia!
    Can I quote a post in your blog with the link to you?

    • http://www.vagrantradio.com Jason Pant

      Hi Polprav,

      Sure, go ahead.

  • Ade Dublin

    Hi this is fantastic, I am trying to add an upload field to Joomla’s Virtuemart and I will just see if I can embed this code into Joomla without it stripping all the javascripts away from it. Most importantly, this is a nice one. Keep them coming bro.

    • http://www.vagrantradio.com Jason Pant

      Thanks Ade,

      Hope it works out for you and I have another version in the works.

  • http://www.codepotato.co.uk Gareth

    Great post, have been looking for something like this for ages!

  • http://wordtaps.com mupet

    Nice tutorials, thanks for sharing

  • ed

    Thx for this ajax upload post. I probably am newb into this and everything sounds to work well except that my files are not uploaded. However, the message said that my file successfully was. Something’s wrong that you’ll with your experience find that out. Thx for your help.
    ed

    • http://www.vagrantradio.com Jason Pant

      Hi ed,

      Make sure your permissions on the folder you are uploading to are set to read, write and execute. If you’re still having problems, send me a message through my contact form and I’ll email you back and try to help the best that I can with your code.

      • ed

        Thx again for your response. I will try to figure it out with permissions.

  • http://www.flyboy.co.uk Karl Mariner

    hi jason

    i’m looking for something that i can include in a form as an additional action ie upload a document then use submit for the ‘standard’ elements. the auto upload from this looks like it’s exactly what i’m after… thanks for sharing.

    • http://www.vagrantradio.com Jason

      My pleasure Karl, glad you enjoyed it.

  • B.OBrien

    Thx for the tutorial, I think its what I need :)

    • http://www.vagrantradio.com Jason Pant

      You’re welcome.

  • Diana Mendoza

    I have been trying to make this script work for hours….and it surprises me nobody else have had any problems with it. So I am hoping you can help me out as I have more than one question.

    My issue starts with the ajaxupload.3.5.js file. When I download it from http://valums.com/ajax-upload/ I grab the ajaxupload.js and rename it to ajaxupload.3.5.js inside a folder called ajax and it does not work. However if I use the jquery.ajax.upload.js (no renaming) from your source files it does work. I have been analyzing them and it seems that the one a Valums is a newer version, is this correct? If so, why the newer one does not work?(Needed to say, I have been changing the link on the html to point to the right file) Is there anything else from the Valumn files or site that I have to use or take into account?

    At this point I have managed to get files get to the server, but the success and error messages are not working. My guess is that there is something wrong with the iframe, which is defined in the jquery.ajax.upload.js. If you could help me out I will really appreciate it.

    • http://www.vagrantradio.com Jason Pant

      Diana,

      It appears that since 3.5 and the newest version, 3.9 something has changed because I can’t get it to work either. I will have to take a look and see what needs to be fixed at a later time.

      As far as your trouble with the success messages, do you have an example I could possibly look at to try and help you? Feel free to send me a message through the contact form.

    • http://www.vagrantradio.com Jason Pant

      Diana,

      it seems that you need to change new Ajax_upload to AjaxUpload for it to work with the new version. Everything else works fine once that change is made.

  • idrish

    hi,
    a great tutorial. However i was looking to include the upload inside a form with other fields as well. I can upload the file however i cannot pass other field elements.
    I have
    upload.setData ({‘field1′ : name, ‘field2′ : age});
    inside my onSubmit handler.
    Do you know what could be wrong…Thanks a lot

    • http://www.vagrantradio.com Jason Pant

      idrish,

      If you check the link in this comment you will see a script I used with this to upload the file and pass the form info in an email. Give it a look and it should accomplish what you need it to. You need to pass the form info to something, simply setting the data for it won’t work.

      Snipplr script

      • http://i-tech-life.blogspot.com idrish

        Thanks a lot Jason. It helped… :)

  • http://pulse.yahoo.com/_MPCWX2IZKA2ZH4YRZJKPTCD5PI Sylvia

    The script seems to work fine. Aside from it will not let me upload the the upload folder. I keep getting “You cannot upload to the /uploads/ folder. The permissions must be changed.”. Even though I have changed permissions to 777. Help?

    • http://www.vagrantradio.com VagrantRadio

      Sylvia, either the permissions aren’t set, the folder doesn’t have the correct path or it doesn’t exist. Check your settings and try it again.

  • http://www.usacheap.us/cheaplaptopsusa/ Dern

    Thanks for sharing

Scroll to top