Handling HTTP file uploads, it's not something I deal with all the time, but when I do it can be tricky to get working, this is mostly down to the number of different layers involved in handling file uploading. Here I have collected the most common issues I have experienced.
Setting the correct Form Encoding Type
When creating an HTML Form the default encoding type is application/x-www-form-urlencoded this is fine for submitting text, but not suitable for binary files. For file uploads the enctype must be multipart/form-data. It is set like this in the opening form tag:
<form action="{dest_url}" enctype="multipart/form-data">
If this is not set correctly and you try to upload a file you will find that only the filename is submitted and not the file data.
Does the Destination Directory Exist?
This can be easily overlooked, be sure that the destination directory where the uploaded file is the be stored actually exists on the server. The easiest way to check this is to use the following code in PHP prior to saving the uploaded file.
if (!is_dir($destination_directory)) {
mkdir($destination_directory, 0755, true);
}
This checks if the destination directory exists, if not create it, the 0755 is the permission mask (see below) and the final parameter will create directories recursively.
File and Directory Permissions
At the very least you must allow write access to the destination directory on the server. It can be tempting to chmod 777, which allows read, write and execute to everyone. But this is not secure.
For directories 755 is better, it allows read and directory traversal for all users and writeable by the owner only, but this may not work for some shared hosting providers.
For files 644 is the best, this allows read by everyone and writeable by the owner user and most importantly is not executable by anyone.
Insufficient Disk Space
It goes without saying your going to need enough space to store user uploaded files. But it is also as important to have enough temporary storage space available for user uploads. Many serer admins will have /tmp mounted on a separate volume to ensure the root drive is not filled with temporary files. If you are expecting lots of users to be uploading lots of large files you need enough /tmp space for them. Alternative you can update the php.ini setting upload_tmp_dir to a different temporary storage directory.
Maximum Post Size
PHP, Apache and Nginx all have limits to how much data can be sent by a user. This is a security feature to stop clients from uploading massive files and filling the disk space. If you see Error 413 Request Entity Too Large then this message is from the web server, for NGINX you need to set the client_max_body_size to be large enough for the biggest file size you expect to be uploaded.
client_max_body_size 30m;
This sets the max upload size to 30MB. Also if you are uploading multiple files in a single request then this value must be greater then the sum of all files in the request.
For Apache you need to set LimitRequestBody in either the apache configuration file or .htaccess file. The value is in bytes.
LimitRequestBody 30000000
This sets the max limit to 30MB.
PHP also has a maximum limit on upload file size and post data size, these can be set in the php.ini file or for apache in the .htaccess file, they cannot be changed in code with ini_set()
Conclusion
Handling HTTP uploads is not always simple, there are many areas which can cause issues and this post doesn't even cover all the security implications of accepting users files. Hopefully it will help you deal with some common technical problems.