3

When uploading a file using cfftp, how do you determine if the file already exists and rename it?

<cfftp
connection = "myConnection"
action = "putFile"
name = "uploadFile"
localFile = "C:\files\upload\some_file.txt"
remoteFile = "some_file.txt"
existing = "some_file.txt">

The cffile tag has a makeunique attribute, which makes the process very simple. Thanks.

Updated 8/2/20:

This is my cfm.

<cfif isDefined("Form.FileContents")>
    <cfset localFileDirectory="c:\localfiles" />
    
    <!--- If directory does not exist, create it --->
    <cfif Not DirectoryExists(localFileDirectory)>
        <cfdirectory action = "create" directory="#localFileDirectory#" />
    </cfif>
    
    <!--- Upload file to temp location --->
    <cffile action = "upload"
        fileField = "FileContents"
        destination = "#localFileDirectory#" 
         nameconflict="overwrite" 
         result="tempFile"> 
     
    <!--- Set the FTP file destination location (directory) --->
    <cfset destinationPath = "remotefiles/myFiles" />
    <!--- initialize attachment service --->
    <cfset attachmentService = new ais.applications.components.service.aisdocdbFtpService()/>
    <!--- upload file to ftp site --->
    <cfset uploadResults = attachmentService.doUpload(destinationPath,tempFile)/>
    
    <cfif uploadResults.Succeeded>
        success
    <cfelse>
        fail
    </cfif>
<cfelse>
    <form method="post" action=<cfoutput>#cgi.script_name#</cfoutput>
        name="uploadForm" enctype="multipart/form-data">
        <input name="FileContents" type="file">
        
        <input name="submit" type="submit" value="Upload File">
    </form>
</cfif>

This is the FTP service I'm using..

<cfcomponent>
    <cfproperty name="overwriteFiles" type="boolean" />
    <cfproperty name="createDirectories" type="boolean" />
    
    <cfset FTPProps = {server="myServer", port = "21", username="myUser", password="myPassword", stopOnError="yes"} >
    
    <!--- Constructor --->
    <cffunction name="init" access="public" output="false" returntype="ais.applications.components.service.aisdocdbFtpService" hint="constructor">
        <cfargument name="overwriteFiles" type="boolean" required="false" default="false">
        <cfargument name="createDirectories" type="boolean" required="false" default="true">
        <cfset this.overwriteFiles = arguments.overwriteFiles/>
        <cfset this.createDirectories = arguments.createDirectories/>
        <cfreturn this/>
    </cffunction>
    
    <!--- doUpload --->
    <cffunction name="doUpload" access="public" returntype="any" output="false">
        <cfargument name="destinationPath" type="string" required="true"/>
        <cfargument name="tempFile" type="any" required="true"/>
        
        <cfset var sourcePath = "#tempFile.serverDirectory#"/>
        
        <!--- FTP to AIS Doc DB --->
        <cftry>
            <!---Open the connection --->                       
            <cfftp  action="open" connection="myConnection" timeout="600" attributeCollection="#FTPProps#" />   
            
            <cfif this.createDirectories>
                <cfset folders = ListToArray(arguments.destinationPath, '/')/>
                <cfset var path = ''/>
                <cfloop array="#folders#" index="folder" >
                    <cfset path = path & folder & '/'/>
                    
                    <!--- Make Sure Directory Exsists --->
                    <cfftp action="existsdir" connection="myConnection" directory="#path#" result="directoryCheck"/>
                    
                    <cfif !directoryCheck.returnValue>
                        <cfftp action="createdir" connection="myConnection" directory="#path#" result="createDirectoryResult"/>
                    </cfif>
                </cfloop>
            </cfif>
                
            <!--- Upload File --->
            <cfftp action="putfile" connection="myConnection" localfile="#sourcePath#\#tempFile.serverFile#" remoteFile="#destinationPath#/#tempFile.clientfile#" failIfExists="#!this.overwriteFiles#" transfermode="auto" result="uploadResult"/>
            <cfcatch type="any" name="exception">
                <cfrethrow/>
            </cfcatch>
            <cffinally>
                <!--- Clean Up Temp Files --->
                <cffile action = "delete" file = "#sourcePath#\#tempFile.serverFile#">
                 <!---close the connection --->      
                <cfftp action="close" connection="myConnection">
            </cffinally>                           
        </cftry>
        
        <cfreturn uploadResult/>
    </cffunction>
</cfcomponent>

I verified that the file is successfully uploading to the remote server. When I attempt to upload a second time, with the same filename, it still says that it succeeded.

Thanks.

Jay
  • 33
  • 3

1 Answers1

1

Your existing code will produce a boolean variable called cfftp.succeeded. You can do whatever you want to do if that variable has a value of false.

Or, you can run a cfftp action = "listDir" command, This will produce a query object including the name of each item including whether or not it's a directory. You can run a query of query to see if the file exists.

Edit begins here

After reading the comments, I thought of another option. Make the filename unique no matter what by appending something to the end of the filename. A UUID would work all the time. The date and time precise to the millisecond would very likely work all the time as well if you want something shorter

OriginalName = 'abc.txt';
FileNamePart = ListFirst(OriginalName, '.');
NewName1 = FileNamePart & DateTimeFormat(now(), 'yyyymmddHHnnssl');
NewName2 = FileNamePart & CreateUUID();  // could replace the hyphens with empty strings here.
Extension = ListLast(OriginalName, '.');
NewName = NewName2 & '.' & Extension;  // could also use NewName1


writeoutput("filename is #FileNamePart#<hr>");
writeoutput("extension is #Extension#<hr>");
writeoutput("NewName1 is #NewName1#<hr>");
writeoutput("NewName2 is #NewName2#<hr>");
writeoutput("NewName is #NewName#<hr>");
Dan Bracuk
  • 20,699
  • 4
  • 26
  • 43
  • Thanks Dan. Please see my updated code above. I am still unable to return that it's failing. – Jay Aug 02 '20 at 18:27
  • @Jay I've never used `` before, but I have coded an ftp script in the past on linux and what I've learned is that ftp clients are notorious for returning false positives, which is likely why you are getting your `succeeded` flag returning true. What I've done is use a hacky workaround to determine if the file was already there by transferring the file from the remote server back to the client and test for the file existence. I know it's not ideal, but it was the only solution I could find at that time to handle for false positives. – user12031119 Aug 03 '20 at 01:44
  • @Jay I looked at the docs for `` and the `failIfExists` flag only tests for existence of a local file on a `getfile` operation. It looks like it's an ignored parameter on a `putfile` operation, which is likely why you're getting false positives. I presented a hacky workaround in my previous comment that you might want to give a try. – user12031119 Aug 03 '20 at 01:53
  • @user12031119 - Thanks for your quick reply! I had considered this solution, but was hoping for a better one. I figured there wasn't. The only thing I don't like about it is, if I'm renaming these files after a Fail, I will have to loop and execute a getFile for every suggested filename as well until I find a unique name. The good thing is that this will rarely happen. Plan for the worst, hope for the best. Thanks again. I will update my post with the solution when complete. – Jay Aug 03 '20 at 13:41
  • After reading, `if I'm renaming these files after a Fail, I will have to loop and execute a getFile for every suggested filename as well until I find a unique name`, I came up with another idea - do something to guarantee uniqueness right off the bat. Answer edited accordingly. – Dan Bracuk Aug 04 '20 at 15:21