Welcome to the very first of my ColdFusion 8 blog postings. (Well, the first since the public release.) My goal for these entries is to look at features, big and small, and show some practical examples. For my first entry, I'm going to talk about something simple - validating that a file uploaded is an image.
As you probably heard, ColdFusion 8 has about 900 or so image functions. Ok, it isn't quite that much, but there are quite a few of them. (By the way, I'm speaking on image features at CFUNITED.) Probably the most common thing you will need to do is simple validation on a file upload. What do I mean by that?
Imagine a preferences form. It asks you things like your name, email address, and other items. It also lets you upload a picture of yourself. How do you validate that the file is an image? After the file is uploaded, it takes all of one call:
<cfif not isImageFile(newfile)>
The isImageFile function simply checks and see if a filename points to an image file that ColdFusion can work with. Here is a slightly larger example:
<cfif not len(trim(form.picture))>
<cfset errors = errors & "Avast Ye! Include a picture or walk the plank!<br />">
<cfelse>
<cffile action="upload" destination="#expandPath('./images')#" nameConflict="makeunique" filefield="picture" result="fileupload">
<cfif fileupload.fileWasSaved>
<cfset newfile = fileupload.serverdirectory & "/" & fileupload.serverfile>
<cfif not isImageFile(newfile)>
<cfset errors = errors & "Avast Ye! Include a VALID picture or walk the plank!<br />">
<!--- clean up --->
<cffile action="delete" file="#newfile#">
</cfif>
</cfif>
</cfif>
In this code block, I not only check and see if the user selected something to upload, I also handle the upload, check to see if it is an image, and even handle the cleanup if not. Note the special "Pirate" mode for errors. I love that.
A complete example is included below. Tomorrow I'll follow this up with a simple size check. That would be useful to for preventing users from upload 2 meg pictures or overly large wide/high pictures.
<cfset errors = "">
<cfparam name="form.name" default="">
<cfparam name="form.picture" default="">
<cfif structKeyExists(form, "save")>
<cfif not len(trim(form.name))>
<cfset errors = errors & "Avast Ye! Include a name or walk the plank!<br />">
</cfif>
<cfif not len(trim(form.picture))>
<cfset errors = errors & "Avast Ye! Include a picture or walk the plank!<br />">
<cfelse>
<cffile action="upload" destination="#expandPath('./images')#" nameConflict="makeunique" filefield="picture" result="fileupload">
<cfif fileupload.fileWasSaved>
<cfset newfile = fileupload.serverdirectory & "/" & fileupload.serverfile>
<cfif not isImageFile(newfile)>
<cfset errors = errors & "Avast Ye! Include a VALID picture or walk the plank!<br />">
<!--- clean up --->
<cffile action="delete" file="#newfile#">
</cfif>
</cfif>
</cfif>
<cfif errors is "">
<cfoutput>
<p>
Here is where we would update the database and send the user away...
</p>
</cfoutput>
<cfabort>
</cfif>
</cfif>
<cfif errors neq "">
<cfoutput>
<p>
<b>Please correct the following error(s):<br />
#errors#
</b>
</p>
</cfoutput>
</cfif>
<cfoutput>
<form action="imageuploadform.cfm" method="post" enctype="multipart/form-data">
<table>
<tr>
<td>Your Name:</td>
<td><input type="text" name="name" value="#form.name#"></td>
</tr>
<tr>
<td>Your Picture:</td>
<td><input type="file" name="picture"></td>
</tr>
<tr>
<td> </td>
<td><input type="submit" name="save" value="Save"></td>
</tr>
</table>
</form>
</cfoutput>
Archived Comments
*Sigh*
Too bad Godaddy won't upgrade to 8 until 2012.
I may be switching to hostmysite quicker than I planned just for this feature!
I have a couple of dozen sites at CrystalTech, which has been reasonably good about quick-but-not-too-quick adaptation of CF upgrades and I hope to see CF8 on the shareds there not too long after it is released...
Ray, you state:
"if a filename points to an image file that ColdFusion can work with"
What are the image file types that CF can work with, and can you pass a list/array/whatever of image types your files can work with. For example, CF may consider WMF files as images, but my web app can't use them. So not only determine if it is an image, but if it is within a user settable range of image types?
The file types that CF can wrk on is partially dependent on your system. Luckily - CF provides a function to tell you what they are: getReadableImageFormats().
Hmmm. Interesting. The imageInfo function does NOT seem to return it. You can check extensions, but that may lie.
Let me get back to you, and feel free to bug me if i forget.
The file extension not matching the file type is where I was one direction I was trying to go with my question. I know that I can set mime types in the CFFILE tag when uploading, but it is my understanding that that info comes from the user agent sending the file, so could be incorrect, much like the file extension being incorrect.
Would be good if there were a way to not only check that a file is an image (which I assume that it just doesn't check the file extension) as well as check for a specific image file type.
Thanks for looking into it Ray.
Godaddy's not going to upgrade till 2012? *boggle* Thanks for the heads-up . . . that's one hosting service off my list.
Hi Ray, is there a big performance difference between FileExists and IsImageFile? If so, what are they?
Thank you.
@Rick: Well, really, that's not a fair question. One function determines if a file exists. That's all it does. isImageFile checks the binary bits of a file to see if it is an image. So fileExists should naturally be quicker, but it isn't doing as much.
@Ray: Did you ever find out if there is a way to determine the image file format beyond checking the file extension?
Nope. I'm sure there is a way.
All I have to say is Thank you.
If only the web was full of helpful people like you. This post has really! helped me.