My First ColdFusion 8 CFFTP Experience - Rocky But Triumphant

Posted August 29, 2008 at 9:46 AM

Tags: ColdFusion

Yesterday, I performed my first ever ColdFusion CFFTP task. I've needed to perform FTP tasks from ColdFusion before but required sFTP functionality, which was only added in ColdFusion 8. As such, until now, I have only ever used third-party utilities. I got the ColdFusion 8 secure FTP to work, but it took me a while to figure it out all. I am sure others will run into similar road blocks, so I thought I'd share my learnings.

The first thing we want to do is create a large test file to upload (PUT) to our FTP account:

 Launch code in new window » Download code as text file »

  • <!--- Get the file name of this test file. --->
  • <cfset strFilePath = ExpandPath( "./test.txt" ) />
  •  
  • <!---
  • Create a really large file. We need to do this because a
  • small file will be uploaded no matter what the timeout it
  • on the CFFTP.
  • --->
  • <cfsavecontent variable="strText">
  • <cfloop index="intI" from="1" to="100000" step="1"
  • >This is a really large file with a massive amount of text.
  • </cfloop>
  • </cfsavecontent>
  •  
  • <!--- Write the text to the test file. --->
  • <cffile
  • action="write"
  • file="#strFilePath#"
  • output="#strText#"
  • />

Here, we are just creating a file path (to be used throughout this example) and writing about 6 MB of data to it. It is important that the file be large because that's when things get a little bit more exciting.

The next thing we need to do is define our connection properties. We could do this inline with the ColdFusion 8 CFFTP tag, but using the AttributeCollection gives us the ability to cache the connection information in our site's configuration mechanism:

 Launch code in new window » Download code as text file »

  • <!--- Set up the FTP configuration. --->
  • <cfset objFTPProperties = {
  • Server = "****************",
  • Port = "***",
  • Username = "bnadel",
  • Password = "******",
  • Secure = true
  • } />

Ok, now that we have our test file and our sFTP configuration object in place (for use with the tag's AttributeCollection), let's go ahead and try to upload (PUT) the file to the remote FTP server:

 Launch code in new window » Download code as text file »

  • <!---
  • Now that the file has been written, we need to FTP it.
  • Let's create a connection object that will be used for
  • the following FTP commands.
  •  
  • When we name this connection, "objConnection", ColdFusion
  • caches the connection and allows us to execute future FTP
  • commands on this connection without passing in login
  • credentials or configuration.
  • --->
  • <cfftp
  • action="open"
  • connection="objConnection"
  • attributeCollection="#objFTPProperties#"
  • />
  •  
  • <!--- "Put" the SQL file to cached connection. --->
  • <cfftp
  • action="putfile"
  • connection="objConnection"
  • localfile="#strFilePath#"
  • remotefile="/home/bnadel/#GetFileFromPath( strFilePath )#"
  • transfermode="auto"
  • />
  •  
  • <!--- Close the connection. --->
  • <cfftp
  • action="close"
  • connection="objConnection"
  • />

There's a couple of things going on here. First, we are naming our sFTP connection, "objConnection." By doing this, it gets ColdFusion 8 to cache to the connection to the FTP server. This allows us to execute additional FTP commands on the cached connection without using our configuration attributes. That is why only the OPEN command uses the AttributeCollection; the PUT and CLOSE commands simply refer to the name of the cached connection.

Simple enough, right? Unfortunately, this does not work. When running the above code, ColdFusion throws the following exception:

An error occurred during the sFTP putfile operation. Error: putFile operation exceeded TIMEOUT. java.io.IOException: putFile operation exceeded TIMEOUT.

Ok, that make sense; I'm uploading a 6 MB file and the default timeout for FTP commands is 30 seconds.

To fix this, I went to increase the timeout of the PUT command to 300 seconds (5 minutes):

 Launch code in new window » Download code as text file »

  • <!---
  • "Put" the SQL file to cached connection. This time, put
  • a 5 minute timeout on the PUT command. This should be more
  • than enough to handle the file size.
  • --->
  • <cfftp
  • action="putfile"
  • connection="objConnection"
  • localfile="#strFilePath#"
  • remotefile="/home/bnadel/#GetFileFromPath( strFilePath )#"
  • transfermode="auto"
  • timeout="300"
  • />

The connection is really fast so 5 minutes should be no problem for 6 MB. However, when I integrated this PUT file with the above example, I got the same exact error:

An error occurred during the sFTP putfile operation. Error: putFile operation exceeded TIMEOUT. java.io.IOException: putFile operation exceeded TIMEOUT.

Maybe 5 minutes wasn't enough. I tried pumping it up to 8 minutes. Still no luck.

After pouring over the ColdFusion live docs for a while, it suddenly occurred to me: the timeout attribute doesn't go on the PUT command. I don't know if this is true for one-off commands, but when we are using a ColdFusion cached connection (named connection), the Timeout attribute must be included in the OPEN command. This way, the Timeout will define the timeout of all commands executed on that cached connection.

So, no problem, I went ahead and put the Timeout in the OPEN CFFTP command:

 Launch code in new window » Download code as text file »

  • <!---
  • Now that the file has been written, we need to FTP it.
  • Let's create a connection object that will be used for
  • the following FTP commands.
  •  
  • This time, let's move the TimeOut property to the OPEN
  • command. This will put the timeout property into our
  • cached connection object for use on all commands.
  •  
  • When we name this connection, "objConnection", ColdFusion
  • caches the connection and allows us to execute future FTP
  • commands on this connection without passing in login
  • credentials or configuration.
  • --->
  • <cfftp
  • action="open"
  • connection="objConnection3"
  • timeout="300"
  • attributeCollection="#objFTPProperties#"
  • />
  •  
  • <!--- "Put" the SQL file to cached connection. --->
  • <cfftp
  • action="putfile"
  • connection="objConnection3"
  • localfile="#strFilePath#"
  • remotefile="/home/bnadel/#GetFileFromPath( strFilePath )#"
  • transfermode="auto"
  • />
  •  
  • <!--- Close the connection. --->
  • <cfftp
  • action="close"
  • connection="objConnection3"
  • />

I was feeling confident when I refreshed the page. As it was running, I monitored the progress of the FTP upload using FileZilla. Every few seconds, I would refresh the remote directory listing in FileZilla to see how big the file size was. When it got to 6 MB, I was excited - it has worked! But then, I was shocked to switch back to the web page and find the following error:

The request has exceeded the allowable time limit Tag: cfftp. The error occurred on line 210. An error occurred during the sFTP putfile operation. Error: putFile operation exceeded TIMEOUT. java.io.IOException: putFile operation exceeded TIMEOUT

When I saw the line:

putFile operation exceeded TIMEOUT

... I assumed the FTP just timed out again. So I increased the Timeout value and ran it again. And, once again, the same problem - the file finished uploading according to FileZilla, but the page kept reporting that the PUT command timed out. What was going on? I started looking at the log files and messing with the timeout value and going back over the documentation.

What had I missed?!? It seemed to be both working and failing at the same time?

Then it occurred to me! The above error is actually telling us two things: the PUT file exceeded the timeout and the request had exceeded the allowable time limit. Of course! The request! This time, it wasn't the FTP command that was timing out, it was the page itself. What was happening was that the ColdFusion sFTP PUT command was finishing properly, but when it returned, the executing page timed out.

The fix for this was simple:

 Launch code in new window » Download code as text file »

  • <!---
  • Give the page some extra time to execute since we are going
  • to be executing some large FTP commands.
  • --->
  • <cfsetting requesttimeout="300" />

By increasing both the timeout of the cached CFFTP connection as well as the timeout of the page, everything went smoothly.

So, it was a bit of a rocky start with ColdFusion 8's CFFTP tag, but once I got all the kinks ironed out, I had some pretty powerful functionality.

I won't bother putting this in the example, but after I was done testing, I moved this into a CFThread tag so that it could run asynchronously as part of a list of scheduled tasks. By putting the CFFTP command in a CFThread, it eliminated the need for the CFSetting tag. ColdFusion threads launched using CFThread do not have a timeout; therefore, only the timeout of the CFFTP connection needs to be considered.

Download Code Snippet ZIP File

Post Comment  |  Ask Ben  |  Permalink  |  Other Searches  |  Print Page


You Might Also Be Interested In:




Reader Comments

Aug 29, 2008 at 12:42 PM // reply »
177 Comments

I have a small nitpick:
"There's a couple of things going on here. First, we are naming our sFTP connection, "objConnection." By doing this, it gets ColdFusion 8 to cache to the connection to the FTP server."

The way you wrote this makes it seem like naming your connection "objConnection" is doing something magical. Maybe it's the use of the quotes. I also don't think it's a 'caching' mechanism as much as it is a naming of a thread. Connection is an optional thing, but if you don't supply a connection name, CF will make one for itself.

Quote from the CFDocs: Name of the FTP connection. If you specify the username, password, and server attributes, and if no connection exists for them, ColdFusion creates one. Calls to cfftp with the same connection name reuse the connection.


Ian
Aug 29, 2008 at 12:47 PM // reply »
1 Comments

The biggest thing I ran into when I upgraded to CF 8 was that CF 8 required the connection attribute but the error you get without it "Null, Null" doesn't give you a clue that that is the problem.


Aug 29, 2008 at 3:30 PM // reply »
6,516 Comments

@Todd,

I was just referencing some of the documentation:

When you establish a connection with cfftp action="open" and specify a name in the connection attribute, ColdFusion caches the connection so that you can reuse it to perform additional FTP operations. When you use a cached connection for subsequent FTP operations, you do not have to specify the username, password, or server connection attributes. The FTP operations that use the same connection name automatically use the information stored in the cached connection. Using a cached connection helps save connection time and improves file transfer performance..... Changes to a cached connection, such as changing retryCount or timeout values, might require reestablishing the connection.

Maybe I am using weird wording, but I was trying to get the above sentiment across. And, as I am new to the CFFTP world, I am not aware of all the ins-and-outs.

@Ian,

Yeah, the Null Null error on anything is frustrating :)


Oct 26, 2008 at 4:03 PM // reply »
1 Comments

Thanks for writing up your experience with this. I just migrated to CF 8 and had this exact problem. Your instructions on solving it saved me a lot of time figuring it out.


Oct 26, 2008 at 4:10 PM // reply »
6,516 Comments

@Chris,

Glad to help man!


Tom
Oct 28, 2008 at 9:12 AM // reply »
12 Comments

To Todd and other readers, the purpose of naming your connection is so that you actually know which connection to refer to when making calls (e.g. lets say you have multiple FTP calls happening simutaneously). If you allow CF to create/name the call, you wont know which one to refer to during multiple FTP calls.

HTH,
Tom

As always, thanks for figuring this out for us!


Jan 17, 2009 at 2:30 AM // reply »
32 Comments

Hi Ben

I was reading this post now and I saw a reference to the "retryCount" property of CFFTP.

I did some research into this and I must admit the documentation relating to this property is very minimal.

What I am wondering is:

1) Does this ONLY apply to the "open" action of CFFTP or other tags, as I've only seen it referenced in the "open" action.

2) If so, does this simply ensure that if a connection can't be established, that it tries [retrycount] number of times to establish the connection
OR
Does this mean that ANY CFFTP action attempt that fails (e.g. action="putfile") will retry [retrycount] number of times??

Any idea?

I was just laying in bed thinking about how to handle FTP file resumes if a file upload should get disrupted somehow and then I saw this post and reference to the "retrycount" property and was wondering if this is what I need? :)

Thanks


rob
Jan 28, 2009 at 11:08 PM // reply »
5 Comments

Thanks for this post, I was about to shoot myself in the face.


May 5, 2009 at 5:38 PM // reply »
5 Comments

Thanks Ian for your post. you saved me a lot of hair,
ie. The biggest thing I ran into when I upgraded to CF 8 was that CF 8 required the connection attribute but the error you get without it "Null, Null" doesn't give you a clue that that is the problem


Jun 30, 2009 at 10:43 PM // reply »
8 Comments

Hi Ben,

Here's a great post on CF8 and a file size issue here: http://coldfused.blogspot.com/2007/08/coldfusion-8-changes-with-file-upload.html

I wasn't sure how big a file CF8 would manage to transfer without timing out as i've had troubles with reading large 400meg xml files.

Any ideas on how to receive a response on the progress of the file?

Cheers


Jul 1, 2009 at 8:31 AM // reply »
6,516 Comments

@Leigh,

I am confused as to what you are asking. This post was about FTP, but the link you listed was about HTTP. Are you asking about timing out in FTP or HTTP?


Jul 1, 2009 at 9:42 AM // reply »
34 Comments

@Leigh

Dude that's insane to have such a huge XML file, especially since you are just reading it. Why don't you just generate your XML file from a database? It would save you so much processing time as 400 megs of XML is really insane I have seen some huge XML files but 400? Dude you need to rethink your structuring a little bit better I know that is killing your server when you request that file.


Jul 1, 2009 at 9:06 PM // reply »
8 Comments

Hi All,

I should be a bit more specific.

I am looking for a file transfer solution through CF to upload a single file at a time (20-100megs). Looks like i'll use CFFTP to do after reading some posts.

The article i posted was mentioning issues with IIS and Windows server 2003 which i thought might effect the CFFTP but i could be wrong?

I've had trouble in the past with CF timing out when reading large xml files, but haven't attempted to copy large files at all.

I have a current client system that generates a massive XML file of property data (full push) which came to 400meg! This is a seperate issue i face in CF as i believe a COM object on a windows server is a solution after doing some research on how to read large files. *The xml is also encased inside a zip file full of images.

I've found i can only read into CF around 3.7 meg of XML data in 10mins before it times out.

Leigh


JFC
Jul 16, 2009 at 8:07 AM // reply »
1 Comments

Is there anything else that must be set-up/configured to allow ColdFusion 8 to establish a secure FTP connection? I have set-up multiple tests with various code configurations, each test results in a "User Authentication failed" error. I can connect to the secure FTP server using CoreFTP or psFTP which confirms my user parameters, server, and port are correct.


Jul 18, 2009 at 1:54 PM // reply »
6,516 Comments

@JFC,

From the docs, it looks like all you need to do is set secure="true" in the CFFTP tag. If you need to get more complex, it looks like you might need to generate some secure private key stuff:

http://livedocs.adobe.com/coldfusion/8/htmldocs/help.html?content=Tags_f_18.html

I have not worked with SFTP very much.


Aug 18, 2009 at 5:31 AM // reply »
5 Comments

Handy article..Ben

you may also want to set the fingerprint parameter to the cfftp tag for SFTP..

<cfsetting requesttimeout="600" />

<cfftp action = "open"
username = "***"
connection = "**********"
password = "*********"
fingerprint = "40:12:77:67:43:bb:2f:71:06:b8:3b:b7:ee:v5:ee:31"
server = "111.11.111.111"
secure = "yes"
timeout="300">

use Bitvise Tunnelier to get the fingerprint for your SFTP login


Sep 2, 2009 at 5:07 PM // reply »
4 Comments

Ben,

Not sure if you're familiar with mainframe files or not, but here goes. One of our processes FTP's a file to the mainframe, but one caveat is that we have to pre-allocate some of the parameters for the file, with CF8 they introduced a handy new action called "site" which would allow you to put in syntax to be run on the ftp server, so in this instance I'm running the following:

<cfftp connection="Myftp"
action="site"
actionparam="LITERAL SITE LRECL=2088 RECFM=FB CYLINDERS PRIMARY=3 SECONDARY=1">

Works great in CF8, the problem is that our production environment is still running CF7 and, unfortunately, we do not have plans to upgrade in the near future. Do you know of any similar commands in CF7 that I could use to accomplish this task?

Any guidance would be much appreciated.

Chuck


Sep 6, 2009 at 11:52 AM // reply »
6,516 Comments

@Chuck,

Unfortunately, that is beyond my understanding. I've never even seen the Site feature before. If I come across anything, I'll let you know.


Sep 20, 2009 at 12:17 AM // reply »
10 Comments

Hi Ben! I do not if i should ask this question or not, but i am bit in complexity.

Can we use cfftp to upload multiple files and insert the same in the database too at the same time.

is This possible.


Sep 23, 2009 at 2:30 PM // reply »
1 Comments

Ben,
I've been able to make the ftp connection to the server ok. but I'm having trouble uploading a file to a remote server. I have the correct path on the remote server and that looks ok. what I'm having trouble with is I use a form to look up the file I want to upload, which give a honking long filename, nothing like the real filename. I always get an error that says it can't make the file. any suggestions on what's going on here?


Tom
Sep 23, 2009 at 2:38 PM // reply »
12 Comments

@Terri,

The most common problem people have with uploading files in CF is they fail to account for the cffile variable. This article sums it up pretty nicely: http://www.quackit.com/coldfusion/tutorial/cffile_parameters.cfm. Check your code and see if this might be the issue. The tip was the "honking long filename." :)


Sep 23, 2009 at 6:47 PM // reply »
5 Comments

Terri,

Just double check you have the correct permissions on the folder..sometimes easy to overlook

You could test with a normal upload function to see if you can write files ok


Sep 24, 2009 at 9:17 AM // reply »
6,516 Comments

@Terri,

If it is giving you a really long file name, it's probably giving you the .TMP file path (extracted from the FORM). What you need to do is actually save the file to disk first (using CFFILE) and then upload the destination file.


Oct 28, 2009 at 5:33 PM // reply »
9 Comments

Chris and Ben,

Have you guys tried to secure ftp into a unix box using just the username and pub/pivate key access methods?


Oct 31, 2009 at 2:12 PM // reply »
6,516 Comments

@Tony,

I have not tried that.


Nov 1, 2009 at 3:41 PM // reply »
5 Comments

Tony

I use the secure ftp to transfer video files from a windows server to a linux server and this works like a dream..

I do pass in the fingerprint parameter...but I guess the determining factor is the sftp service you have setup on your unix box as to how you can get this to work with the cfftp tag.


Nov 1, 2009 at 3:48 PM // reply »
9 Comments

@Ben, ok thanks....

@Chris, are you using the "username/key" instead of "username/password"???


Nov 1, 2009 at 7:08 PM // reply »
5 Comments

Hi Tony,

we are using username/password/fingerprint.

Sorry if the previous post was unhelpful.


Nov 2, 2009 at 10:32 AM // reply »
9 Comments

@Chris, any input on this is helpful. I appreciate the response!


Nov 10, 2009 at 9:17 AM // reply »
2 Comments

Thanks for the post. I spent like 3 hours trying to figure out why it kept on timing out. But it was worse for me, on our Dev server it worked right away, but on the test I kept on getting a read time out error. But when I put the longer timeouts in the open connection and on the calling page seems to have solved the problem.


Nov 15, 2009 at 10:58 PM // reply »
6,516 Comments

@Roman,

Glad you got it working; ColdFusion is sometimes funny that way, in that it won't timeout while a 3rd party interaction is executing; it will only timeout once that process has returned.


Post Comment  |  Ask Ben

Recent Blog Comments
Nov 22, 2009 at 1:56 AM
Learning ColdFusion 9: Using CFQuery In CFScript Can Enable SQL Injection Attacks
Why adobe would give you script equivalent of cfquery is beyond me. I love cfquery tag because it helps me wriite clean sql, and get away from the horrible jdbc queries If I wanted to write javali ... read »
Nov 22, 2009 at 1:45 AM
Streaming Text Using ColdFusion's CFContent Tag And The Variable Attribute
The reason you would want to do this is to stream. Ack json/xml files to ria clients I used thus technique before because putting json in response stream causes debugging info to come thru As well a ... read »
Nov 21, 2009 at 6:47 PM
Hal Helms - Real World Object Oriented Development, Sarasota - Day Five
@charlie griefer, Thank you.. ... read »
Nov 21, 2009 at 5:15 PM
Using ColdFusion Structures To Remove Duplicate List Values
@Jose Galdamez, Oh heh yeah I didn't paste the whole code. I should have defined the vars -- my bad. It's fixed thou. Thanks. ... read »
Nov 21, 2009 at 4:49 PM
Styling The ColdFusion 8 WriteToBrowser CFImage Output
Great work yet again Ben! Whilst I didn't use this whole code, I copied some of your regex code for a similar problem with the lack of an alt attribute and unescaped ampersands in CFIMAGE for Railo 3 ... read »
Nov 21, 2009 at 1:13 PM
My First ColdFusion Builder Extension - Encrypting And Decrypting CFM / CFC Files
@Ben, Because I am pedantic, I just want to make sure that everyone knows there is absolutely no encryption going on. There is only encoding and obfuscation. The cfencode tool only obfuscates your C ... read »
Nov 21, 2009 at 12:28 PM
Using ColdFusion Structures To Remove Duplicate List Values
@Jody I can't seem to get your code sample to work. If you are still having problems, try this code out and see if it gets you what you wanted. <!--- Comma delimited list with various duplicates ... read »
Nov 21, 2009 at 11:03 AM
Groovy Operator Overloading Does Not Work In The ColdFusion Context
Hi Ben, Thanks for this informative post. Now I am reading ur old posts too ... read »