Ask Ben: Uploading Multiple Files Using ColdFusion

Posted January 8, 2008 at 8:53 AM

Tags: Ask Ben, ColdFusion

After posting a while back about uploading a file and emailing it using ColdFusion, I was asked to put up a demo of how to upload multiple files using ColdFusion. For this demo, I am concentrating only on the upload aspect and not worrying about any emailing functionality as I believe that adding that is easy after the upload is complete.

Before I show the code, I just want to preempt some stuff. For starters, I am using a LOT Of error handling via ColdFusion's CFTry / CFCatch tags. In practice, I don't really use that much error handling. However, I am just trying to instill some good practice here and drive home the fact that when dealing with a third party service (the file system), there is always potential for errors to occur. And, the truth is, I should really use better error handling anyway.

That being said, this code is only partially tested as I could not generate any errors on the file upload. I think the error handling looks good, but again, not fully tested. The best that I could do was to change the NameConflict attribute in the CFFile tag from MakeUnique to Error and upload two files of the same name, which threw the following error:

There was a problem uploading file #2: File overwriting is not permitted in this instance of the CFFile tag.

So, it seems to be working; but, I just want to stress that I couldn't generate a file system error and therefore some of this code is still theoretical.

Additionally, I build the page such that the number of files to be uploaded can be variable. Right now, it is set to have 5 file fields, but that can be set using the REQUEST.FileCount variable. I know that this kind of stuff is handled very Web 2.0 dynamic style these days, but for this demo, I wanted to keep it really simple and straight forward.

That being said, here is the code:

 Launch code in new window » Download code as text file »

  • <!---
  • Set the number of files that can uploaded in a single
  • form submission.
  • --->
  • <cfset REQUEST.FileCount = 5 />
  •  
  • <!--- Set the destination folder for uploads. --->
  • <cfset REQUEST.UploadPath = ExpandPath( "./uploads/" ) />
  •  
  •  
  •  
  • <!--- Param the appropriate number of file fields. --->
  • <cfloop
  • index="intFileIndex"
  • from="1"
  • to="#REQUEST.FileCount#"
  • step="1">
  •  
  • <!--- Param file value. --->
  • <cfparam
  • name="FORM.file#intFileIndex#"
  • type="string"
  • default=""
  • />
  •  
  • </cfloop>
  •  
  •  
  • <!--- Param upload flag. --->
  • <cftry>
  • <cfparam
  • name="FORM.submitted"
  • type="numeric"
  • default="0"
  • />
  •  
  • <cfcatch>
  • <cfset FORM.submitted = 0 />
  • </cfcatch>
  • </cftry>
  •  
  •  
  • <!--- Set up an array to hold errors. --->
  • <cfset arrErrors = ArrayNew( 1 ) />
  •  
  •  
  • <!--- Check to see if the form has been submitted. --->
  • <cfif FORM.submitted>
  •  
  • <!---
  • Here is where we would validate the data; however,
  • in this example, there really isn't anything to
  • validate. In order to validate something, we are going
  • to require at least one file to be uploaded!
  • --->
  •  
  •  
  • <!---
  • Since we are going to require at least one file, I am
  • going to start off with an error statement. Then, I am
  • gonna let the form tell me to DELETE IT.
  • --->
  • <cfset ArrayAppend(
  • arrErrors,
  • "Please select at least one file to upload"
  • ) />
  •  
  •  
  • <!--- Loop over the files looking for a valid one. --->
  • <cfloop
  • index="intFileIndex"
  • from="1"
  • to="#REQUEST.FileCount#"
  • step="1">
  •  
  • <cfif Len( FORM[ "file#intFileIndex#" ] )>
  •  
  • <!--- Clear the errors array. --->
  • <cfset ArrayClear( arrErrors ) />
  •  
  • <!--- Break out of loop. --->
  • <cfbreak />
  •  
  • </cfif>
  •  
  • </cfloop>
  •  
  •  
  • <!---
  • Check to see if there were any form validation
  • errors. If there are no errors, then we can continue
  • to process the form. Otherwise, we are going to skip
  • this and just let the page render again.
  • --->
  • <cfif NOT ArrayLen( arrErrors )>
  •  
  • <!---
  • Create an array to hold the list of uploaded
  • files.
  • --->
  • <cfset arrUploaded = ArrayNew( 1 ) />
  •  
  •  
  • <!---
  • Loop over the form fields and upload the files
  • that are valid (have a length).
  • --->
  • <cfloop
  • index="intFileIndex"
  • from="1"
  • to="#REQUEST.FileCount#"
  • step="1">
  •  
  • <!--- Check to see if file has a length. --->
  • <cfif Len( FORM[ "file#intFileIndex#" ] )>
  •  
  • <!---
  • When uploading, remember to use a CFTry /
  • CFCatch as complications might be encountered.
  • --->
  • <cftry>
  • <cffile
  • action="upload"
  • destination="#REQUEST.UploadPath#"
  • filefield="file#intFileIndex#"
  • nameconflict="makeunique"
  • />
  •  
  • <!---
  • Store this file name in the uploaded file
  • array so we can reference it later.
  • --->
  • <cfset ArrayAppend(
  • arrUploaded,
  • (CFFILE.ServerDirectory & "\" & CFFILE.ServerFile)
  • ) />
  •  
  •  
  • <!--- Catch upload errors. --->
  • <cfcatch>
  •  
  • <!--- Store the error. --->
  • <cfset ArrayAppend(
  • arrErrors,
  • "There was a problem uploading file ###intFileIndex#: #CFCATCH.Message#"
  • ) />
  •  
  • <!---
  • Break out of the upload loop as we
  • don't want to deal with any more
  • files than we have to.
  • --->
  • <cfbreak />
  •  
  • </cfcatch>
  • </cftry>
  •  
  • </cfif>
  •  
  • </cfloop>
  •  
  •  
  • <!--- Check to see if we have any form errors. --->
  • <cfif ArrayLen( arrErrors )>
  •  
  •  
  • <!---
  • We encountered an error somewhere in the upload
  • process. As such, we want to clean up the server
  • a bit by deleteing any files that were
  • successfully uploaded as part of this process.
  • --->
  • <cfloop
  • index="intFileIndex"
  • from="1"
  • to="#ArrayLen( arrUploaded )#"
  • step="1">
  •  
  • <!--- Try to delete this file. --->
  • <cftry>
  • <cffile
  • action="delete"
  • file="#arrUploaded[ intFileIndex ]#"
  • />
  •  
  • <cfcatch>
  • <!--- File could not be deleted. --->
  • </cfcatch>
  • </cftry>
  •  
  • </cfloop>
  •  
  •  
  • <cfelse>
  •  
  •  
  • <!---
  • !! SUCCESS !!
  • The files were properly uploaded and processed.
  • Here is where you might forward someone to some
  • sort of success / confirmation page.
  • --->
  •  
  •  
  • </cfif>
  •  
  • </cfif>
  •  
  • </cfif>
  •  
  •  
  • <!--- Set the content type and reset the output buffer. --->
  • <cfcontent
  • type="text/html"
  • reset="true"
  • />
  •  
  • <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  • <html>
  • <head>
  • <title>Multiple File Uploads</title>
  • </head>
  • <body>
  •  
  • <cfoutput>
  •  
  • <h1>
  • Multiple File Upload ColdFusion Example
  • </h1>
  •  
  •  
  • <!--- Check to see if we have any errors to display. --->
  • <cfif ArrayLen( arrErrors )>
  •  
  • <p>
  • Please review the following errors:
  • </p>
  •  
  • <ul>
  • <cfloop
  • index="intError"
  • from="1"
  • to="#ArrayLen( arrErrors )#"
  • step="1">
  •  
  • <li>
  • #arrErrors[ intError ]#
  • </li>
  •  
  • </cfloop>
  • </ul>
  •  
  • </cfif>
  •  
  •  
  • <form
  • action="#CGI.script_name#"
  • method="post"
  • enctype="multipart/form-data">
  •  
  • <!--- Submission flag. --->
  • <input type="hidden" name="submitted" value="1" />
  •  
  •  
  • <!---
  • Loop over the number of files we are going to
  • allow for the upload.
  • --->
  • <cfloop
  • index="intFileIndex"
  • from="1"
  • to="#REQUEST.FileCount#"
  • step="1">
  •  
  • <label for="file#intFileIndex#">
  • File #intFileIndex#:
  • </label>
  •  
  • <input
  • type="file"
  • name="file#intFileIndex#"
  • id="file#intFileIndex#"
  • />
  •  
  • <br />
  •  
  • </cfloop>
  •  
  •  
  • <input type="submit" value="Upload Files" />
  •  
  • </form>
  •  
  • </cfoutput>
  •  
  • </body>
  • </html>

Hope that helps. Please let me know if there are any follow up questions.

Download Code Snippet ZIP File

Post Comment  |  Ask Ben  |  Permalink  |  Other Searches  |  Print Page


You Might Also Be Interested In:



Learning ColdFusion 9 - ColdFusion 9 tutorials, samples, examples, demos

Reader Comments

duncan
Jan 8, 2008 at 11:06 AM // reply »
18 Comments

Just wondering why you add the step="1" attribute on all your cfloops?


Jan 8, 2008 at 11:11 AM // reply »
5,406 Comments

@Duncan,

There is no technical reason for this. I know that the loop increment defaults to 1. However, since many of my posts are meant to help people learn, I believe that it is best to spell everything out explicitly so there is no mystery and people can concentrate on the real task at hand.


Jan 8, 2008 at 11:02 PM // reply »
22 Comments

A nice addition for the beginners out there might be to use the result attribute and show'em how it can be used to interact with the db.

Great post!

Will


Feb 6, 2008 at 7:04 AM // reply »
1 Comments

thank you for this, very helpful


John
Sep 17, 2008 at 9:11 AM // reply »
2 Comments

Thanks Ben. Have been wondering how to do this for a little while now. Nice tutorial.


May 21, 2009 at 1:57 PM // reply »
1 Comments

Greetings -

I tried this code to upload multiple files, which worked great. However, while the files are uploaded to the right directory, I wanted to upload the name of files to my database.

Here is my databse code I added to this script:


INSERT INTO Uploads (user_ID, File_Name, Date_Published)
VALUES (#Form.ClientID#, 'file#intFileIndex#', #Now()#)

Issue 1 -
------------
The upload runs successfully, but I am not getting the right filenames populated on the database. Exp.: I have photo-1.jpg photo-2.jpg photo-3.jpg - On the "upload" directory, I get the right names: photo-1.jpg photo-2.jpg photo-3.jpg But on the database I get: file1 file2 file3 - instead I'd like to see the right files on the database as follows: photo-1.jpg photo-2.jpg photo-3.jpg

Issue 2 -
------------
2) I set the script to show 5 uploads:
as follows: <cfset REQUEST.FileCount = 5 />

But once they upload 5 photos, they can come back and upload more, I tested, I expected to see an error message that says "you have reached max limit which is 5 files/photos"

Issue 3 -
------------
Could we specify the file size. i.e. only up to 1MB per file can be uploaded

Please note, I am not too concerned about Issue 2 or 3, but the issue 1 is very critical.

Thank you so much for any input you can provide.

Regards,

Karim
MoroccoIT@gmail.com


May 22, 2009 at 3:53 AM // reply »
7 Comments

Karim:
Issue 1. Replace 'file#intFileIndex#' with '#cffile.ServerFile#' - this is the name that CFFile saves the file as on the server.

Issue 3. After the file uploads, you could use CFFile.fileSize to check if the size is GT 1Mb.


Post Comment  |  Ask Ben

Recent Blog Comments
Jul 4, 2009 at 9:42 AM
FLV 404 Error On Windows 2003 Server
I bookmarked this page. Thanks for given this great post.... ... read »
Jul 4, 2009 at 4:00 AM
Terms Of Service / Privacy Policy Document Generator
thanks ben, I'm not a big fan of contracts so to find your no no-nesense ToS generator has helped me no end. all the best matt ... read »
Justice
Jul 3, 2009 at 11:10 PM
Create A Running Average Without Storing Individual Values
@Ben, I think you're going about this the wrong way. You're trying to use complicated techniques when there is a simple and beautiful technique readily available (a la Gary Funk's comment). Instead ... read »
Bob
Jul 3, 2009 at 9:19 PM
Project HUGE: Huge In A Hurry - Get Big - Phase 3 / Week 1
a good technical explanation http://crossfitphoenix.typepad.com/crossfit_phoenix_forging_/the-overhead-squat.html ... read »
Jul 3, 2009 at 9:03 PM
Create A Running Average Without Storing Individual Values
If I wanted to do this and only carry two numbers, I'd keep track of the sum and N. Then you are pretty much accurate all the time. average = (sum + new_number) / (N + 1) But all this was in a for ... read »
Roland Collins
Jul 3, 2009 at 8:58 PM
Create A Running Average Without Storing Individual Values
@Martin - not just floating point though. Depending on what langauge you're working in, decimals can cause just as many headaches if they're not precise enough. But again, for most applications, th ... read »
Isnogood
Jul 3, 2009 at 7:16 PM
Project HUGE: Huge In A Hurry - Get Big - Phase 3 / Week 1
Watch this http://www.nsca-lift.org/videos/default.shtml ... read »
Aaron
Jul 3, 2009 at 7:13 PM
Project HUGE: Get Big, Phase One (Chat Waterbury - Huge In A Hurry)
I've just finished the 3rd week of phase 3, and have to agree that the overhead squats are hard. I think this is most due to the wide grip on which places more pressure on your upper back. Only this ... read »