Problem Solved: Simple PHP uploads

For my second problem solved post I wanted to cover something that at one time was a bit mystifying before I actually

Are you a wizard?Are you a wizard?

tried it. I always assumed the ability to upload files was a complicated process that had plenty of moving parts behind the scenes. Well, it turned out that just wasn’t the case.

This was again part of the phone record project I wrote about in my previous problem solved post. If you didn’t read that one I’ll save you the time. I needed a way to upload, splice, and evaluate several XML files that contained my company’s phone records. As part of that process I clearly needed to get the files uploaded and available for the script.

All you need for this is a basic HTML form and some handy PHP script to check the user uploads and move the files from the temp folder to your directory of choice. So, lets start with the form. It’s important to note that when you setup the form you want to set the enctype attribute. This is to tell the server how the data should be encrypted – for this purpose it should be set to multipart/form-data. That means no characters are encrypted and your looking to upload files; by the way this can ONLY be used when the method attribute is set to POST. The full thing should look like the following:

A few things to take note of in the above example. First, your type attribute on the input should be file. Second, you’ll notice that the multiple attribute is set to multiple and the name has brackets included. This is entirely optional if you’re only uploading a single file at a time. As is, this allows you to select and upload multiple files at one time which are then accessed through the file array. So this will get you as far as being able to select a file and hit upload. From there you need some PHP to catch those files and move them to the desired destination. As of right now, if you hit the upload button the server will just move your file to a temporary location till it’s either moved to a permanent location or it is deleted by the server after x amount of time. I’m going to post the PHP below and I’ll step through it below:

foreach($FILES as $file){//begin for each for($n=0; $narray($extension, $allowedExts))//if allowed type { if ($file["error"][$n] > 0)//if error { echo "Return Code: " . $file["error"][$n] . "
"; continue; }//end if error else //no error { echo "

"; echo "

Success!

"; echo "Upload: " . $file["name"][$n] . "
"; echo "Type: " . $file["type"][$n] . "
"; if (fileexists("upload/" . $file["name"][$n])) //if already exists { echo "".$file["name"][$n] . " already exists. "; }//end if already exists else //does not already exist { moveuploadedfile($file["tmpname"][$n], "upload/" . $file["name"][$n]); echo "Stored in: " . "upload/" . $file["name"][$n]; }//end else does not already exist echo "
"; }//end else no error }//end if allowed type else //not allowed type { echo "Invalid file
"; }//end else not allowed type }//end main for loop to count entries }//end main for each

OK, I know that’s a lot to take in so I’m going to break this up as best I can. It’s not as terrible as it looks, I promise. The first thing you need to know is that after submission the file(s) you uploaded from the form and all the info associated with them is now in the associative $FILES array. To be completely honest the structure of the $FILES array is a little silly but I’ll save that for another post. But, know that you’ll have entries for the Name, tmpName, Size, and type among others. So, starting from the top – we’re stepping through that associative array with our outer most foreach loop.

Next, since the $_FILES array stacks the info in different piles ( Name[0], Name[1], tmpName[0],tmpName[1] etc.) we need a numerical index that represents the number of uploaded files.

for($n=0; $n

So, we setup an additional for loop with an index variable ($n) set to 0. We’ll loop this for as many files as we have. To get that number, we take one of our stacks – in this case the file name – and count how many values are in the array. There is a one to one correlation between any of the data in the array so you could use tmpName or size and you’ll get the same number.

if(!$file["name"][$n]){//if nothing was entered don't even bother continue; } $allowedExts = array("xml"); $extension = end(explode(".", $file["name"][$n])); if (in_array($extension, $allowedExts))//if allowed type

First and foremost, it’s important to check that the file uploaded by the user has a name and a valid extension. That first line just checks to make sure the file name is not empty. If you’re only allowing pictures your array should include jpg, png, gif etc. As for my case I was only accepting XML files so the only valid extension is .xml. You check this by pulling apart the current file name with explode delimited by the dot (.) and checking to see if the extension is in your array. If not, bounce it out, if it is, lets move on.

if ($file["error"][$n] > 0)//if error { echo "Return Code: " . $file["error"][$n] . "
"; continue; }//end if error else //no error { echo "

"; echo "

Success!

"; echo "Upload: " . $file["name"][$n] . "
"; echo "Type: " . $file["type"][$n] . "
"; if (fileexists("upload/" . $file["name"][$n])) //if already exists { echo "".$file["name"][$n] . " already exists. "; }//end if already exists else //does not already exist { moveuploadedfile($file["tmpname"][$n], "upload/" . $file["name"][$n]); echo "Stored in: " . "upload/" . $file["name"][$n]; }//end else does not already exist echo "
"; }//end else no error }//end if allowed type else //not allowed type { echo "Invalid file
"; }//end else not allowed type }//end main for loop to count entries }//end main for each

I’m going to attempt this whole last chunk at once. It’s tough with all these nested if’s and loops. If you need to, refer back up to the full code at the top. And, while I’m mentioning it, make sure you keep things nice and tidy as far as white space and alignment. The plugin I’m using to display the code doesn’t do well with that so everything is showing up without indents.

Moving on – We need to check for any general error code. This is given in the $FILES array and is referenced with our index ($n). If there isn’t an error, the name is set, and the file has a valid extension we’re looking good for a valid upload and should be clear to move it to our directory. You’ll see that there is some HTML output to show the name and type of the file, you can skip that as it’s optional. The very last thing we need to check, is that if the file has already been uploaded. You’ll see the use of php’s fileexists coupled with the upload directory – in this case upload/ – and our file name with index (remember were still looping with the index through each file’s info). Assuming that file name doesn’t exist we’re clear to move it from the tmp folder to our upload directory. That is done really easily with moveuploadedfile, which takes – in order – the current file’s temp name ($file[“tmp_name”]) and what directory you’d like to move it to. That’s it, it already knows exactly where to pluck the file from.  After that comes the tedious chore of closing out all of our nested loops and conditional statements but you’ve likely done that since the start.

Conclusion

This look a lot more daunting than it actually is. The nested loops and conditionals give it some girth but are ultimately necessary. For doing basic uploads this can take you a long way. I’ve just recently been trying to work this into something slightly more complex where, basically, created modules can all upload an individual image and are all in a different array depending on what vertical they fall into. This really becomes a challenge with the $_FILES array structured as it is because it’s very hard to then work in the identifying vertical. I found out it is do able but it requires a significant amount of work around. Maybe I’ll make that into another post in the future.

comments powered by Disqus