Handling File Uploads

Published: January 8th, 2009 by:

There are very few websites in existence that do not allow, for whatever function, uploading files via the browser. Whether for forum avatars, a gallery script, or even a school project, websites across the World Wide Web employ a myriad of upload scripts, including the ever-popular MySpace, Facebook, and YouTube. With this script and step-by-step explanation, your website can now allow users to add their own files.


An upload script can seem like a daunting task, a process of several steps and error-handling, and in truth, there is a lot to take into account, but the uploading step itself is very simple.  Before we even begin with the form, I suggest (for those not too afraid) checking some settings in your php.ini file, typically located in your PHP root folder.  This step isn’t necessary, so feel free to move on now.  Find the following lines and check the settings as explained below:

  • file_uploads: Be sure this is set to On or your uploads will fail every time
  • upload_max_filesize: Must be at least the maximum file size you wish to allow for uploads
  • post_max_size: Represents the total amount of data allowed to be passed from a form, including file uploads, so I recommend setting this higher than the upload_max_filesize

For most typical PHP setups, the settings should work as they are, but for more advanced users I always recommend learning exactly what that php.ini file does with respect to certain PHP applications.  With those settings taken care of, let’s move on to setting up the basic HTML form.  For the purpose of this example, I’ll use the most basic markup possible.

<html>
<body>
<form method="post" action="upload.php" enctype="multipart/form-data">
<input type="hidden" name="MAX_FILE_SIZE" value="500000" />
<input type="file" name="file" />
<input type="submit" name="submit" value="Submit" />
</form>
</body>
</html>

Three things to keep in mind are the following specifications:

  • enctype=”multipart/form-data”: This attribute must be set as shown or the form will not process properly.  This is different from most basic PHP forms.
  • <input type=”hidden”…: Specifies the maximum file size, in bytes, allowed to be uploaded.  You can omit this line if you specify a maximum in your php.ini file (as described earlier).
  • <input type=”file”…: Notice we are using the “file” type here, again, mandatory for file uploads.  This line will provide the input field with the “Browse” button.

Certainly, the HTML form is the easiest part, so let’s move on to actually handling the file and moving it to its final destination through the PHP processing file.  Above we designated that as “upload.php.”

First of all, we’ll set two variables, arrays actually, which will be very handy a little later on in the script: the possible PHP error messages and the allowed file extensions.


<?php

$errors = array(1 => "The file exceeds the maximum file size specification.",
2 => "The file exceeds the maximum file size specification.",
3 => "The file was not fully uploaded.",
4 => "The file was not properly uploaded.",
6 => "An error occurred during uploading.",
7 => "An error occurred during uploading.",
8 => "An error occurred during uploading.");

$allowedExtensions = array("jpeg","jpg","gif","png");

?>

I suggest leaving the error messages as they are (despite the odd numbering), but feel free to edit the allowed extensions to suit your needs.  As we move through the script, the error messages will be further explained.

The next step in my upload script is to create two functions with very specific, well, functions.  The first will be used when the upload fails:


function uploadFail($error) {
header("refresh: 3; url=index.php");
echo "<p>".$error."  You are now being returned to the upload form.</p>";
}

This will return the user to the upload form just after displaying the error message which is passed to the function.  The next function will obtain the file’s extension:


function getExtension($file) {
$file = explode(".",$file);
return strtolower($file[count($file)-1]);
}

Certainly there are several methods for obtaining the file’s extension, but this is the shortest one I could put together.  Our last stop before starting the handling is one more array which is completely optional.  I use it to ease the process of getting the file’s attributes:


$file = array("tmp" => $_FILES['file']['tmp_name'],
"name" => $_FILES['file']['name'],
"type" => $_FILES['file']['type'],
"size" => $_FILES['file']['size'],
"error" => $_FILES['file']['error']);
$file['ext'] = getExtension($file['name']);

This will remove the need for such long lines each time an attribute is needed, though this step is not necessary.  Note that we used our extension-finding function to do just that, and also be aware that the file type (MIME type) is available if you wish to check the type that way.

Finally, we’re here!  We are ready to begin handling the file and checking for errors.  First we’ll make sure the page is accessed through the form by making sure the ‘submit’ button was pressed:


if (!isset($_POST['submit'])) { uploadFail("You may only access this page through the form."); }

Next, we’ll check for those PHP errors we specified earlier.  If the variable is set to ’0,’ that means there is no error.  Otherwise, let’s reference the array we set earlier and return to the form.  Note that the inherent PHP error returns an integer based on the error encountered.  Our descriptions match pretty well what the problem is, but you can read more extensive descriptions in the manual.


else {
if ($file['error'] != 0) { uploadFail($errors[$file['error']]); }

The last step in checking the file is to reference it against the extensions we listed earlier, so let’s do that now:


else {
if (!in_array($file['ext'],$allowedExtensions)) { uploadFail("Uploaded file (".$file['name'].") is of a disallowed type."); }

If the file makes it this far, that means everything checks out and we just have two steps left: setting the final file name and moving it to the ‘files’ folder.


else { //Now the file is fine; let's finish the upload
//Make sure file name is not already in use
while (file_exists("files/".$file['name'])) {
$file['name'] = time()."-".$file['name'];
}
//Finally move the file to the proper place
if(move_uploaded_file($file['tmp'],"files/".$file['name'])) {
header("Location: success.php");
}

Notice we use the file_exists() function to make sure a file of the same name isn’t already located in the folder, and if so, we rename it something sure to be more unique.  Then, we use the move_uploaded_file() function to move the temporary file to its final resting place, and we take the user to the ‘success’ page where they are greeted with much love and praise for finishing the entire process.  You can create a custom file however you wish and reference it in your ‘upload’ file.

All together, the ‘upload’ file can seem complicated, but it isn’t too tough.  By establishing easy-to-use functions and variables early in the process, we were able to simplify the task and break it down into manageable parts.  The finished script looks like this:


<?php
//The following array will hold all PHP error messages
$errors = array(1 => "The file exceeds the maximum file size specification.",
2 => "The file exceeds the maximum file size specification.",
3 => "The file was not fully uploaded.",
4 => "The file was not properly uploaded.",
6 => "An error occurred during uploading.",
7 => "An error occurred during uploading.",
8 => "An error occurred during uploading.");
$allowedExtensions = array("jpeg","jpg","png","gif","txt");
//This function will return the user to the form, displaying the proper error message
function uploadFail($error) {
header("refresh: 3; url=index.php");
echo "<p>".$error."  You are now being returned to the upload form.</p>";
}
//This function will get the file's extension
function getExtension($file) {
$file = explode(".",$file);
return strtolower($file[count($file)-1]);
}
//The following array will hold all of our file information
$file = array("tmp" => $_FILES['file']['tmp_name'],
"name" => $_FILES['file']['name'],
"type" => $_FILES['file']['type'],
"size" => $_FILES['file']['size'],
"error" => $_FILES['file']['error']);
$file['ext'] = getExtension($file['name']);
//Processing begins here
//Make sure the page is accessed through the form
if (!isset($_POST['submit'])) { uploadFail("You may only access this page through the form."); }
else {
if ($file['error'] != 0) { uploadFail($errors[$file['error']]); } //Check for PHP errors
else {
//Check file extension
if (!in_array($file['ext'],$allowedExtensions)) { uploadFail("Uploaded file (".$file['name'].") is of a disallowed type."); }
else { //Now the file is fine; let's finish the upload
//Make sure file name is not already in use
while (file_exists("files/".$file['name'])) {
$file['name'] = time()."-".$file['name'];
}
//Finally move the file to the proper place
if(move_uploaded_file($file['tmp'],"files/".$file['name'])) {
header("Location: success.php");
}
else { uploadFail($errors[6]); }
}
}
}
?>

Now you’re ready to make your website even more dynamic!  By allowing file uploads, your visitors have the chance to add their own unique contribution to a website they’ll enjoy even more!


Leave a Reply





Wordpress doesn't like it when you post PHP code. Go save your code at pastebin, and post the link here.

About the Author

Kurtis has been working with PHP for nearly four years, and he has moderate experience with MySQL as well as other programming languages, like Java and C++.