In a recent project at work we needed a simpler approach to using the FTP solution built into Adobe ColdFusion. A couple of the drawbacks to the current implementation of cfftp in ColdFusion are:
- A cached connection variable must be stored at the template page level. Using a class facade, we are able to store the persisted connection within the component.
- Deleting files and folders does not check if the file exists first, our facade takes care of that. If the file doesn’t exist, and we are attempting to remove a directory or file, it throws a custom exception type that we can catch.
- If the connection is closed on the remote server, we want our facade to handle reconnecting, not each implementation of cfftp.
- Recursive putting and deleting of directories. This was a big deal for our project, and it didn’t make sense to implement this in the code specific to the project, but to have a general purpose method to
putDirectory()
andremoveDirectory()
.
Our facade/utility does have a dependency on our Exception factory, which is stored in the application.exceptions
application variable.
If you would like to use this code you can replace these with your own exception handling or just plain cfthrow tags.
Our utility class also uses a logger factory that follows the principles of the Java logging utility logf4j.
You can read more about my simple logging utility.
Lastly, the facade is programmed using CFML (tag-based) rather than the more succinct cfscript as our project required this.
Opening and Closing a Connection
Opening and closing a connection is as simple as calling either the open()
or close()
method.
When opening a connection you must specify the connection parameters: server
, username
, and password
.
The class stores the connection parameters so you can also use the setters: setServer()
, setUsername()
, and setPassword()
.
Here is an example of opening the connection:
<<cfset variables.FTP_SERVER = 'ftp.remoteserver.com'>
<cfset variables.FTP\_USERNAME = 'username'>
<cfset variables.FTP\_PASSWORD = 'password'>
<cfset variables.FTP\_TIMEOUT = 1200>
<cfset ftpUtil = CreateObject("component", "FtpUtil")>
<cfset ftpUtil.open(server=variables.FTP\_SERVER, username=variables.FTP\_USERNAME, password=variables.FTP\_PASSWORD, timeout=variables.FTP\_TIMEOUT)>
Closing a connection is simple, just call the close method:
<cfset ftpUtil.close()>
If you want to reset the connection, which will close and reopen the connection, simply call the reset method:
<cfset ftpUtil.reset()>
File and Directory Operations
To get started, let’s look at the simple exists methods.
You can call existsDirectory()
or existsFile()
to check if a file exists.
You can use the getFile()
method to download a file from the remote server.
To upload files, use the putFile()
and putDirectory()
methods; and you can use the removeFile()
and removeDirectory()
methods to remove files and directories.
Note that the putDirectory()
and deleteDirectory()
methods are recursive.
These will upload an entire local directory and all of it’s folders and files to the remote server, or delete all files and folders within a remote directory.
Here are the method signatures:
existsDirectory(required string directory)
existsFile(required string file)
getFile(required string source, required string destination, boolean overwrite=true)
putFile(required string source, required string destination)
putDirectory(required string source, required string destination, boolean includeHiddenFiles=true, boolean includeHiddenDirectories=true)
removeFile(required string file, boolean validateExists=true)
removeDirectory(required string directory, boolean validateExists=true)
You can also change directories and get the current directory (and URL of the current directory), and list the directory contents using the following methods:
getCurrentDirectory()
getCurrentUrl()
listDirectory(string directory=getCurrentDirectory())
changeDirectory(required string directory)