HTML5 Mulit-Upload

Now that I have some time to not work on something for someone or another I figure I’d post this.

Uploading multiple files at once used to be strictly in the realm of flash or required javascript to crate multiple upload forms as needed. The first method has the problems with the general incompatibility of flash. The second, well, it’s a very low tech method and limits you to selecting only one file per upload form, real pain.

It’s a two step problem, step one, the form:

Pretty standard form, all you gotta do is add the multiple="multiple" in there and add brakets ([]). Those brakets are the key to the next set, they tell PHP to make the file variable an array so it stacks the files up, instead of just replace the it with the next one (laving you with only the last file uploaded).

Next thing to do is tell PHP up handle the uploaded files one by one. This is pretty simple, heres a quick one.

Snipplr: http://fatfolderdesign.com/ex/multi-upload/index.php

First thing you have to do is get the number of files, I used the count() of the file size because every file has a size, but the same can be said for any $_FILES attribute, so they all work equally well. Using a similar method it’s easy to retrofit an old upload system (which was my original implementation) simple by adding it in the loop and adding the variable to the end of the $_FILES call and it all just works.

This information was surprising difficult to find (most searches returned flash based solutions) but implementation on the existing system (that used FTP to transfer uploaded files to another server and wrote information in multiple databases) was far simpler than any of the flashed based ones, and it’s small and compact which is an added bonus.

An example of the above code can be found here: http://fatfolderdesign.com/ex/multi-upload/index.php.

Edit 2/12/11 Changed the display for the “view uploads” page.

Edit 1/22/13 As requested I’ve made the source of the uploads page viewable here: http://fatfolderdesign.com/ex/multi-upload/upload.php.txt

9 Replies to “HTML5 Mulit-Upload”

    1. foreach works on a copy of the array (eating RAM), and tends to be slower than for. for most application I still use foreach out of simplicity but this ones just a little more logically programmed as a for IMO.

      Also, it would be ($_FILES[‘file’][‘size’] as $i => $size)

      That should also make it clear why it’s slower, it’s dealing with a lot more information just to get a simple number than a for loop. Not to say my for loop is efficient, I’m repetitively calling the count function in it, and that alone may make it a wash.

  1. Also, I just noticed something about your security measure:
    if(strstr($_FILES[‘file’][‘type’][$i], ‘image’)!==false)

    This is not very good. The MIME type is sent by the browser and it CAN be faked. Posting the code here with the live example is a way to get some idiot hack your website 🙂

    Here’s a little harmless proof of concept:
    http://fatfolderdesign.com/ex/multi-upload/uploads/1295309574%20-%20please_secure_your_script.php

    So before you approve this comment you should change your code so that it checks for an array of allowed extensions (.gif, .png, .jpg is a good start).
    Even just changing the type check line to:
    if(strstr($_FILES[‘file’][‘name’][$i], ‘.php’)!==false)
    Would be much better, but still far from great.

    Cheers and happy coding!

    1. A simpler approach since this is not production code and doesn’t need the same level of security as something that’s actually important is to simple deny anything in that folder from executing. When I uploaded this I didn’t think much of it, it’s just a simple example and nothing important would be lost, besides I don’t think I have to worry about someone hacking the site.

      It’s also not checking if the file is already uploaded and if the upload went off without a hitch, two additional things that should be looked at when your doing something with a purpose. Not to mention it’s loading the full size image and shrinking it instead of making a proper thumbnail. All things I considered doing but decided against since I was only posting about HTML5 multi-uploading. Perhaps verifying and securing uploads should be another post.

  2. “simple deny anything in that folder from executing”

    It’s an idea, but I’m sure that with enough thought put into it I could think of a way of still executing a .php file. 🙂

    Here’s one idea that popped to my mind just now – you could regain PHP on files ending with .nice-try by uploading a .htaccess file with:

    AddType application/x-httpd-php .nice-try

    but that would require me to do some manual editing of the POST data being sent (which I don’t have the time to do now) to change the filename to a prepared string which would be something like:

    /../.htaccess

    You’re glueing time() to the beginning of the filename – and that’s good in a sort a way, cause it’s actually somewhat of a security measure.
    There’s really no point in demonstrating this .htaccess hack – this is just yet another flaw that shows you that it’s not as simple as disabling PHP for a folder 🙂 cause the attacker can just reenable it or try using string injection in POST, to upload the file to a totally different directory, which has permissions for executing of .php.

    Also, deleting the website – thus loosing the content (hope you have backups btw.!) isn’t really the worst thing that could happen. The worst thing would be if somebody would start using your website as hosting for malware, which crackers like to distribute in this anonymous way.

    Here’s a nice article I found on securing upload forms:
    http://www.acunetix.com/websitesecurity/upload-forms-threat.htm
    Doesn’t cover it all (nothing covers it all, really), but it’s a decent start.

    Cheers

    1. I’m banning the executing of files not through htaccess but basic directory permissions. And back traveling to my htaccess file would ultimately lead to you a file only the root user can edit (which is a basic security thing that word press sets up even if you don’t).

      I’m sure there is still I way to execute code in that directory (find a way to run it as root since I left it off root so I could see whats going on) but that’ll be true no matter what. I once read an article about web security in development, and i could remember where it was i’d post it, but is has one of the simplest views about true security on the web. It’s not your job to stop them. If someone wants to do something they will find a way no matter what you try and do. It’s simple your job to make it difficult enough that they don’t want to and leave.

      Or that the cause enough of a traffic spike thats it’s obvious and worse case you can pull the proverbial plug.

  3. I agree with you for the most part, especially good point on the RAM eating of foreach.
    First thing I did when I forked your code was to get rid of that count($_FILES[‘file’][‘size’]) from the for and put that beforehand in a variable.

    But back to security with this:
    Changing directory permissions disallowing execution will only work when executing the code directly, not by an interpreter such as PHP, therefore if you turn the executive bit off for user/group/everyone it won’t change a thing with PHP – try it yourself with any PHP file or the directory.

    “And back traveling to my htaccess file would ultimately lead to you a file only the root user can edit (which is a basic security thing that word press sets up even if you don’t).”

    I use WordPress on daily basis doesn’t set up any such thing.
    Wordpress does however generate a .htaccess if you use nice URL rewriting, but that’s about it, the files permissions aren’t too special and the file is by owned by the user who created it, not root. There shouldn’t be any problems overwriting that file. And we probably wouldn’t even have to, cause the attacker could just try uploading a php file to a parent directory with the method I described before.

    PS
    Indeed, it’s our job to make it difficult enough, but it’s just not difficult in this case 😉

    1. Yes for the production version I did the same thing (although the production version uses ftp to transfer files to another server making that ram and speed bonus you get from using for over foreach much more noticeable)

      I didn’t thoroughly tesy this, but I couldn’t get php to run, not from that directory, not when included from that directory, not when told to run from a script outside that directory. I’m sure theres a method but it’s not a particularly simple one (or I’m to tired to see it)

      Even if WordPress doesn’t set the .htaccess file to root only (although I thought it did) I know mines set that way (I double check it, so I must have done it if WP didn’t) so the security benefit is still there. As for preventing the user from uploading to a parent directory, thats an easy one to fix too. The simplest method would be to strip all directory slashes from the filename after the point of upload, although I usually just rename the file based on the md5 or sha, in no way allowing the user to effect the end file name (and it prevents duplicate images too, win/win).

Leave a Reply to Phillip Cancel reply

Your email address will not be published. Required fields are marked *