From family photos to business documents, file uploads power many of the major web applications.
A typical HTML form that allows the user to upload a file may look like this:

<html>
<body>

<form action="upload_file.php" method="post" enctype="multipart/form-data">
File Name:
<input type="file" name="file" id="file" /> 
<br />
<input type="submit" name="submit" value="Submit" />
</form>

</body>
</html>

In this case, the only field displayed on the form is the “file” field.  This field allows the user to browse their hard drive for the file they wish to upload. The enctype “multipart/form-data” specifies that the field should be filled with binary data, as from a file, rather than typed input from the user.
PHP applications allow users to upload files through its $_FILES object. Developers can use the $_FILES object to check on the properties of an uploaded file:

  • $_FILES[“file”][“name”] – the name of the uploaded file
  • $_FILES[“file”][“type”] – the type of the uploaded file
  • $_FILES[“file”][“size”] – the size in bytes of the uploaded file
  • $_FILES[“file”][“tmp_name”] – the name of the temporary copy of the file stored on the server
  • $_FILES[“file”][“error”] – the error code resulting from the file upload

For files that upload successfully, the value of $_FILES[“file”][“error”] is 0. However, some developers may want to place restrictions on the files users can upload.

File Type

Developers can use the $_FILES[“file”][“type”] property to limit the types of files uploaded to those in use for specific applications. For instance, businesses may wish to restrict file types to documents, spreadsheets and presentations, but not allow users to post photos, videos or executable programs.

<?php
if (($_FILES["file"]["type"] != "application/msword")
|| ($_FILES["file"]["type"] != "application/vnd.ms-excel ")
|| ($_FILES["file"]["type"] != "application/vnd.ms-powerpoint"))

  {
  echo "Invalid file type";
  }
?>

File Size

Network administrators may also choose to limit the size of files users can upload to a server in order to reduce bandwidth usage. Developers can set limits on the size of a file a user can upload.

<?php
if ($_FILES["file"]["size"] < 25000)) // Max File Size: 25KB
  {
  echo "File size exceeds maximum.";
  }
?>

Upload Timed Out

Another method that administrators use to conserve bandwidth is to limit the time that a page can use to upload a file. Most PHP applications time out after 30 seconds, but the developer can set the time to as little or as much as needed by changing either the php.ini file on the server or setting the time in the application itself.
PHP.INI File
max_input_time 300

PHP Script

<?php
// code to upload file to temporary directory
ini_set('max_input_time', 300);
// code to move file to new directory
?>

Assigning Upload Directory

The uploaded files then need to be placed into a directory on the server. The move_uploaded_file() method moves the uploaded file from a temporary directory to the assigned directory.

<?php
$uploaddir = '/user/www/uploads/'; //assigns upload directory
$uploadfile = $uploaddir . basename($_FILES['file']['name']); //assigns upload directory and file name

if (move_uploaded_file($_FILES['file']['tmp_name'], $uploadfile)) { //checks file tmp_name for successful upload
    echo "File upload successful.\n";
} else {
    echo "File upload failed\n";
}
?>

These restrictions can allow the user the freedom to upload the files they need, while preventing much of the malicious or accidental damage that can occur when files are transmitted over the network.

By Gerald Hanks
Gerald Hanks has been involved in web development applications since 1996. He has designed applications with JavaScript, ASP.NET and PHP, as well as building databases in MS SQL Server and MySQL. He lives in Houston, Texas.
  • Please don’t encourage people to use $_FILES[“file”][“type”] for file validation. This value comes directly from the user, and can be easily faked. Meaning, I could upload a .php file using a application/msword mime type and the script would consider it valid. Instead, white listing file extensions is a much better approach.

    And the ini_set(‘max_input_time’…) trick won’t work, and if it did, it would be useless, because the PHP script won’t execute until the file finished uploading completely. So unless your script takes more than 30 seconds to validate and move the uploaded file, it’s unnecessary.

    • Totally Agreed for the file extension thing…

    • Ryan Cavicchioni

      I complete agree. Just last week I found a vulnerability in a website because a PHP script uploaded files to a publicly accessible folder. With a simple curl command, I was able to spoof the mime type and then execute the PHP script. The script was vulnerable because the developer was trusting the MIME type in the $_FILES superglobal.

      • With all these bad tutorials out there, I’m not even surprised. Even w3schools.com relies on the MIME type from the user.

        http://www.w3schools.com/php/php_file_upload.asp

        This tutorial here doesn’t really help the case either.

        • steakyfask

          Wow, Just wow. Thanks for the info! wonder how many other holes are in the PHP language itself….

      • pathinfo($path); should be used to get the file type – I wonder how many people know this, and how many websites have a vulnerability because of using $_FILES to get the file type.

    • Tary

      Thanks Nico for the useful set of information. However, can you please eleborate on the same. Is $_FILES array as a whole is vulnerable or is it only for $_FILES[‘filename’][‘type’]?

      Thanks
      Tarun

  • Few more things to check are as below:
    1) Destination is exists or not
    2) Destination is writable or not.

  • Eric Wilson

    I would say understanding how to securely store and access an uploaded file is more important than how you upload it.

    For storage you should always be storing uploaded files outside of the web root. In addition to this I generally never store the file using the filename provided by the user. I prefer to store the file name and extension in the database and assign the actual file a name generated by my script.

    For access you should use a download script that is not able to be directly called by the user. You should also ensure that your download script can not be tricked into accessing files outside of your uploads directory.

  • if ($_FILES[“file”][“size”] great than….

    WTF!

  • siva

    ($_FILES[“file”][“type”] == “application/vnd.openxmlformats-officedocument.wordprocessingml.document”)

Home XML WordPress Web Services Web Development Web Design Underscore Uncategorized Tutorial Tools SQL Server Social Apps Snippet SEO Security RoR Responsive Design Resources Python PHP News MySQL Mobile Miscellaneous jQuery JavaScript Java J2EE HTML5 HTML Design Patterns