Ask Ben: Creating An Archive Folder / File List

Posted January 8, 2007 at 8:55 AM by Ben Nadel

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:

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

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

Thanks Ben!


Jan 8, 2007 at 10:11 AM // reply »
11,246 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 »
11,246 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 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 23, 2013 at 9:52 PM
Preventing Links In Standalone iPhone Applications From Opening In Mobile Safari
@Muhmmadibn Did you figure out a solution to launching PDFs? I am running into the same issues myself. There is no way to close the PDF or go back once you launch it. Thanks in advance! ... read »
May 23, 2013 at 6:06 PM
The Girl Who Broke My Heart, And Made Me A Better Person
Good day,ladies and gentle men, my name is Dr AMADI the great spell caster in Africa, i have help so many people for different kind of problems,who say there is no solution to problems on earth, that ... read »
May 23, 2013 at 4:26 PM
ColdFusion QueryAppend( qOne, qTwo )
@Heather, Glad people are still getting value out of this! ... read »
May 23, 2013 at 3:49 PM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@WebManWalking, I meant the code at the bottom (not the video). I did try to experiment with an intermediary variable, like: value = users.id[ i ]; arrayContains( userIDs, value ); ... but t ... read »
May 23, 2013 at 11:06 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Ben, Are you talking about As Number: YES As String: YES As Java: YES? If so, that's with 3 different ways of referencing the constant 1, not users.id[1]. Query object references(*) are what seem ... read »
May 23, 2013 at 9:55 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Dan, According to the CF Admin, I'm running Java "1.6.0_45". As far as the DB column, in the database it's an INT. I'll see if I can dig into what CF sees it as. @WebManWalking, But h ... read »
May 23, 2013 at 9:49 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Ben, I think the problem is that we're used to loose typing in ColdFusion, like JavaScript. If a value is a number but it's needed in an expression to be a string, noooo problem. I've encountered ... read »
May 23, 2013 at 9:47 AM
ColdFusion QueryAppend( qOne, qTwo )
You rock! Thank you, thank you, thank you!!! ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools