Article

Practical Uses of HTTP in ColdFusion

Page: 1 2 3

Time for Some Fun

Okay, so we've gotten through the dirty work -- it's time to have a little fun. Let's pretend we're building an image server and we want to track every image that's displayed. I'm not going to go through the whole application from start to finish, but I'm going to show you how to return the images using ColdFusion, and how to track them each time they're displayed.

First, we need a database table to store each image. This will be a very simple table that will hold an image identifier, the absolute path to the image, and a descriptive image name. When building a real image server you may want to include the ID of the user who uploaded it, the date and time it was uploaded, the page the image was displayed on, and any other information you may want regarding the image. You might also track the image size so that you can measure how much disk space and bandwidth each user is utilizing. But for simplicity's sake, my measly little table looks like this:

1312_cf1

This table will store the full path to the image, a brief description of the image (so we can know what it is when looking at it through an administrative interface or in the database table itself), and a unique ID. I'm using SQL Server for this, but you can replicate the code in Access or MySQL pretty easily.

I also want to count every time that an image is accessed. Again, for simplicity's sake I'm going to track only the Image ID and the date and time it was accessed. Here's what my table looks like:

1312_cf2

Once you've created your tables, you'll want to think about your directory structure. For our simple image server, we're going to store our images in the /images/ directory on our server. We'll have a page that returns the images and it will be stored under the root directory, just for this application. We'll also have an anonymous upload page that will allow users to put images up.

We'll start off with the upload script. Here's what our form will look like:

<form name="upload" action="upload.cfm" enctype="multipart/form-data" method="post">  
  <input type="file" name="uploadFile" size="20" />  
  <input type="submit" value="Upload File" />  
</form>

Allowing anonymous uploads does open security hazards, so it's best to have some sort of authorization in place before allowing people to upload files. This is a simple example, though, so we'll work with what we've got. Take special note of the enctype="multipart/form-data"" attribute. This is essential for uploading a file. I've named this page index.cfm.

In the upload.cfm file, we first want to make sure the file name was specified. That code will look like this:

<cfif not isDefined("Form.uploadFile") or (isDefined("Form.uploadFile") and Form.uploadFile eq "")>  
 <p>  
   You must select a file to upload.  
 </p>  
 <cfabort>  
</cfif>

I always check to make sure that the field is there, and that it's not empty, to prevent people from directly accessing the URL and to keep them from submitting the form without uploading a file. Next, we'll set the file name and the destination for the file:

<cfset fileName = DateFormat(Now(), "yyyymmdd") & TimeFormat(Now(), "HHmmss")>  
<cfset destination = GetDirectoryFromPath(CGI.Path_Translated) & "images\" & fileName>

The file name will be the date and time in a single, long string. The destination will be the images directory underneath the directory that the current file is in (the CGI.Path_Translated variable gives us the absolute path to the current file). Now we can upload the file to this location:

<cffile action="upload"    
 filefield="uploadFile"    
 destination="#destination#"  
 accept="image/gif,image/jpeg"  
 nameconflict="makeunique">  
   
<cfset FullFilePath = "#CFFILE.ServerDirectory#\#CFFILE.ServerFileName#.#CFFILE.ServerFileExt#">

Note that ColdFusion generates its own temporary filename under which to store the file until you decide what to do with it. As a result, if you output the value of Form.uploadFile to the screen, the filename extension is ".tmp". But, in the cffile struct, we get the actual file name and the file extension. Make sure that you limit the types of files that can be uploaded, using the "accept" attribute as above, and specifying GIF and JPEG images. You could also specify bitmaps and PNGs as well. Now, we'll put this in the database.

<cfquery name="InsertFile" datasource="kodefusion_mssql">  
 INSERT INTO Images (  
   ImagePath,  
   ImageName  
 )  
 VALUES (  
   '#FullFilePath#',  
   'ANONYMOUS USER UPLOAD'  
 )  
</cfquery>

Here, we simply insert the full path to the image, along with a note that this was uploaded by an anonymous user. When we uploaded the file above, it didn't have an extension, so now we need to rename it to match what was in the database. Here's how we'll do that:

<cfif FileExists(destination) and not FileExists(FullFilePath)>  
 <cffile action="rename" source="#destination#" destination="#FullFilePath#">  
</cfif>

Now that the file is in the correct place, we'll retrieve the URL to put in our <img> tag, and display it to the user. You'll need to change the URL based on the way you've set up your directory structure.

<cfquery name="GetFileID" datasource="kodefusion_mssql">  
 SELECT ID  
 FROM Images  
 WHERE ImagePath = '#FullFilePath#'  
</cfquery>  
 
<cfoutput>  
 Here's your URL: http://127.0.0.1/imagetracking/returnimage.cfm?ImageID=#GetFileID.ID#  
</cfoutput>

The next step is to create the returnimage.cfm file. This is a pretty big chunk of code, so take a look first, then we'll talk about it:

<cfif not isDefined("URL.ImageID") or (isDefined("URL.ImageID") and not isNumeric(URL.ImageID))>  
 <!--- no image specified. you could return a default graphic here if you want. --->  
<cfelse>  
 <cfquery name="GetImagePath" datasource="kodefusion_mssql">  
   SELECT ImagePath  
   FROM Images  
   WHERE ID = #URL.ImageID#  
 </cfquery>  
 <cfif GetImagePath.RecordCount neq 0>  
   <cfquery name="InsertTracking" datasource="kodefusion_mssql">  
     INSERT INTO ImageTracking (  
       ImageID,  
       InsertDate  
     )  
     VALUES (  
       #URL.ImageID#,  
       GetDate()  
     )  
   </cfquery>  
   <cfset fileExt = ListLast(GetFileFromPath(GetImagePath.ImagePath), ".")>  
   <cfif fileExt eq "jpg" or fileExt eq "jpeg">  
     <cfset contentType = "image/jpeg">  
   <cfelse>  
     <cfset contentType = "image/gif">  
   </cfif>  
   <cfheader name="Content-Disposition" value="inline; filename=#GetFileFromPath(GetImagePath.ImagePath)#">  
   <cfcontent type="#contentType#" deletefile="no" file="#GetImagePath.ImagePath#">  
 <cfelse>  
   <!--- no image. return default graphic. --->  
 </cfif>  
</cfif>

The first thing we do is check to make sure there's an image ID available. If not, we could return a default "Graphic Not Available" type of graphic. If we don't, an infamous red X will appear there.

Assuming an ID is provided, we use it to select the ImagePath field from our Images table. We check to make sure the query returned a result, and we put a row in the ImageTracking table to indicate that the image was accessed. We then figure out if this was a JPEG or a GIF image, and set the content type variable accordingly. You could create a separate "FileExtension" field in the Images table and eliminate this bit of work by storing the file extension or even the content type in there.

Once we have the content type figured out, we send our cfheader, then push our image along using cfcontent. Make sure that the deletefile attribute is set to "no", so that the file isn't removed after it's used. If there are no images matching that ID in the database, we could return our "Image Not Available" graphic, or just let it display a red X.

Be sure to specify in the cfheader value attribute that this is inline data. This means that it will be displayed in the Web page, not downloaded as an attachment. (Hint: If you want to track downloads of a file, you could use this method and set the value attribute to "attachment".) Also, note that the value should be the file name only, not the full path.

Conclusion

There you have it: a very basic start on an image server. There are many, many things that you can do with the tags and techniques we've discussed in this article. Your assignment now is to take the above application and build it into something more comprehensive. Add a way for users to name images, a report to show how often the images are accessed, and the ability to store more data about each image upload and each time the file is accessed. There are plenty of things you can do!

In this article, we've covered a lot of ground (and I'm pretty much exhausted, believe me!). We've discussed using the cfhttp tag to retrieve an RSS feed, using the cfhttpparam tag to send form, URL, and cookie variables, as well as files, to a remote Website, and how to return file types other than text and HTML, using ColdFusion. The more applications you develop, the more ways you will find to apply these tags in your code. Until next time, have fun in the wide world of ColdFusion.

If you liked this article, share the love:
Print-Friendly Version Suggest an Article

Sponsored Links

Rate This Article

  • 1
    Poor
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
    Great

Comment on This Article

Have something to say?

Post A Comment

You need to be a member of the SitePoint Forums to comment on this post. Sign Up

Already a member? Post using your SitePoint Forums account: