Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
I am the chief technical officer at InVision App, Inc - a prototyping and collaboration platform for designers, built by designers. I also rock out in JavaScript and ColdFusion 24x7.
Meanwhile on Twitter
Loading latest tweet...
Ben Nadel at CFUNITED 2010 (Landsdown, VA) with: Josh Highland

Ask Ben: Creating An Archive Folder / File List

By Ben Nadel on

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:

  • <!--- 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>



Reader Comments

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

Reply to this Comment

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.

Reply to this Comment

@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.

Reply to this Comment

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
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.