CFZip, CFZipParam, And Virtual File System (RAM) Directories

Posted December 9, 2009 at 9:22 AM by Ben Nadel

Tags: ColdFusion

NOTE: I was not running the latest version of ColdFusion 9. Using the freshest install, this now works. My bad :)

As part of my "Best of ColdFusion 9" entry, I needed a way to download IMAP-based mail attachments. To show off some of the features of ColdFusion 9, I figured I would have CFIMAP save the attachments to the virtual file system (RAM disk - ram://) and them ZIP them up and return the resultant archive to the client. I had a heck of a time getting that to work; eventually, I narrowed it down to what I think is a bug in the interaction between the CFZip tag and the RAM disk - specifically, when it comes to zipping an entire source directory off the RAM disk.

To demonstrate this (and get some feedback as to whether or not this is a bug), I went about creating a ZIP file both from the physical file system and from CF9's virtual file system. As my control case, I created the ZIP archive based on an entire physical directory first:

  • <!---
  • Create a ZIP file of the Files directory located on the
  • physical file system.
  • --->
  • <cfzip
  • action="zip"
  • source="#expandPath( './files/' )#"
  • file="#expandPath( './physical_source.zip' )#"
  • overwrite="true"
  • />
  •  
  •  
  • <!---
  • Read the images from the zip file and output them to the
  • screen (to make sure the full cycle works).
  • --->
  • <cfzip
  • name="fileList"
  • action="list"
  • file="#expandPath( './physical_source.zip' )#"
  • />
  •  
  •  
  • <h1>
  • CFZip - Physical File System
  • </h1>
  •  
  • <!--- Loop over the zipped files to extract and output. --->
  • <cfloop query="fileList">
  •  
  • <!--- Read the image binary from the zip. --->
  • <cfzip
  • variable="imageBinary"
  • action="readbinary"
  • file="#expandPath( './physical_source.zip' )#"
  • entrypath="#fileList.directory##fileList.name#"
  • />
  •  
  • <!--- Write the image to the client. --->
  • <cfimage
  • action="writetobrowser"
  • source="#imageBinary#"
  • height="200"
  • style="float: left ; margin-right: 10px ;"
  • />
  •  
  • </cfloop>

This code is pretty straightforward; I set the source of the CFZip tag to be the entire "./files/" directory. Then, to make sure everything worked as expected, I read each binary image from the zip archive and wrote it to the browser as a visual confirmation of the successful life cycle. When we run the above code, we get the following page output:

 
 
 
 
 
 
CFZip, CFZipParam, And The Virtual File System - Physical File System Control Case. 
 
 
 

As you can see, our control case works like a charm.

Next, I tried to do the same thing using a directory on the virtual file system (RAM disk) as the source directory. The code is basically the same, except for that I had to copy the files to the virtual file system before zipping them:

  • <!---
  • Delete RAM directory in case it exists (I needed this to run
  • the page more than once).
  • --->
  •  
  • <cfdirectory
  • action="delete"
  • directory="ram://cfzip-files/"
  • recurse="true"
  • />
  •  
  •  
  • <!---
  • Create the directory in our RAM disk (we will need to copy
  • the physical files to this RAM directory before we can ZIP
  • them).
  • --->
  • <cfdirectory
  • action="create"
  • directory="ram://cfzip-files/"
  • />
  •  
  • <!--- Copy the physical files to the ram disk. --->
  • <cfloop
  • index="fileName"
  • list="girl1.jpg,girl2.jpg,girl3.jpg"
  • delimiters=",">
  •  
  • <cfset fileCopy(
  • expandPath( "./files/#fileName#" ),
  • "ram://cfzip-files/#fileName#"
  • ) />
  •  
  • </cfloop>
  •  
  •  
  • <!---
  • Create a ZIP file of the cfzip-files directory located on
  • the virtual file system.
  • --->
  • <cfzip
  • action="zip"
  • source="ram://cfzip-files/"
  • file="#expandPath( './virtual_source.zip' )#"
  • overwrite="true"
  • />
  •  
  •  
  • <!---
  • Read the images from the zip file and output them to the
  • screen (to make sure the full cycle works).
  • --->
  • <cfzip
  • name="fileList"
  • action="list"
  • file="#expandPath( './virtual_source.zip' )#"
  • />
  •  
  •  
  • <h1>
  • CFZip - Virtual File System
  • </h1>
  •  
  • <!--- Loop over the zipped files to extract and output. --->
  • <cfloop query="fileList">
  •  
  • <!--- Read the image binary from the zip. --->
  • <cfzip
  • variable="imageBinary"
  • action="readbinary"
  • file="#expandPath( './virtual_source.zip' )#"
  • entrypath="#fileList.directory##fileList.name#"
  • />
  •  
  • <!--- Write the image to the client. --->
  • <cfimage
  • action="writetobrowser"
  • source="#imageBinary#"
  • height="200"
  • style="float: left ; margin-right: 10px ;"
  • />
  •  
  • </cfloop>

As you can see, if you ignore the file-copy at the top, this code is basically the same as the physical file system control case. However, when we run this code, we get the following page output:

.... nothing ....

Absolutely nothing gets output to the screen. Not even a ColdFusion error. However, when I check my Application log in the ColdFusion administrator, I see the following exception:

'' The specific sequence of files included or processed is: C:\ColdFusion9\wwwroot\testing\cfzip\vfs.cfm

That's doesn't really help me at all in terms of useful exception messages. After a bit of trial and error, I found that I could finally create the zip archive if I added some CFZipParam tags to the CFZip parent tag. I could keep the virtual directory as the source of the archive, but the CFZipParam tags had to specify the files that would get included:

  • <!---
  • Delete RAM directory in case it exists (I needed this to run
  • the page more than once).
  • --->
  •  
  • <cfdirectory
  • action="delete"
  • directory="ram://cfzip-files/"
  • recurse="true"
  • />
  •  
  •  
  • <!---
  • Create the directory in our RAM disk (we will need to copy
  • the physical files to this RAM directory before we can ZIP
  • them).
  • --->
  • <cfdirectory
  • action="create"
  • directory="ram://cfzip-files/"
  • />
  •  
  • <!--- Copy the physical files to the ram disk. --->
  • <cfloop
  • index="fileName"
  • list="girl1.jpg,girl2.jpg,girl3.jpg"
  • delimiters=",">
  •  
  • <cfset fileCopy(
  • expandPath( "./files/#fileName#" ),
  • "ram://cfzip-files/#fileName#"
  • ) />
  •  
  • </cfloop>
  •  
  •  
  • <!---
  • Create a ZIP file of the cfzip-files directory located on
  • the virtual file system.
  •  
  • NOTE: Because the CFZip tag does not seem to play well with
  • virtual directories as the source, we need to define the
  • individual files using CFZipParam tags.
  • --->
  • <cfzip
  • action="zip"
  • source="ram://cfzip-files/"
  • file="#expandPath( './virtual_source.zip' )#"
  • overwrite="true">
  •  
  • <cfzipparam source="girl1.jpg" />
  • <cfzipparam source="girl2.jpg" />
  • <cfzipparam source="girl3.jpg" />
  •  
  • </cfzip>
  •  
  •  
  • <!---
  • Read the images from the zip file and output them to the
  • screen (to make sure the full cycle works).
  • --->
  • <cfzip
  • name="fileList"
  • action="list"
  • file="#expandPath( './virtual_source.zip' )#"
  • />
  •  
  •  
  • <h1>
  • CFZip - Virtual File System (+CFZipParam)
  • </h1>
  •  
  • <!--- Loop over the zipped files to extract and output. --->
  • <cfloop query="fileList">
  •  
  • <!--- Read the image binary from the zip. --->
  • <cfzip
  • variable="imageBinary"
  • action="readbinary"
  • file="#expandPath( './virtual_source.zip' )#"
  • entrypath="#fileList.directory##fileList.name#"
  • />
  •  
  • <!--- Write the image to the client. --->
  • <cfimage
  • action="writetobrowser"
  • source="#imageBinary#"
  • height="200"
  • style="float: left ; margin-right: 10px ;"
  • />
  •  
  • </cfloop>

Notice that this is exactly the same as the previous code, except for the addition of three CFZipParam tags. This time, when we run the above code, we get the following page output:

 
 
 
 
 
 
CFZip, CFZipParam, And The Virtual File System - Virtual File System Case. 
 
 
 

Now, the CFZip tag works as expected and interacts properly with the virtual file system.

Is this a bug? It certainly feels like one to me. I have looked around the documentation and I don't see any restrictions on directory-level actions.




Reader Comments

Dec 9, 2009 at 9:46 AM // reply »
10,640 Comments

It looks like this is the same bug:

http://cfbugs.adobe.com/cfbugreport/flexbugui/cfbugtracker/main.html#bugId=79101


Dec 9, 2009 at 10:37 AM // reply »
10,640 Comments

Ooops, as it turns out, I was NOT running the latest version of ColdFusion 9.

After upgrading my install, this now works.


Dec 9, 2009 at 11:57 AM // reply »
14 Comments

Hey Ben.

Your CF9 was out of date? What version are you running, and where did you find a hotfix? I did not see any updates at all for CF9 on the adobe update support site.

Cheers dude.

-Brian


Dec 9, 2009 at 11:59 AM // reply »
10,640 Comments

@Brian,

I didn't hotfix. I just uninstalled and re-installed. I may have still been running a pre-release version.


Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
InVision App - Prototyping Made Beautiful With Prototyping Tools Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
Feb 12, 2012 at 3:37 AM
Learning ColdFusion 8: CFImage Part III - Watermarks And Transparency
Hi Ben, Just to ask currently it is placed bottom right corner, if i need to replace the same rendered image on the bottom left side or in the bottom center, how that can be calculated. bottom ce ... read »
Feb 11, 2012 at 9:29 PM
Use jQuery's SlideDown() With Fixed-Width Elements To Prevent Jumping
I can't say how glad I am that I found your post. Thank you very much. ... read »
Feb 10, 2012 at 7:21 PM
jQuery AJAX Strips Script Tags And Inserts Them After Parent-Most Elements
Update! Instead of $(eval(options.insertAfter)).after(data['insertData']); I now use: var ajaxNode = document.createElement('span'); var parent = $(eval(options.insertAfter))[0].parentNode; ... read »
Feb 10, 2012 at 6:18 PM
jQuery AJAX Strips Script Tags And Inserts Them After Parent-Most Elements
encountered this same, what I consider, jQuery bug last week. I'm building a site in which I load some content via AJAX. This content contains Linkedin share button placeholders which Linkedin API ne ... read »
Feb 10, 2012 at 11:30 AM
Cross-Origin Resource Sharing (CORS) AJAX Requests Between jQuery And Node.js
After you understand the concepts here, this is an awesome cheatsheet for enabling CORS in just about anything http://enable-cors.org/ ... read »
JM
Feb 10, 2012 at 9:10 AM
My Safari Browser SQLite Database Hello World Example
@Amy, Here is a very good tutorial on how to use JOIN: http://www.sqltutorial.org/sqljoin-innerjoin.aspx ... read »
Feb 10, 2012 at 4:42 AM
Building A Twitter-Inspired RESTful API Architecture In ColdFusion
This is great, very useful Ben. I spotted a small typo in the api.cgm listing: <cfthrow type="Unauthroized" /> Cheers Stefan ... read »
Feb 9, 2012 at 10:35 PM
CFDirectory Filtering Uses Pipe Character For Multiple Filters (Thanks Steve Withington)
I was wondering if there would be a filter you could apply so that you got everything but what you included in the filter. As in show me all docs that are not a .pdf. ... read »