ColdFusion Muse

INI and XML File Configuration Options

Mark Kruger December 14, 2005 11:44 AM Coldfusion Tips and Techniques Comments (10)

Getting an web application deployed can be very challenging. The word that comes to mind is "messy". You can do some things to tidy it up like using INNO, or use the deployment options provided by CF or J2EE, but the truth is that someone is going to have to "fiddle" with the configuration options until they are right. The most common settings to change are data source names and file paths. We have worked with many applications where we were required to open the Application.cfm file and directly change the values of application variables. This is not a good idea and it limits your deployment options. You may want to compile your pages and not have them open to prying eyes. Or you may be nervous about folks mucking about in the Application.cfm or Application.cfc (as well you should be). There are a couple of alternatives.

NOTE: I amended this post on 12/15 due to an error pointed out by Ray and Sean Corfield (see the comments).

XML File

This is easy and straight-forward. You simply include a "config.xml" file of "settings.xml" for you a "clickHereandeditthis.xml" file in the same directory as your Application.cfc or Application.cfm that contains the settings you want.

<settings>
   <dsn>myDatasource</dsn>
   <siteRoot>MySiteRoot</siteRoot>
</settings>
Then, in your "onApplicationStart()" section of your Application.cfc file you simply open the file and use xmlParse( ) to set up the Application vars.

While I like this approach and I do not object to it, it has the disadvantage of being slightly (only slightly) less user friendly than an INI file. I like INI files because admin and operations folks are often tasked with installing your application. They are used to dealing with INI files. From a Human perspective an INI file is a little bit more readable than an XML file, and if you have only 1 level of variables to work with it certainly makes sense.

INI Anatomy

An INI file has sections that contain parameters. A section is defined by the square brackets, and a parameter is a name value pair - just like you've come to expect.

[datasource]
dsn=mydsn


[paths]
siteRoot=c:\inetpub\wwwdocs
imgdir=e:\myimages
docdir=e:\mydocs
This sample has 2 sections, datasource and paths. You would get at these parameters from the file using the underappreciated function "getProfileString( )". This function takes a file name (with a full path), a section value and a parameter value, so the following...
<cfset Application.result = getProfileString(expandPath("./config.ini"),"datasource","dsn")>
...would set Application.result to the value "mydsn" in the above example.

Some "Gotcha's"

One of the biggest gotchas has nothing to do with INI files. How do I change application variables (like dsn or path) without renaming the application or restarting the server. In the "Application.cfm" file we would simply include something in the logic check like "cfif Isdefined('url.refresh')". So naturally you might think the same approach would work here - only you would simply need to run "onApplicationStart()" - easy right? Actually, you might make the mistake I did and include the refresh code at the top of the Application.cfc file - as if it was going to "run" with each request. That's not the case is it. The Application.cfc file is not run with each request - at least not in the way that Application.cfm was run with each request (as a part of the request procedure). Instead, Application.cfc is instantiated at the start of the application and certain events within the application.cfc component are fired at certain times. To get my "refresh" code to work I needed to place it inside the "onRequestStart()" function where the check would be made with each request. Something Like....

<cfscript>
   if(IsDefined('url.refresh'))
      onApplicationStart();
   </cfscript>
That way I could refresh the values in the application scope easily.

Another "gotcha" is formatting. An INI file doesn't require quotes or semi-colons etc. It's just a straight string value - what you see is what you get.

Innovative Uses

One of the most creative uses of INI is this very blog software, written by Ray Camden. Ray does something nifty that allows multiple blogs. There is an "blogname" variable in the Application.cfm file that you must set (I know, I know it goes against the advice above - but hang with me). His "blog.cfc" component opens the "blog.ini" file and looks for a "section" titled the same as the blogname. So, if I name my blog "cfmuse" I would look for a section like this inside of blog.ini.

[cfmuse]
dsn=cfmuse_blog
owneremail=******
blogURL=http://mkruger.cfwebtools.com/index.cfm
rdfURL=http://mkruger.cfwebtools.com/rss.cfm
unsubscribeURL=http://mkruger.cfwebtools.com/unsubscribe.cfm
blogTitle=Coldfusion Muse
blogDescription=Mark Kruger's Daily Musings on Coldfusion
blogItemURLPrefix=mode=entry&entry=
blogDBType=MSSQL
locale=en_US
users=************
commentsFrom=
mailserver=
mailusername=
mailpassword=
Why the rigmarole? Because blog CFC can now use a single set of components to support multiple blogs based on the name of the application. Nifty eh? Nice job Ray.

  • Share:

10 Comments


Leave this field empty

Write a comment

If you subscribe, any new posts to this thread will be sent to your email address.

  • Ryan Guill's Gravatar
    Posted By
    Ryan Guill | 12/14/05 10:07 AM
    xml's user friendiness aside, xml config files have a good advantage over ini's because they are so easy to work with (xmlparse() now will even do the cffile read for you in cf 7) to read in and to edit. In several of my apps, I have an xml config file and provide a user interface to be able to change the settings (guarded by a password of course). So its ease of use in cf really outweighs its sometimes hard to read syntax, especially when you can create an interface for it. IMO anway.
  • mkruger's Gravatar
    Posted By
    mkruger | 12/14/05 10:12 AM
    Ryan - yes, if you are providing an interface for it I quite agree.
  • Raymond Camden's Gravatar
    Posted By
    Raymond Camden | 12/14/05 10:13 AM
    Thanks for the kind words. :) I actually wrote a series on xml/ini config files a few months back. One more cool thing about the blog.ini (at least I think it is cool), all options in sections outside of default allow for

    foo=@default

    This will set foo equals to foo's value in the default section.
  • Mkruger's Gravatar
    Posted By
    Mkruger | 12/14/05 10:27 AM
    Ray - I didn't see that... very cool.
  • Critter's Gravatar
    Posted By
    Critter | 12/14/05 10:44 AM
    doesn't lighthouse pro call the application start from within the application.cfc based on the url parameter reinit ?
  • Raymond Camden's Gravatar
    Posted By
    Raymond Camden | 12/14/05 10:49 AM
    Critter. Yes. Technically this is not thread-safe, but its ok for LHP. (I'm not doing any operations that require thread safety.)
  • dave ross's Gravatar
    Posted By
    dave ross | 12/14/05 11:08 AM
    .properties files are the best for storing this kind of data. While very similar to .ini files, I'd rather use something that's more of a standard, and has support within the runtime environment (ResourceBundles, ClasspathResource, etc etc).

    If people are hazy on this stuff I'd be willing to blog it (Chris Scott wrote about ClasspathResource a while ago).
  • shane montgomery's Gravatar
    Posted By
    shane montgomery | 12/14/05 11:40 AM
    Nice entry Mark. I saw Ray speak at Max05, all of you guys are damn innovative. Good Stuff
  • Sean Corfield's Gravatar
    Posted By
    Sean Corfield | 12/14/05 5:39 PM
    "The function "onApplicationStart()" does not seem to be capable of being invoked from within the Application.cfc file."

    That simply isn't true!

    The 'standard' way to do this is inside onRequestStart() using the code you showed - and Ray confirms this works (it's in LHP).
  • mkruger's Gravatar
    Posted By
    mkruger | 12/15/05 7:26 AM
    Sean,

    Hmmm.... I suppose the problem is that I'm not including it in "onRequestStart()". I tried it just under the "this" declarations at the top. That would not work would it - because the cfc isn't "run" like a requested template... dang. Thank you Sean - I will amend the post.