HTML-Market

Upload Multiple Images with PHP

Mar 2, 2007 10:47 pm
by: Shane Goodwin

Learn how to create a standalone application for uploading images to your website. This application uses an "iframe" to achieve an AJAX-like method for easily uploading multiple images to your server without the need for an FTP client. Images are automatically uploaded one at a time and displayed as thumbnails so you can keep track of which ones have already been uploaded. This tutorial is an enhanced version of Asynchronous image file upload without AJAX by Martin Konicek. The enhancements include being able to preview "gif" and "png" images in addition to "jpg" images, notification if the image already exists, an error message in case the upload fails, and image size restrictions.

Here is an example of the image uploader we will be creating:

Image of Uploader Application

There are two pages to create for this image uploader. The first of these pages can easily be incorporated into an existing web page while the second page is what does all the work and will be referenced by an iframe. We'll start with the first page...

Page Setup

Here is the code for this first page:

<html>
<head></head>
<body>
<div id="fileupload">
<div id="iframe">
<iframe src="upload.php" frameborder="0"></iframe>
</div>
<div id="images"></div>
</div>
</body>
</html>

As you can see, this part is very simple. The first div is a container for the entire application so that you can place this uploader anywhere on your page. We then have another div called "iframe" to contain the iframe as well as other iframe's that we will be creating in our main script. There is one final div called "images" that will house our thumbnail images. And that does it for this page. The second page will be a little more in depth, however.

Upload Script Overview

Here is the basic script that will actually upload our images to the server. I say basic because this only includes one of the enhancements I mentioned earlier - the ability to preview "gif" and "png" images in a thumbnail area. (Please Note: The following code will allow you to upload any type of file; even malicious files. Therefore, it is NOT recommended to put this code on your page as it is. We will be changing it later to restrict the uploads to images only, as well as add the other three enhancements.)

<?php
$temp = $_FILES['image']['tmp_name'];
$file_name = $_FILES['image']['name'];
$dir = '/images/'.$file_name;

if(move_uploaded_file($temp, $dir)) {
?>
<script>
var par = window.parent.document;
var images = par.getElementById('images');
var imgdiv = images.getElementsByTagName('span')[<?php echo (int)$_POST['imgnum']?>];
var image = imgdiv.getElementsByTagName('img')[0];
imgdiv.innerHTML = '<img src="<?php echo $dir ?>" width="100" height="100" alt="<?php echo $file_name ?>" title="<?php echo $file_name ?>">';
</script>
<?php
exit();
}
?>

<html><head>
<script language="javascript">
<!--
function upload(){
// hide old iframe
var par = window.parent.document;
var num = par.getElementsByTagName('iframe').length - 1;
var iframe = par.getElementsByTagName('iframe')[num];
iframe.className = 'hidden';

// create new iframe
var new_iframe = par.createElement('iframe');
new_iframe.src = 'upload.php';
new_iframe.frameBorder = '0';
par.getElementById('iframe').appendChild(new_iframe);

// add image progress
var images = par.getElementById('images');
var new_span = par.createElement('span');
var new_img = par.createElement('img');
new_img.src = 'images/loadingicon.gif';
new_img.className = 'load';
new_div.appendChild(new_img);
images.appendChild(new_span);

// send
var imgnum = images.getElementsByTagName('span').length - 1;
document.iform.imgnum.value = imgnum;
document.iform.submit();
}
//-->
</script>

</head><body>
<form name="iform" action="" method="post" enctype="multipart/form-data">
<input id="file" type="file" name="image" onchange="upload()" />
<input type="hidden" name="imgnum" />
</form>
</body>
</html>

The credit for this script goes to Martin Konicek as he is the one responsible for most of the function of this script. However, he only explains the code briefly through comments so I will exlain in a little more detail here for you. Let's break the script down. There are two main sections in this script - a PHP section and a non-PHP section. The non-PHP section will appear in the browser within the iframe tags while the PHP section is what does the uploading and also sends thumbnails to the "images" div from our first page. We'll start at the bottom to make everything else easier to understand as we go:

</head><body>
<form name="iform" action="" method="post" enctype="multipart/form-data">
<input id="file" type="file" name="image" onchange="upload()" />
<input type="hidden" name="imgnum" />
</form>
</body>
</html>

This should seem fairly simple. What we have is an HTML form with a few inputs. The name of the form is "iform", it has no action since all of the action will take place using an "onchange" command in the first input, its method is "post", and most importantly, it has an additional attribute called "enctype" with a value of "multipart/form-data". This simply changes the encoding of the form so that when the form is submitted to the server, the server knows that there are actual files included that need to be kept in their original format. Don't forget to set this attribute in your form or your files will not upload. Inside the form we have two inputs: a "file" input and a "hidden" input. The "file" input is what creates our textbox and "Browse" button and allows us to search for files. It also includes the "onchange" event responsible for setting everything in motion. The "hidden" input will be used in a Javascript function to denote which iframe is visible. There are going to be iframes created dynamically so we need a way to identify which one we are on - hence the purpose of this input.

Now that we understand the form elements responsible for uploading files, we will go to the middle of the code and run through the "upload" Javascript function that is called from our "onchange" event. The first part of this function is:

<html><head>
<script language="javascript">
<!--
function upload(){
// hide old iframe
var par = window.parent.document;
var num = par.getElementsByTagName('iframe').length - 1;
var iframe = par.getElementsByTagName('iframe')[num];
iframe.className= 'hidden';

This will be the beginning of the actual HTML page that forms our iframe source so we include the "HTML" and "HEAD" tags. Next, we specify that this is Javascript so the browser will run the code correctly. Then on to the good stuff. We first specify that this is the "upload" function. This first section is responsible for hiding the old iframe since it already contains an uploaded file. The next line of Javascript simply sets up a variable called "par" that we use to reference the main website page; not the iframe page. The next line sets up another variable that allows us to reference the iframe that we just used to upload an image. Note that there are multiple iframes - a new one is created everytime a file is uploaded. Therefore, each iframe contains one and only one form with the textbox and browse button.

Each iframe is named by its position in an array of iframes. Since arrays start at zero by default, the name of the most recent iframe will be the total number of iframes less 1. We use this number in the next line of code to actually reference the most recent iframe and assign it to a variable called "iframe". Since only one file can be uploaded in each iframe, we need to hide it now that we are done with it by giving it a new class name of "hidden". In our CSS file, we will specify that the "hidden" class be invisible and that the width and height both be "0".

Continuing our javascript function, the next section of code is:

// create new iframe
var new_iframe = par.createElement('iframe');
new_iframe.src = 'upload.php';
new_iframe.frameBorder = '0';
par.getElementById('iframe').appendChild(new_iframe);

Since we hid the last iframe, we now need to create a new one in its place. That's the purpose of this section of the script. This is all a little easier to understand than the last part. First, we establish a new variable called "new_iframe" that creates a new iframe element on our main page. This iframe's source is the name of this iframe page. (So, if you save all of this code as "upload.php", then the source of the iframe we are creating is also "upload.php". For aesthetic purposes, we have set the border of this new iframe to "0". Finally, we append this new iframe to the last iframe that we just set to "hidden".

Still with me? Moving on...

// add image progress
var images = par.getElementById('images');
var new_span = par.createElement('span');
var new_img = par.createElement('img');
new_img.src = 'images/loadingicon.gif';
new_img.className = 'load';
new_span.appendChild(new_img);
images.appendChild(new_span);

This section adds a temporary loading image to our thumbnails div. This image serves as a placeholder in the thumbnails div to inform the user that the image is still uploading. The first variable here simply references our "images" div from the main page that contains our thumbnails. Then we create a new span to hold a new image and call it "new_span". Next we create an image element to be be displayed within our new span and call it "new_img". We also specify the source of our loading image as well as give it a class name of "load". Don't use my loading image though! Make your own at this great website: Ajaxload. This website is really cool and easily allows you to create a number of different loading images. The last two lines of code here simply append our new temporary image to our new span and append the new span to our "images" div. Simple enough?

The final part of our "upload" function is:

// send
var imgnum = images.getElementsByTagName('span').length - 1;
document.iform.imgnum.value = imgnum;
document.iform.submit();
}
//-->
</script>

This section is responsible for actually sending the file we wish to upload to the server where we can work with it using PHP code. The first line of code here is similar to what we did earlier: we are figuring out the most recent "imgnum" hidden input by counting the number of imgnum's and subtracting 1 to account for the array starting at 0. This allows us to set a value for the form to submit. This value will be used to add the thumbnail to the correct place in our "images" div. We then submit the form and end the javascript code. And that takes care of our "upload" function.

Next we need to write the PHP script to deal with the file that has been sent to the server and to change our temporary image into the actual image that we need. To begin all this, we need to set up variables for the file that was uploaded:

<?php
$temp = $_FILES['image']['tmp_name'];
$file_name = $_FILES['image']['name'];
$dir = '/images/'.$file_name;

When a file is uploaded using its form element (seen at the bottom of our main script), it is placed in a temporary directory using a temporary name. It is done this way for security reasons; the idea is that the script should first run checks on the file to make sure it is not malicious before moving it to a real directory. We will do these checks later although we have skipped them for now. This temporary name can be accessed using the PHP command "$_FILES['form element']['tmp_name']. 'Form element' refers to the name of the "file" type input. So, in our form, the 'form element' is "image". We simply set up a variable for this value called "temp". The second variable we set up contains the name of the file being uploaded as it is written on the user's computer. It uses the same format as the previous command except that we replace "tmp_name" with "name". This variable will allow us to rename the uploaded file to its real name when it is moved to a real directory. The last variable here sets up which directory the file needs to be moved to. You will either need to create an "images" folder on your server or change the directory to the location where you want your images to upload to.

The next bit of code is a little more involved:

if(move_uploaded_file($temp, $dir)) {
?>
<script>
var par = window.parent.document;
var images = par.getElementById('images');
var imgdiv = images.getElementsByTagName('span')[<?php echo (int)$_POST['imgnum']?>];
var image = imgdiv.getElementsByTagName('img')[0];
imgdiv.innerHTML = '<img src="<?php echo $dir ?>" width="100" height="100" alt="<?php echo $file_name ?>" title="<?php echo $file_name ?>">';
</script>
<?php
exit();
}
?>

This section of code does three things: it moves the file from its temporary directory to the real directory, removes the temporary loading image from the thumbnails, and inserts the image we have just uploaded into the thumbnails to replace the loading image.

The first line of code is responsible for moving the newly uploaded file to the correct folder on our server using the PHP command "move_uploaded_file(temporary file,directory)". Here we are using our previously declared variables to move the temporary file in the temporary directory to our real directory with the name we specified. This command is placed within an "if" structure so that we can inform the user in case the upload fails by using an "else" command. We will add this functionality later.

Next, we end the PHP code with "?>". The next lines of code will be more Javascript so to keep it simple we will place it outside the PHP code. That first line of Javascript simply sets up the variable "par" again so that we can easily reference the main website page. The following line creates another variable that we can use to reference our "images" div. The next line creates yet another variable that searches within our "images" div and selects the most recent span created. Remember that the most recent span was created when a file was chosen in the form - it was part of our "upload" function. How do we know it is the most recent span? Remember how our form contains a "hidden" element called "imgnum"? This number was submitted via the "POST" method whenever we upload a file. This number is also increased at the same time in our prior javascript code. So we can use the PHP variable "$_POST['form element name']" to reference this most recent span. We need to reference this most recent span so we can replace the uploading image with the new actual image.

Now that we have selected the most recent span and assigned it to a variable called "imgdiv", we can select the temporary image within that span and remove it. We select the image in the next line of code and assign that image a name of "image". The very next line of code then removes this image so that we can insert another image in its place. We do this using some DOM: we will change the "inner" HTML inside our most recent span to the image of what we just uploaded. We also give the image a title, alternate text for those with images disabled, and a height and width of "100" for uniformity. Then we end the script, restart PHP, use an exit command to stop running this script, close the if statement, and close PHP again.

And there you have it. The basic script created by Martin Konicek with one enhancement: the ability to preview "png" and "gif" images in addition to "jpg" images. This script as it is has the ability to upload and preview three image formats. However, this script currently allows a user to upload any file format they want to your server - including files with malicious code.