Server Time:
Sunday May 11 2008 08:10 PM  
Your Time:
  
HostMySite.Com is sponsoring this tutorial, please visit their site today!
This tutorial is sponsored by HostMySite.Com - ColdFusion Hosting

Remote File Management
by: Charlie Griefer (CJ)
Email this tutorial to a friend Display Printer Friendly Format
[Download in PDF Format] [Download in FlashPaper Format]

Managing Remote Files with ColdFusion

At the request of a fellow EasyCFM Forum user, we’re going to discuss how to use ColdFusion to manage remote files on the server. While the original request was only for .txt files specifically, we’re going to look at handling .txt, .cfm, .cfml, .htm, and .html.

This can actually come in handy if you need to do a quick edit on a page on your Web site, but have no access to FTP clients...only a Web browser.

In order for the code shown in this tutorial to work, all files to be edited must reside on the Web server, in the web root directory, in a directory called ‘myfiles’. The tutorial will assume the following path:

c:\inetpub\wwwroot\myfiles\

This application will consist of 5 templates:

remote_file_list.cfm – displays a list of all available files
remote_file_add.cfm – allows the user to create a new file
remote_file_edit.cfm – allows the user to edit an existing file
remote_file_save.cfm – saves the file to the server, either after an add or an edit
remote_file_delete.cfm – deletes a file

NOTE: usually I like to include a link to a working sample of code with my tutorials. However, due to the nature of this tutorial (the ability to write files to the server), I’ve decided that an ounce of prevention is worth a pound of cure...and chickened out. I do, however, include all 5 files in a zip located at http://charlie.griefer.com/mrf.zip.

On to the tutorial...

remote_file_list.cfm:
********************************************
<cfscript>
    if (NOT structKeyExists(form, 'fileExt')) form.fileExt = "*";
</cfscript>

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
>

<html xmlns=
"http://www.w3.org/1999/xhtml">
<head>
<title>
File List</title>
<meta http-equiv=
"Content-Type" content="text/html;charset=utf-8" />

<style type="text/css">
    body, td { font-family:verdana; font-size:11px; }
    a { color:#0000ff; text-decoration:none; }
    a:hover { color:#ff0000; text-decoration:underline; }
</style>
</head>

<body>

<!--- get the list of text files. this assumes they will all be in a directory called 'textfiles' under the web root --->
<cfdirectory action="list"
   
                  directory="c:\Inetpub\wwwroot\myfiles"
                  name=
"fileList"
                  filter=
"#form.fileExt#">

<table style="width:500px;" cellpadding="1" cellspacing="1">
    <form action="remote_file_list.cfm" method="post">
    <tr>
        <td style=
"vertical-align:bottom; padding-bottom:2px;">Select a File to Edit:</td>
        <td style=
"vertical-align:bottom; text-align:right;">File Type:
        <select name="fileExt" style="font-family:verdana; font-size:11px;" onchange="this.form.submit();">
            <option value="*"<cfif form.fileExt IS "*"> selected</cfif>>all files</option>
            <option value=
"*.cfm"<cfif form.fileExt IS "*.cfm"> selected</cfif>>cfm</option>
            <option value=
"*.htm"<cfif form.fileExt IS "*.htm"> selected</cfif>>html</option>
            <option value=
"*.txt"<cfif form.fileExt IS "*.txt"> selected</cfif>>txt</option>
        </select>

        </td>
    </tr>

    </form>
</table>

<table style="width:500px; border:1px #000000 solid;" cellpadding="1" cellspacing="1">
    <tr style=
"background-color:#cccccc;">
        <td style=
"font-weight:bold;">File Name&nbsp;&nbsp;</td>
        <td style=
"font-weight:bold; width:80px; text-align:right;">File Size&nbsp;&nbsp;</td>
        <td style=
"font-weight:bold; width:150px;">Last Modified&nbsp;&nbsp;</td>
        <td style=
"font-weight:bold; width:60px;">&nbsp;&nbsp;</td>
    </tr>

    <cfoutput query="fileList">
    <cfif left(fileList.name, 1) IS NOT ".">
    <!--- this condition does NOT need to be included in CF MX!! --->
    <tr style="background-color:<cfif currentRow MOD 2>##ffffff<cfelse>##ececec</cfif>;">
        <td><a href=
"remote_file_edit.cfm?file=#URLEncodedFormat(name)#">#name#</a>&nbsp;&nbsp;</td>
        <td style=
"text-align:right;">#int(evaluate(size/1024))# KB&nbsp;&nbsp;</td>
        <td>
#dateFormat(dateLastModified, 'mm/dd/yyyy')# #timeFormat(dateLastModified, 'h:mm tt')#&nbsp;&nbsp;</td>
        <td style=
"text-align:center;"><a href="remote_file_delete.cfm?file=#URLEncodedFormat(name)#" onclick="return confirm('Are You Sure You Wish to Delete This File?');">delete</a></td>
    </tr>

    </cfif>
    </cfoutput>

</table>
<br />
<a href="remote_file_add.cfm">Create a new file</a>

</body>
</html>

****************************************

Here we use a <cfdirectory> with a LIST action attribute. By default, there is no filter applied (all files are returned). In include a <select> form input allowing the user to determine the type of file he/she wishes to see (options being *.txt, *.html, and *.cfml). This is reflected in the FILTER attribute of the <cfdirectory> tag.
Looking at the docs for <cfdirectory>, you can see that it actually returns a named recordset (very similar to a cfquery), with specific ‘columns’. I display a table which shows the values of those columns. Name, file size, and date last modified are displayed within the <cfoutput query=”fileList”></cfoutput> tags.

The Name column contains a link to remote_file_edit.cfm, and passed the file name in the URL (wrapped in a URLEncodedFormat() function to handle any non-URL-friendly characters). To make this more of a ‘full’ application, I also include a link with each record to remote_file_delete.cfm, also passing the name of the file in the URL. The links to remote_file_delete.cfm contain a JavaScript confirm() method, prompting the user as to whether or not he/she wishes to proceed with the delete. This is something I try to do standard on links that will delete any files or data.

Finally, a link exists underneath the existing files, allowing the user to create a new file.


remote_file_edit.cfm:
******************************************
<cfif NOT structKeyExists(URL, 'file')>
    <cflocation url=
"remote_file_list.cfm" />
    <cfabort />
</cfif>

<cfscript>

    variables.validFile = 1;

    if (NOT reFindNoCase('.txt$|.htm$|.html$|.cfm$|.cfml$', URL.file)) {
        variables.validFile = 0;
    }
</cfscript>

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
>

<html xmlns=
"http://www.w3.org/1999/xhtml">
<head>
<title>
Editing <cfoutput>#URL.file#</cfoutput></title>
<meta http-equiv=
"Content-Type" content="text/html;charset=utf-8" />

<script language="JavaScript" type="text/javascript">
    function sTrim(sVariable) {
        return sVariable.replace(/^\s+|\s+$/g,"");
    }

    function validateFields(form) {

        if (sTrim(form.fileContent.value) == "") {
            alert('The file must have content!');
            form.fileContent.focus();
            return false;
        }
    return true;
    }
</script>

<style type="text/css">
   
body, td { font-family:verdana; font-size:11px; }
    a { color:#0000ff; text-decoration:none; }
    a:hover { color:#ff0000; text-decoration:underline; }
</style>
</head>

<body>

<cfif NOT variables.validFile>
    <cfoutput>

        <span style="font-weight:bold;">#URL.file#</span> is not an acceptable file type to edit.
        <br /><br />
        <a href="remote_file_list.cfm">click here to continue</a>
    </cfoutput>

<cfelse>

    <cffile action="read"
              file=
"c:\inetpub\wwwroot\myfiles\#URL.file#"
              variable=
"thisFile">

    <cfoutput>
    <form action="remote_file_save.cfm" method="post" onsubmit="return validateFields(this);">
    <input type=
"hidden" name="fileName" value="#URL.file#" />
    <input type=
"hidden" name="action_type" value="edit" />

    <table border="0" style="width:600px;">
        <tr>
            <td style=
"font-weight:bold; width:120px;">Currently Editing:&nbsp;</td>
            <td style=
"width:480px;">#URL.file#</td>
        </tr>
        <tr>
            <td colspan=
"2"><textarea name="fileContent" style="font-family:verdana; font-size:11px; height:250px; width:600px;">#thisFile#</textarea>
            </td>
        </tr>
        <tr>
            <td colspan=
"2" style="text-align:right;">
<input type="button" value="cancel" style="font-family:verdana; font-size:11px;" onclick="location.href='remote_file_list.cfm';" />
<input type=
"submit" value="edit file >" style="font-family:verdana; font-size:11px;" />
            </td>
        </tr>
    </table>

    </form>
    </cfoutput>

</cfif>

</body>
</html>

*********************************************

Before doing anything on the remote_file_edit.cfm page, we need to make sure a URL variable named ‘file’ was passed. If not, we send the user back to the main page. We are then going to use <cffile> with an ACTION=”read” attribute. However, before reading the file, we need to make sure it’s a ‘valid’ file (eg a text-based file). I use an reFindNoCase() function to ensure that the file extension of the specified file is either .txt, .cfm, .cfml, .htm, or .html. If this condition is not met, the user is informed that he or she picked a file type that can not be edited, and a link to the first page is displayed.

Assuming a valid file type, the <cffile action=”read”> is run on the specified file, and the content saved into a variable called ‘thisFile’.

The rest of the code is a simple HTML form, with a couple of hidden form fields (one to tell the action page that the user was editing a file, not adding one...and one with the file name), and one textarea which will contain the contents of the file.

There is a JavaScript function to validate the form prior to submission, ensuring that there is content inside of the textarea (a zero-length file cannot be saved).



remote_file_save.cfm:
************************************************
<cfif NOT structKeyExists(form, 'fileName')>
    <cflocation url=
"remote_file_list.cfm" />
    <cfabort />
</cfif>


<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
>

<html xmlns=
"http://www.w3.org/1999/xhtml">
<head>
<title>
File Saved</title>
<meta http-equiv=
"Content-Type" content="text/html;charset=utf-8" />

<style type="text/css">
    body, td { font-family:verdana; font-size:11px; }
    a { color:#0000ff; text-decoration:none; }
    a:hover { color:#ff0000; text-decoration:underline; }
</style>
</head>

<body>


<cffile action="write"
         file=
"c:\inetpub\wwwroot\myfiles\#form.fileName#"
         output=
"#form.fileContent#"
         addnewline=
"no">

<span style="font-weight:bold;"><cfoutput>#form.fileName#</cfoutput></span> 
has been <cfif form.action_type IS "edit">updated<cfelse>written</cfif> successfully.

<br /><br />

<a href="remote_file_list.cfm">click here to continue</a>

</body>
</html>

*********************************************

In remote_file_save.cfm, we first check for the existence of the form field ‘fileName’. If it does not exist, we send the user back to the main page. Once we’re passed that, we run a <cffile> with an ACTION=”write” attribute to create the specified file. Since we’re specifying a filename that already exists, we will essentially be overwriting the original file. 

Because remote_file_save.cfm is the action page for both editing and adding a file, we need to run a quick condition to check the value of form.action_type before displaying the confirmation message to the user.

A link is provided to return the user to the main page.


remote_file_add.cfm:
*****************************************
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
>

<html xmlns=
"http://www.w3.org/1999/xhtml">
<head>
<title>
Untitled</title>
<meta http-equiv=
"Content-Type" content="text/html;charset=utf-8" />

<cfdirectory action="list"
                 directory=
"c:\Inetpub\wwwroot\textfiles"
                 name=
"fileList"
                 filter=
"*.txt">

<script language="JavaScript" type="text/javascript">
    var fileArray = new Array(<cfoutput>#quotedValueList(fileList.name)#</cfoutput>);

    function sTrim(sVariable) {
        return sVariable.replace(/^\s+|\s+$/g,"");
    }

    function validateFields(form) {
        var fileCount = 0;
        var re = /.txt$|.cfm$|.cfml$|.htm|.html$/;

        // has the user entered a file name?
        if (sTrim(form.fileName.value) == "") {
            alert('You Must Enter a File Name');
            form.fileName.focus();
            return false;
        }

        // make sure the file name ends in .txt
        if (form.fileName.value.search(re) < 0) {
            alert('Unacceptable File Extension!\n\n.cfm, .cfml, .htm, .html, and .txt Only!');
            form.fileName.focus();
            form.fileName.select();
            return false;
        }

        for (var i=0; i<fileArray.length; i++) {
            if (sTrim(form.fileName.value) == fileArray[i]) {

                fileCount++;
            } 
        }


        // is the file name going to conflict with an existing file name?
        if (fileCount > 0) {
            alert('The File Name You Selected Already Exists! Please Choose Another Name');
            form.fileName.focus();
            form.fileName.select();
            return false;
        }

        // has the user entered content for the file?
        if (sTrim(form.fileContent.value) == "") {
            alert('The file must have content!');
            form.fileContent.focus();
            return false;
        }
    return true;
    }
</script>

<style type="text/css">
    body, td { font-family:verdana; font-size:11px; }
</style>
</head>

<body>

<cfoutput>
<form action="remote_file_save.cfm" method="post" onsubmit="return validateFields(this);">
<input type="hidden" name="action_type" value="add" />
<table border="0" style="width:400px;">
    <tr>
        <td style=
"font-weight:bold;" nowrap="nowrap">File Name:&nbsp;&nbsp;</td>
        <td><input type=
"text" name="fileName" style="font-family:verdana; font-size:11px; width:316px;" /></td>
    </tr>
    <tr>
        <td colspan=
"2">
       
<textarea name="fileContent" style="font-family:verdana; font-size:11px; height:250px; width:600px;"></textarea>
        </td>
    </tr>
    <tr>
        <td colspan=
"2" style="text-align:right;">
       
<input type="button" value="cancel" style="font-family:verdana; font-size:11px;" onclick="location.href='textfile_reader.cfm';" />
        <input type=
"submit" value="add file >" style="font-family:verdana; font-size:11px;" />
        </td>
    </tr>
</table>

</form>
</cfoutput>

</body>
</html>

*********************************************

remote_file_add.cfm is very similar to remote_file_edit.cfm. One major difference is the user is specifying the new file name, so a JavaScript function runs (on form submit) to ensure a valid file extension (again, .cfm, .cfml, .htm, .html, and .txt). 
remote_file_delete.cfm:
**********************************************
<cfif NOT structKeyExists(URL, 'file')>
    <cflocation url=
"textfile_reader.cfm" />
    <cfabort />
</cfif>


<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
>

<html xmlns=
"http://www.w3.org/1999/xhtml">
<head>
<title>
Delete <cfoutput>#URL.file#</cfoutput></title>
<meta http-equiv=
"Content-Type" content="text/html;charset=utf-8" />

<style type="text/css">
    body, td { font-family:verdana; font-size:11px; }
    a { color:#0000ff; text-decoration:none; }
    a:hover { color:#ff0000; text-decoration:underline; }
</style>
</head>

<body>

<cffile action="delete"
         file="c:\inetpub\wwwroot\myfiles\#URL.file#">

<span style="font-weight:bold;"><cfoutput>#URL.file#</cfoutput></span> has been deleted.
<br /><br />
<a href="remote_file_list.cfm">click here to continue</a>

</body>
</html>

*****************************************

remote_file_delete.cfm is one of the simpler templates. After checking for the existence of a URL variable named ‘file’, it simply runs a <cffile> with an ACTION=”delete” attribute. The user is then presented with a message indicating a successful deletion, with a link back to the main page.

Questions? I spend way too much time in the Easycfm.com forums. Meet me there and I’ll see if I can answer ‘em for ya :)


Date added: Tue. June 3, 2003
Posted by: Charlie Griefer (CJ) | Views: 15341 | Tested Platforms: CF5 | Difficulty: Intermediate
Categories Listed: Full Applications Other

HostMySite.Com is sponsoring this tutorial, please visit their site today!
This tutorial is sponsored by HostMySite.Com - ColdFusion Hosting

This author's other tutorials:
Helping users obtain their passwords
Your site requires your visitors to log in. of course, some of your visitors are going to forget their passwords (ok, most will forget their passwords). You don't want them to have to send you an e-mail, and then wait for a response. They need immediate access. <br><br> This tutorial shows two methods by which you can accomodate them. - Date added: Thu. August 28, 2003
CF 'Best Practices'
Some tips and techniques that I've picked up over the years. I don't maintain that these are 'official' or 'absolute'...they are simply my preference and things that have worked for me. I would like to share them here, and leave you to make the decision as to whether or not they fit in your 'code arsenal' :) - Date added: Fri. August 15, 2003
JavaScript Form Validation
Yes, I know we're a ColdFusion site...but ColdFusion does not live in a vacuum. We have to know SQL, HTML, CSS...and sometimes...JavaScript! This tutorial focuses on using JavaScript (in lieu of cfform) to create client side form validation (and explains why writing your own is better than using <cfform>). - Date added: Thu. August 14, 2003
arrays and structures - part 3
part three of a three-part tutorial designed to gently introduce you to the world of complex variables. - Date added: Mon. August 11, 2003
arrays and structures - part 2
part two of a three-part tutorial designed to gently introduce you to the world of complex variables. - Date added: Mon. August 11, 2003

Additional Tutorials:
· arrays and structures - part 1

· Grouping Output in CF

· Save your visitor's clickstreams

· Dynamic Column Output (Part Two)

· Dynamic Column Output (Part One)

· to cfqueryparam or not to cfqueryparam

· ColdFusion Mad Libs - Part II

· ColdFusion Mad Libs - Part I

· CFSCRIPT Intro
Please rate this tutorial:
5 Stars 4 Stars 3 Stars 2 Stars 1 Stars
Comments on this tutorial
Read previous comments on this particular tutorial
problems with textarea
it's seem got some problem when i try to edit a cfm file that have a text area input.
Posted by: zaihan
Posted on: 07/25/2004 09:54 PM
textarea
Yes, it seems that the first closing tag "</textarea>", present in the file that is edited, goes in "conflict" with the <textarea> tag of the editing page, closing it.

If you use this tutorial to build some kind of administration pages you can use a rude workaround; simply use the "Replace" function to replace all the </textarea> closing tags with something else, than when you submit the form do the same but this time placing back the </textarea> tags.
Posted by: Giovanni
Posted on: 11/05/2004 08:44 AM
textarea on edit page
>#thisFile#</textarea>

ya need to change it to this

>#htmleditformat(thisFile)#</textarea>

if you don't do this the coldfusion can get confused between the textarea code and the actual file code

Try and edit the remote_file_add.cfm and the remote_file_edit.cfm files with these files without doing the change that i specified above and you will know what I mean.
Posted by: L33nsta
Posted on: 04/04/2005 11:07 AM
Thanks!
Once I made the slight change to the edit page as noted above, this is EXACTLY what I needed. This code was a GREAT way to get to those files allowing me to update them as needed. Now I can use my evenings for somethig else!

Thanks EasyCFM!
Posted by: Excalibur
Posted on: 08/22/2005 12:20 PM
Load Balanced Server
Will this work on a load balanced server environment?
Posted by: Daryl
Posted on: 08/04/2006 03:27 PM
Populating List
right first of all great coding. i got one little problem though. i've got all of the codings to work. the only problem i'm getting is when i save a new file i have created, the file does not show on the list.
i think my problem is the root directory not 100% sure.
heres what i've written down where you have written directory="c:\Inetpub\wwwroot\myfiles"

directory=
"O:\TG-54-H\40 - WEB\Projects\Nadeem\testing\myfiles"

please tell if it is right or wrong, or what else could i check
Posted by: Nadeem
Posted on: 08/31/2006 08:34 AM
Post a new comment on this tutorial
post a new comment on this particular tutorial
Your Name:
Your Email:
Comment Title:
Comments:
Key Phrase:
 
Skyscrapper Banner Advertisement
Daily Razor - ColdFusion Hosting

You are 1 of 707 active sessions! | Privacy | Company
Copyright © 2002 EasyCFM.Com, LLC. (Easy ColdFusion Tutorials) All Rights Reserved
All other trademarks and copyrights are the property of their respective holders.
ColdFusion Hosting ColdFusion Hosting
ADD TO:
Blink
Del.icio.us
Digg
Furl
Google
Simpy
Spurl
Y! MyWeb