Ask Ben: Creating An Archive Folder / File List

Posted January 8, 2007 at 8:55 AM

Tags: ColdFusion, Ask Ben

I have a simple little app im trying to develop that will display end of the month reports. These reports are in excel format.

I need it to do two things..

1. allow upload of new excel files
2. create new archive folders for the previous month.

I can easily do 1 & 2, but my problem is getting the paths right.

the folder structure has a root folder.. say.. reports. inside that folder are the current excel (xls) files AND the archived folders (april06,may06 etc.). Inside each archived folder there are the archived .xls files for that month.

the way i started creating this little app was to add an index.cfm file to every directory, so I can link directly to the folder and it will pick up index.cfm in that folder which pretty much does the same thing like the root index.cfm. Not at all ideal, but it was working....almost..

In each index.cfm file I display all the xls files for that current directory, as well as it lists all the folders in the root directory with an href to that folder. For the inside folders, the folder link path were incorrect. they now display as http://localhost/reports/april06/april06/

so.... How can i dynamically build the folder structure so I dont have to worry about this? Also what other suggestions do you have for this? It would be nice to not have to create an index.cfm file in every folder...

Any help would be appreciated.

For this, I would just put all the navigation in the root folder. The page should start by listing out all the archive folders. Each folder link should submit back to itself and pass in the desired folder name. The page should then list out the archive documents for that folder. This way, there is only one page required to navigate the root folder AND all the sub folders. Furthermore, this does not require you to do anything when you add new archive folders.

Take a look at the page below and let me know if you have any questions:

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

  • <!--- Kill extra output. --->
  • <cfsilent>
  •  
  • <!---
  • This is the name of the archive folder for which we
  • want to list out the archive documents.
  • --->
  • <cfparam
  • name="URL.folder"
  • type="string"
  • default=""
  • />
  •  
  • <!--- Decode the folder value. --->
  • <cfset URL.folder = UrlDecode( URL.folder ) />
  •  
  • <!---
  • For security reasons, we want to get rid of any suspect
  • values in the folder variable. These include "../"
  • which would go to a parent directory or "/" which will
  • go to the root perhaps.
  • --->
  • <cfset URL.folder = URL.folder.ReplaceAll(
  • "(\.\.[\\/])+", ""
  • ).ReplaceAll(
  • "[\\/]+", ""
  • ) />
  •  
  • <!---
  • Set the directory path of the root archive
  • directory (this one).
  • --->
  • <cfset strRoot = ExpandPath( "./" ) />
  •  
  •  
  • <!---
  • Check to see if we have an archive folder selected.
  • If we do, then we want to query that one. If not,
  • then we want to get the list of all the archive folders.
  • Furthermore, if we have an archive folder, just
  • check to make sure the folder exists.
  • --->
  • <cfif (
  • Len( URL.folder ) AND
  • DirectoryExists( strRoot & "\" & URL.folder )
  • )>
  •  
  • <!--- Set the query path to be the archive folder. --->
  • <cfset strQueryPath = (strRoot & "\" & URL.folder) />
  •  
  • <cfelse>
  •  
  • <!---
  • We have no archive folder selected (or it did not
  • exist). Query the root directory.
  • --->
  • <cfset strQueryPath = strRoot />
  •  
  • <!---
  • Reset the folder variable so we don't get confused
  • later on.
  • --->
  • <cfset URL.folder = "" />
  •  
  • </cfif>
  •  
  •  
  • <!---
  • Query for the files / folders in the selected
  • directory (might be root OR an archive folder). When
  • sorting the directory list, we want to sort by name
  • DESC if we are listing the archive folders, but sort
  • by name ASC if we are listing out the documents.
  • --->
  • <cfdirectory
  • action="LIST"
  • directory="#strQueryPath#"
  • recurse="false"
  • sort="name #IIF( Len( URL.folder ), DE( 'ASC' ), DE( 'DESC' ) )#"
  • name="qDirectoryList"
  • />
  •  
  • </cfsilent>
  •  
  • <cfoutput>
  • <html>
  • <head>
  • <title>Document Archive</title>
  • </head>
  • <body>
  •  
  • <h1>
  • Document Archive
  • </h1>
  •  
  • <!---
  • Check to see if we have a folder value. If we do then
  • we are outputting the contents of that folder. If we do
  • not, then we are outputting the archive folder list.
  • --->
  • <cfif Len( URL.folder )>
  •  
  • <!--- We are listing out the archive documents. --->
  • <h2>
  • #URL.folder#
  • </h2>
  •  
  • <cfloop query="qDirectoryList">
  •  
  • <!---
  • Output the link to the file from the root
  • directory (since that is where we will are).
  • Include the name of the sub folder in the path.
  • --->
  • <p>
  • <a href="./#UrlEncodedFormat( URL.folder )#/#UrlEncodedFormat( qDirectoryList.name )#">#qDirectoryList.name#</a>
  • </p>
  •  
  • </cfloop>
  •  
  •  
  • <!--- Provide a link back to parent directory. --->
  • <p>
  • &laquo; <a href="#CGI.script_name#">Back To Archive</a>
  • </p>
  •  
  • <cfelse>
  •  
  • <!--- We are viewing the archive folder list. --->
  • <p>
  • Please select an archive folder to view documents:
  • </p>
  •  
  • <cfloop query="qDirectoryList">
  •  
  • <!---
  • When outputting, we only want to display
  • directories, not files (otherwise we might
  • output the index.cfm file.
  • --->
  • <cfif (qDirectoryList.Type EQ "Dir")>
  •  
  • <!---
  • For each link, submit the page back to
  • itself but pass in the requested folder
  • name.
  • --->
  • <p>
  • <a href="#CGI.script_name#?folder=#UrlEncodedFormat( qDirectoryList.name )#">#qDirectoryList.name#</a> &raquo;
  • </p>
  •  
  • </cfif>
  •  
  • </cfloop>
  •  
  • </cfif>
  •  
  • </body>
  • </html>
  • </cfoutput>

Download Code Snippet ZIP File

Post Comment  |  Ask Ben  |  Permalink  |  Print Page





Reader Comments

Jan 8, 2007 at 9:44 AM // reply »
41 Comments

Thanks Ben!


Jan 8, 2007 at 10:11 AM // reply »
6,516 Comments

Any time dude!


Sep 27, 2007 at 6:25 PM // reply »
5 Comments

Fabulous!! I just modified and used this code on one of my sites, Ben, and it works perfectly. Man, awesome stuff. Thanks!


Dan
Oct 22, 2008 at 12:09 PM // reply »
1 Comments

I could be wrong about this, but as far as I can tell, your code will not prevent ".." from working. Additionally, it wouldn't prevent things like %system% (can't recall if that's the right env var) from working. This would allow for one upward directory traversal, or traversal to paths predefined in the environment variables. Not too big a deal, especially considering that the intended usage of this would be to display .xls files only, but it's good to know anyway, I think.


Oct 22, 2008 at 8:04 PM // reply »
6,516 Comments

@Dan,

The script actually protects against the use of "..". It's a bit hard to read because it is in a regular expression which has to escape the periods:

\.\.

However, I do not know anything about things like %system%. I am not sure if that applies to ColdFusion paths! I will have to look into that. Thanks for the concern.


Post Comment  |  Ask Ben

Recent Blog Comments
Nov 20, 2009 at 11:32 PM
Five Months Without Hungarian Notation And I'm Loving It
I've used headless camel case for years for not only ColdFusion variables, but also SQL tables and fields... pretty much everything involving code. I also subscribe to the "don't abbreviate and clea ... read »
Nov 20, 2009 at 11:00 PM
Five Months Without Hungarian Notation And I'm Loving It
@Marcel, Yeah, I always err on the side of longer but more readable variable names. As for the camel casing of CF methods and the headless camel casing of custom items, I get around this by always ... read »
Nov 20, 2009 at 10:56 PM
Five Months Without Hungarian Notation And I'm Loving It
I use the following and love it: my.namespace.MyComponents.functionMethodsOrUDF() CONSTANT_VALUES_OR_PROPERTIES One thing I always try is to CamelCaseBuiltInColdFusionFunctions() so others can tell ... read »
Nov 20, 2009 at 5:38 PM
Learning ColdFusion 8: CFImage Part I - Reading And Writing Images
Hi Ben, Great article. I've been looking around to see if ColdFusion image engine can programatically create the following "wrap around" effect: http://www.creativepro.com/article/photoshop-s-she ... read »
Nov 20, 2009 at 5:35 PM
Maintaining ColdFusion Sessions Across SMS Text Message Requests Without Cookies
@Dave: I talked to Gert he suggested: <cfhttp method="get" url="http://{some cf website}" result="stuff" addtoken="yes" /> Note the addition of cfhttp attribute addtoken. That should persist y ... read »
Nov 20, 2009 at 5:23 PM
Maintaining ColdFusion Sessions Across SMS Text Message Requests Without Cookies
@Todd, Ahh, gotcha, yeah that makes sense. ... read »
Nov 20, 2009 at 5:17 PM
Maintaining ColdFusion Sessions Across SMS Text Message Requests Without Cookies
Ben, sorry if I didn't make this clear. You can make it work like that if you want, just put <cfset session.foo = 1> (and <cfset application.foo = 1>) in your OnRequestStart() and it reve ... read »