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 »
11,238 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 »
11,238 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 »
11,238 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
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 21, 2013 at 7:46 PM
Using Plupload For Drag & Drop File Uploads In ColdFusion
No luck. At least I have uncovered the cause, URLScan 3.1. Here is what I see in the IIS log when a file is over 30mb. 2013-05-21 23:29:05 10.105.45.128 GET /plupload/assets/jquery/jquery-1.8. ... read »
May 21, 2013 at 6:12 PM
Using Plupload For Drag & Drop File Uploads In ColdFusion
Ben, I did not see you after Pete Freitag's Lockdown session at cfObjective but he said that IIS sets file size limits at 30MB by default which just happened to be the threshold for file size when ... read »
May 21, 2013 at 11:51 AM
Ask Ben: Parsing Very Large XML Documents In ColdFusion
Looking at my first ever XML document that I have to parse and put into MS SQL 2000 with CF8. I get it to list the desired Field name, many times over, and have a long list of this field name displa ... read »
May 21, 2013 at 9:25 AM
Turning Off and On Identity Column in SQL Server
you are awesome..i am lucky to get this blog between such a garbage one....Thanks, Prashant ... read »
May 20, 2013 at 4:38 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
@Dana, Your confusion is well founded, since this is a very confusing features. In fact, it ONLY works if you use array notation. Meaning, that this: arrayToList( query[ "columnName" ] ) ... read »
May 20, 2013 at 4:34 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
I was thinking chicken and the egg, I wouldn't have expected it to work in the valuelist going in I guess. Maybe I just need a beer, long day :) ... read »
May 20, 2013 at 4:29 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
@Dana, That's if you're trying to reference a specific row. In this case, we're trying to reference the entire query column as one cohesive value. So, you are correct that if you wanted to output a ... read »
May 20, 2013 at 4:24 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
I thought when you used array notation to reference queries you always had to have the row or it would throw a similar error as well? ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools