Relative File Paths Work In A ColdFusion File System

Posted July 16, 2012 at 9:37 AM by Ben Nadel

Tags: ColdFusion

For years, I've been using regular expressions as a means to traverse file paths in my ColdFusion applications. By chopping-off the last directory "pattern" in a file path, I was able to move up into the parent directory:

  • <!--- Get the current directory. --->
  • <cfset currentDirectory = getDirectoryFromPath( getCurrentTemplatePath() ) />
  •  
  • <!---
  • Get parent directory by chopping off the last directory of the
  • current directory path: /(xxxxxxxx/)
  • --->
  • <cfset parentDirectory = reReplace(
  • currentDirectory,
  • "[^/]+/$",
  • "",
  • "one"
  • ) />
  •  
  • <!--- If the Hello file exists, execute it. --->
  • <cfif fileExists( parentDirectory & "relative_paths/subfolder/hello.cfm" )>
  •  
  • <cfinclude template="./subfolder/hello.cfm" />
  •  
  • </cfif>

Here, you can see that I am using the reReplace() method to move up the currentDirectory path in order to obtain the parentDirectory path. Then, I am using this parentDirectory path in a fileExists() call. This code successfully runs and outputs the following message:

Hello from the SubFolder!

This works. But, it lacks clarity and readability. While the intent may be evident from my variable name choices, the implementation may remain a mystery to anyone who's not comfortable with regular expressions.

In the last few months, I've abandoned this convoluted approach to path traversal and replaced it with relative-path constructs in my ColdFusion path logic:

  • <!--- Get the current directory. --->
  • <cfset currentDirectory = getDirectoryFromPath( getCurrentTemplatePath() ) />
  •  
  • <!--- Get the parent directory using relative pathing. --->
  • <cfset parentDirectory = (currentDirectory & "../") />
  •  
  • <!--- If the Hello file exists, execute it. --->
  • <cfif fileExists( parentDirectory & "relative_paths/subfolder/hello.cfm" )>
  •  
  • <cfinclude template="./subfolder/hello.cfm" />
  •  
  • </cfif>

Here, rather than chopping off the last directory, I am simply adding the relative-path construct, "../", to my currentDirectory value. And, when I run this code, I get the following output:

Hello from the SubFolder!

Not only does this work, it's significantly more intuitive than the regular-expression-based approach.

I used to dislike the idea of having "../" constructs in my ColdFusion file paths. But, this fear was emotional. For some reason, it felt dirty; like there was "clean up" left to be done on the file path and I wasn't doing it. But, I have since overcome this emotional limitation and started using the easier, more intuitive, more maintainable notation in my ColdFusion file paths.

A Note On Security

Using relative-file-path constructs can be dangerous if you're letting your uses define or manipulate paths. This is why (I believe) "../" constructs are disabled, by default, in ASP Classic applications. If you are using "../" file paths as part of your internal configuration, however, there is absolutely no security exposure.




Reader Comments

Jul 16, 2012 at 12:42 PM // reply »
3 Comments

I've always found ColdFusion's lists (delimited with "/") to be an elegant way of traversing directories. (Though it doesn't fair as well with this example.)

  • <cfset parentDirectory = ListDeleteAt(currentDirectory, ListLen(currentDirectory, "/"), "/") />

That said, I might just like it because I have a few list utility routines to help me out here, and could write this as

  • <cfset parentDirectory = ListDrop(currentDirectory, 1, "/") />

(where ListDrop drops the last n elements of a list, n being it's second argument).

But at that point I might as well write my own set of directory traversal functions as well...


Jul 16, 2012 at 2:01 PM // reply »
5 Comments

After I spent too much time with traversing file paths, supporting win (\) + lin (/) servers, I realized that actually I didn't want to traverse paths.

What I wanted is to hardcode filepaths in a platform independend way, so I came up with the idea of project relative paths. My project root is where the Eclipse .project file resides.

Instead of traversing the code looks like this:

  • if( fileExists( Path.getProject("/cache/myFile.ini") ) ){...}

As I code all that paths in a project fully qualified way, it is possible to use search & replace on refactorings.

The Path.cfc starts with:

  • relativeProjectPathOfThisFileRegEx = "project[/\\]path[/\\]of[/\\]this[/\\]Path.cfc";
  • project = reReplace(getCurrentTemplatePath(), relativeProjectPathOfThisFileRegEx, "");

and all path methods are build on top of that.

This is from the comments: The ColdFusion function expandPath() is usefull, but not reliable with virtual mappings, defined in IIS or Apache and also not reliable in environments with path rewriting (my experience, not documented). The functions getCurrentTemplatePath() and getBaseTemplatePath() are usefull for file operations relative to the current location or the webroot. Still, this class provides the easiest way, to cope with any system paths inside the project root.


Jul 16, 2012 at 2:08 PM // reply »
11,314 Comments

@Thom,

I've also played with the list-based usage as well. The one thing that always bothered me was having to determine the length of the list - the listDrop() method would be nice for that (or rather, for not caring what the length is).

@Walter,

I think I used to use a similar approach where I used a Config.cfc instead of a Path.cfc; but then, inside the Path.cfc, I usually had some branch-logic for which server I was on (ex. Live vs Dev).

Now, I tend to just put all my path calculations inside my onApplicationStart() event handler. Luckily, I believe the path-support has gotten much stronger in the last few releases of ColdFusion (in terms of cross-OS path separators).


Jul 16, 2012 at 2:39 PM // reply »
5 Comments

Just curious, do you set per application mappings or customtag paths in the Application.cfc, somehow based on that path calculations in the onApplicationStart? Sorry, a little off topic.


Jul 31, 2012 at 9:34 AM // reply »
11,314 Comments

@Walter,

I tend to set up per-app mappings and tag paths (though less tag paths these days) in my Application.cfc pseudo constructor. Typically, I'll set up some sort of "root" directory property and then build off that:

  • <cfcomponent>
  •  
  • <cfset this.rootDir = getDirectoryFromPath( getCurrentTemplatePath() ) />
  •  
  • <cfset this.mappings[ "/com" ] = (this.rootDir & "com/") />
  •  
  • </cfcomponent>

... like that.

You can't set up per-app mappings in the onApplicationStart() as this is already *too late* for those mappings to take effect. They have to be calculated and defined in the pseudo-constructor.


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
Jun 20, 2013 at 3:15 AM
A Billion Wicked Thoughts By Ogi Ogas And Sai Gaddam
nice post i love it thanks 4 u :) ... read »
seb
Jun 20, 2013 at 2:32 AM
Working With Inherited Collections In AngularJS
@mike, @ben, The best article about scope and prototypal prototypical inheritance in angularjs is http://stackoverflow.com/questions/14049480/what-are-the-nuances-of-scope-prototypal-prototypical- ... read »
Jun 20, 2013 at 2:17 AM
ColdFusion NumberFormat() Exploration
Nice read thanks Ben, Is there a way to mask a negative number? Long story short in the finance sector when you go 'short' on a stock you want the price to fall this is a good thing because you are ... read »
Jun 20, 2013 at 1:09 AM
The Beauty Of The jQuery Each() Method
my html code : <html> <head> <script type="text/javascript" src="jquery.js"></script> <script type="text/javascript" src="nss.js"> ... read »
Jun 19, 2013 at 11:31 PM
Directive Link, $observe, And $watch Functions Execute Inside An AngularJS Context
@Ben, bunch to learn indeed, but thats fun part : ) ... read »
Jun 19, 2013 at 10:41 PM
Referencing ColdFusion Query Columns In A Loop Using Both Array And Dot Notation
Burdock-roots Are you going fat day by day? You need to be good for your family and make some money too. So we bring for you a best product that helps you to be more energetic every day. You will b ... read »
Jun 19, 2013 at 9:52 PM
Working With Inherited Collections In AngularJS
I recognize the applicability of your solution, and how easy it makes to share data across multiple views or even "submodules" of rather simple application. But it seems to me that it creat ... read »
Jun 19, 2013 at 9:38 PM
Directive Link, $observe, And $watch Functions Execute Inside An AngularJS Context
@Alesei, Glad you like it. Even after working with AngularJS for months, I still get a bunch of unexpected, "$digest is already in progress". So hard to debug sometimes! ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools