Skip to content

Instantly share code, notes, and snippets.

@cflove
Last active September 24, 2020 02:15
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cflove/4bac3a0e0d1ed0f430b92738640b354e to your computer and use it in GitHub Desktop.
Save cflove/4bac3a0e0d1ed0f430b92738640b354e to your computer and use it in GitHub Desktop.
ColdFusion custom tag to work with WinSCP / sftp. This use external files and write hostkey and script file in the same dir location of the custom tag template. Change default attributes. This need WinSCP installed in the server.
<!---
<cf_WinSCP action ="listdir"
username =""
password =""
host =""
name ="qryDirectory"
directory ="" />
<cf_WinSCP action="exists"
username =""
password =""
host =""
item =""/>
<cfif val(exists)>File Exists </cfif>
<cf_WinSCP action="getFile"
username =""
password =""
host =""
localFile =""
remoteFile ="" />
<cf_WinSCP action="rename"
overwrite = "true"
username =""
password =""
host =""
existing =""
new =""/>
<cf_WinSCP action="remove"
username =""
password =""
host =""
item ="" />
<cf_WinSCP action ="putFile"
username = ""
password = ""
host = ""
localFile = ""
remoteDirectory = ""
remoteFile = "" />
--->
<cfswitch expression="#ThisTag.ExecutionMode#">
<cfcase value="Start">
<cfparam name="attributes.hostkey" default="">
<cfparam name="attributes.WinSCPPath" default="C:\Program Files (x86)\WinSCP\WinSCP.com">
<cfparam name="attributes.timeOut" default="120">
<cfparam name="attributes.chmod" default="644">
<cfparam name="attributes.secure" default="yes">
<cfset tempDir = "#GetDirectoryFromPath(GetCurrentTemplatePath())#WinSCP\">
<cfif not directoryExists(tempDir)>
<cfdirectory action = "Create" directory = "#tempDir#" />
</cfif>
<!--- ************************************************************************ --->
<!--- check do we have hostkey saved --->
<!--- ************************************************************************ --->
<cfif not len(attributes.hostkey) and booleanFormat(attributes.secure)>
<cfif not fileExists("#tempDir##attributes.host#")>
<!--- get the host key and save it for later use --->
<cfexecute
name = "#attributes.WinSCPPath#"
arguments = '/command "open sftp://#attributes.username#:#attributes.password#@#attributes.host#'
timeout = "#attributes.timeOut#"
variable = "return">
</cfexecute>
<cfset s = findNoCase("Host key fingerprint is", return)>
<cfif val(s)>
<cfset attributes.hostkey = listFirst( removeChars(return, 1,s+23) ,'.')>
<cfif len(attributes.hostkey)>
<cffile action = "Write" file = "#tempDir##attributes.host#" output = "#trim(attributes.hostkey)#" />
</cfif>
</cfif>
<cfelse>
<cffile action = "read" file = "#tempDir##attributes.host#" variable = "attributes.hostkey" />
</cfif>
</cfif>
<cfswitch expression = "#attributes.action#">
<!--- ************************************************************************ --->
<!--- get directory listing --->
<!--- ************************************************************************ --->
<cfcase value = "listdir">
<!--- ************************************************************************ --->
<!--- Save the listing script for the first time --->
<!--- ************************************************************************ --->
<cfif not fileExists("#tempDir#listDir.cfm")>
<cfset Content = '##<cfabort>#chr(10)#open sftp://%1%:%2%@%3% -hostkey="%5%"#chr(10)#ls "%4%"#chr(10)#exit'>
<cffile action = "Write" file = "#tempDir#listDir.cfm" output = "#trim(Content)#" />
</cfif>
<cfexecute
name = "#attributes.WinSCPPath#"
arguments = '/script=#tempDir#listDir.cfm /parameter "#attributes.username#" "#attributes.password#" "#attributes.host#" "#attributes.directory#" "#attributes.hostkey#"'
timeout ="#attributes.timeOut#"
variable = "return">
</cfexecute>
<!--- ************************************************************************ --->
<!--- Get the body --->
<!--- ************************************************************************ --->
<cfset start = findNoCase("Active session:", return)>
<cfif not val(start)>
<!--- ************************************************************************ --->
<!--- We have an error. show it --->
<!--- ************************************************************************ --->
<cfthrow type="Application" message="#listLast(return,chr(10))#" detail="#return#">
<cfexit method = "exitTag">
</cfif>
<cfset start = find(chr(10), return, start)>
<cfset body = trim(RemoveChars(return, 1, start))>
<cfset body = listToArray(body, chr(10))>
<!--- ************************************************************************ --->
<!--- format the body into a query --->
<!--- ************************************************************************ --->
<cfset q = QueryNew('longname,attributes,hardlinks,owner,name,length,lastModified,isdirectory')>
<cfloop array = "#body#" index = "i">
<cfset QueryAddRow(q)>
<cfset i = trim(i)>
<cfset QuerySetCell(q, 'longname', i)>
<cfset QuerySetCell(q, 'attributes', listGetAt(i,1,' '))>
<cfset QuerySetCell(q, 'hardlinks', listGetAt(i,2,' '))>
<cfset QuerySetCell(q, 'owner', listGetAt(i,3,' '))>
<cfset QuerySetCell(q, 'name', listlast(i,' '))>
<cfset QuerySetCell(q, 'length', listGetAt(i,5,' '))>
<cfif left(i,1) eq '-'>
<cfset QuerySetCell(q, 'isdirectory', false)>
<cfelse>
<cfset QuerySetCell(q, 'isdirectory', true)>
</cfif>
<cfset QuerySetCell(q, 'lastModified', ParseDateTime('#listGetAt(i,6,' ')# #listGetAt(i,7,' ')# #listGetAt(i,9,' ')# #listGetAt(i,8,' ')#'))>
</cfloop>
<cfset caller[attributes.name] = q>
<cfset caller.WinSCP = return>
</cfcase>
<!--- ************************************************************************ --->
<!--- getFile --->
<!--- ************************************************************************ --->
<cfcase value = "getFile">
<!--- ************************************************************************ --->
<!--- Save the get script for the first time --->
<!--- ************************************************************************ --->
<cfif not fileExists("#tempDir#getFile.cfm")>
<cfset Content = '##<cfabort>#chr(10)#option transfer binary#chr(10)#open sftp://%1%:%2%@%3% -hostkey="%4%"#chr(10)#get %5% %6%#chr(10)#exit'>
<cffile action = "Write" file = "#tempDir#getFile.cfm" output = "#trim(Content)#" />
</cfif>
<cfexecute
name = "#attributes.WinSCPPath#"
arguments = '/script=#tempDir#getFile.cfm /parameter "#attributes.username#" "#attributes.password#" "#attributes.host#" "#attributes.hostkey#" "#attributes.remoteFile#" "#attributes.localFile#"'
timeout ="#attributes.timeOut#"
variable = "return">
</cfexecute>
<cfset caller.WinSCP = return>
</cfcase>
<!--- ************************************************************************ --->
<!--- putfile --->
<!--- ************************************************************************ --->
<cfcase value = "putFile">
<cfif structKeyExists(attributes,'remoteFile')>
<cfif not right(attributes.remoteDirectory,'1') eq '/'>
<cfset attributes.remoteDirectory = attributes.remoteDirectory & '/'>
</cfif>
<cfset attributes.remoteDirectory = attributes.remoteDirectory & attributes.remoteFile>
</cfif>
<cfset attributes.localFile = replace(attributes.localFile,'/','\','all')>
<!--- ************************************************************************ --->
<!--- Save the get script for the first time --->
<!--- ************************************************************************ --->
<cfif yesNoFormat(attributes.secure)>
<cfif not fileExists("#tempDir#putFile.cfm")>
<cfset Content = '##<cfabort>#chr(10)#option transfer binary#chr(10)#open sftp://%1%:%2%@%3% -hostkey="%4%"#chr(10)#put %5% %6%#chr(10)#chmod %7% %6%#chr(10)#exit'>
<cffile action = "Write" file = "#tempDir#putFile.cfm" output = "#trim(Content)#" />
</cfif>
<cfset args = '/script=#tempDir#putFile.cfm /parameter "#attributes.username#" "#attributes.password#" "#attributes.host#" "#attributes.hostkey#" "#attributes.localFile#" "#attributes.remoteDirectory#" "#attributes.chmod#"'>
<cfelse>
<!--- ************************************************************************ --->
<!--- ftp --->
<!--- ************************************************************************ --->
<cfif not fileExists("#tempDir#putFile_ftp.cfm")>
<cfset Content = '##<cfabort>#chr(10)#option transfer binary#chr(10)#open ftp://%1%:%2%@%3% #chr(10)#put %4% %5%#chr(10)#exit'>
<cffile action = "Write" file = "#tempDir#putFile_ftp.cfm" output = "#trim(Content)#" />
</cfif>
<cfset args = '/script=#tempDir#putFile_ftp.cfm /parameter "#attributes.username#" "#attributes.password#" "#attributes.host#" "#attributes.localFile#" "#attributes.remoteDirectory#"'>
</cfif>
<cfexecute
name = "#attributes.WinSCPPath#"
arguments = '#args#'
timeout = "#attributes.timeOut#"
variable = "return">
</cfexecute>
<cfset caller.WinSCP = return>
</cfcase>
<!--- ************************************************************************ --->
<!--- rename file --->
<!--- ************************************************************************ --->
<cfcase value = "rename">
<cfif not fileExists("#tempDir#rename.cfm")>
<cfset Content = '##<cfabort>#chr(10)#open sftp://%1%:%2%@%3% -hostkey="%4%"#chr(10)#mv %5% %6%#chr(10)#exit'>
<cffile action = "Write" file = "#tempDir#rename.cfm" output = "#trim(Content)#" />
</cfif>
<cfif structKeyExists(attributes,'overwrite') and yesNoFormat(attributes.overwrite)>
<cfset attributes.item = attributes.new>
<cfset remove(attributes)>
</cfif>
<cfexecute
name = "#attributes.WinSCPPath#"
arguments = '/script=#tempDir#rename.cfm /parameter "#attributes.username#" "#attributes.password#" "#attributes.host#" "#attributes.hostkey#" "#attributes.existing#" "#attributes.new#"'
timeout ="#attributes.timeOut#"
variable = "return">
</cfexecute>
<cfset caller.WinSCP = return>
</cfcase>
<!--- ************************************************************************ --->
<!--- remove file --->
<!--- ************************************************************************ --->
<cfcase value = "remove">
<cfset caller.WinSCP = remove(attributes)>
</cfcase>
<!--- ************************************************************************ --->
<!--- check file exists --->
<!--- ************************************************************************ --->
<cfcase value = "exists">
<cfset r = exists(attributes)>
<cfset caller.exists = r.exists>
<cfset caller.WinSCP = r.WinSCP>
</cfcase>
</cfswitch>
<!--- ************************************************************************ --->
<!--- functions we need --->
<!--- ************************************************************************ --->
<cffunction name = "exists" access= "Public" output = "No" returntype= "Any">
<cfargument name= "a" required= "Yes" type= "any" />
<cfif not fileExists("#tempDir#exists.cfm")>
<cfset Content = '##<cfabort>#chr(10)#option failonnomatch on#chr(10)#open sftp://%1%:%2%@%3% -hostkey="%4%"#chr(10)#stat %5%#chr(10)#exit'>
<cffile action = "Write" file = "#tempDir#exists.cfm" output = "#trim(Content)#" />
</cfif>
<cfexecute
name = "#attributes.WinSCPPath#"
arguments = '/script=#tempDir#exists.cfm /parameter "#attributes.username#" "#attributes.password#" "#attributes.host#" "#attributes.hostkey#" "#attributes.item#"'
timeout ="#attributes.timeOut#"
variable = "return">
</cfexecute>
<cfset r.WinSCP = return>
<cfif findNoCase("No such file or directory", return)>
<cfset r.exists = 0>
<cfelse>
<cfset r.exists = 1>
</cfif>
<cfreturn r>
</cffunction>
<cffunction name = "remove" access= "Public" output = "No" returntype= "Any">
<cfargument name= "a" required= "Yes" type= "any" />
<cfif val( exists(arguments.a).exists )> <!--- file have to be exists for us to delete it --->
<cfif not fileExists("#tempDir#remove.cfm")>
<cfset Content = '##<cfabort>#chr(10)#open sftp://%1%:%2%@%3% -hostkey="%4%"#chr(10)#rm %5%#chr(10)#exit'>
<cffile action = "Write" file = "#tempDir#remove.cfm" output = "#trim(Content)#" />
</cfif>
<cfexecute
name = "#attributes.WinSCPPath#"
arguments = '/script=#tempDir#remove.cfm /parameter "#attributes.username#" "#attributes.password#" "#attributes.host#" "#attributes.hostkey#" "#attributes.item#"'
timeout ="#attributes.timeOut#"
variable = "return">
</cfexecute>
<cfreturn return>
</cfif>
<cfreturn ''>
</cffunction>
</cfcase>
</cfswitch>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment