Automating file transfer via FTP over TLS using Python

By Jan 26, 2016

Description:

Automating file transfer via FTP over TLS using Python

Preferencesoft

In this article, we will see how to transfer files from a local computer to a remote server via a FTPS connection.

The goal is to automate file transfers with scripts in Python on Windows.

Introduction

On Windows, there is no basic software to perform secure FTP transfers. There is, however, paid or free solutions.

The language Python 3.5 has a library ftplib.py for FTP with TLS connections.

But it is necessary to modify the ftplib.py file, if we want to write a file on an IIS server.

Indeed, the storbinary function hangs up unexpectedly when run.

So, let's start by placing it in comment lines 512 and 513 of ftplib.py.

511: # shutdown ssl layer

512: #  if _SSLSocket is not None and isinstance(conn, _SSLSocket):
513: #      conn.unwrap()

the problem has already been reported by http://www.sami-lehtinen.net/blog/python-32-ms-ftps-ssl-tls-lockup-fix

Scripts in Python

This first script to display the list of files in a directory of the remote server.

from ftplib import FTP_TLS
import sys, os
    
destdir="/rootdir/blog"
    
ftps = FTP_TLS('kodfor.com')
ftps.set_debuglevel(1)
ftps.set_pasv(False)
ftps.connect(port=21, timeout=80)
ftps.login('mylogin', 'password')
ftps.prot_p()
ftps.ccc()
ftps.cwd(destdir)
ftps.pwd()
ftps.retrlines('LIST')
ftps.close()

This second script copy recursively the content of a local directory named flac to a directory on the remote server.

from ftplib import FTP_TLS
import sys, os
import os.path
    
root="C:\\Users\\kodfor\\Documents\\mypython\\flac"
destdir="/rootdir/flac"
    
ftps = FTP_TLS('kodfor.com')
ftps.set_debuglevel(1)
ftps.set_pasv(False)
ftps.connect(port=21, timeout=80)
ftps.login('mylogin', 'password')
ftps.prot_p()
ftps.ccc()
try:
       ftps.cwd(destdir)
except Exception:
       ftps.mkd(destdir)
for (dir, _, files) in os.walk(root):
       newdir=destdir+dir[len(root):len(dir)].replace("\\","/")
       try:
               ftps.cwd(newdir)
       except Exception:
               ftps.mkd(newdir)
       for f in files:
               file = open(os.path.join(dir, f),'rb')
               ftps.storbinary('STOR '+f, file,blocksize=8192)
               file.close()
ftps.close()

This last script removes a directory named blog with all its contents.

 

from ftplib import FTP_TLS
import sys, os
import os.path

destdir="/rootdir"
rootdir = "blog"

def crossdel(ftps, curdir):
       ftps.cwd(curdir)
       l=ftps.nlst()
       lines = []
       ftps.retrlines('LIST', lines.append)
       dirlist = []
       filelist = []
       for i in range(len(l)):
               if lines[i].find("<DIR>")>0:
                       dirlist.append(l[i])
               else:
                       filelist.append(l[i])
       for f in filelist:
               ftps.delete(f)
       for d in dirlist:
               print('dir',d)
               crossdel(ftps, d)
       p = ftps.pwd()
       pl = p.split('/')
       dd = pl[len(pl)-1]
       ftps.sendcmd('CDUP')
       if p!=destdir:
               ftps.rmd(dd)

ftps = FTP_TLS('kodfor.com')
ftps.set_debuglevel(1)
ftps.set_pasv(False)
ftps.connect(port=21, timeout=80)
ftps.login('mylogin', 'password')
ftps.prot_p()
ftps.ccc()
ftps.cwd(rootdir)
crossdel(ftps, rootdir)
ftps.close()

You still must change the connections settings and the different names of the directories.

Now write a python script to run multiple commands on the remote server in the same session.
We want to be able to call this script by passing a string containing commands, so that it executes them.
For that we pick most of the FTP commands. Commands can be separated in the string by a semicolon “;” or a carriage return \n.

The commands are:

  • *      cwd Change working directory on the remote server

  • *      dele Delete file

  • *      mkd Make directory

  • *      ren Rename file

  • *      rmd Remove a directory

  • *      stor store the data as a binary file at the server site

  • *      nop no operation

ftpcon.py

from ftplib import FTP_TLS
import sys, os
import re


def cwd(ftps, destdir, none):
       ftps.cwd(destdir)
def stor(ftps, srcfile, fileNameOnServer):
       ext = os.path.splitext(srcfile)[1]
       if ext in (".txt", ".htm", ".html"):
             file = open(srcfile)
             ftps.storlines("STOR " + fileNameOnServer, file)
       else:
             file = open(srcfile,'rb')
             ftps.storbinary('STOR ' + fileNameOnServer, file, blocksize=8192)         
       file.close()

def rmd(ftps, dirname, other):
       ftps.rmd(dirname)
def mkd(ftps, dirname, other):
       ftps.mkd(dirname)
def dele(ftps, file, other):
       ftps.delete(file)   
def ren(ftps, fromname, toname):
       ftps.rename(fromname, toname)
def nop(ftps, any, other):
       None


functions = [cwd, dele, mkd, ren, rmd, stor, nop, nop]
keywords = ["cwd", "dele", "mkd", "ren", "rmd", "stor", "nop", ""]

script = sys.argv[1]
#print(script)
script += ';'
pat = re.compile("[\n\r;]+")
script = re.sub(pat, ';', script)
pat = re.compile("[\s]+")
script = re.sub(pat, ' ', script)
instruction_list = script.split(';')
#print(instruction_list)
destdir="/rootdir"
ftps = FTP_TLS('xxxxxxxxxxxxx.1and1-data.host')
ftps.set_debuglevel(0)
ftps.set_pasv(False)
ftps.connect(port=21, timeout=80)
ftps.login('mylogin', 'password')
ftps.prot_p()
ftps.ccc()
ftps.cwd(destdir)
ftps.pwd()
#ftps.retrlines('LIST')
for i in instruction_list:
       op = i.split(' ')
       instr = "no"
       arg1 = ""
       arg2 = ""
       l = len(op)
       if l > 0:
             instr = keywords.index(op[0])
       if l > 1:
             arg1 = op[1]
       if l > 2:
             arg2 = op[2]
       #print(">>> " + keywords[instr] +' ' + arg1 + ' ' + arg2)
       try:
             functions[instr](ftps, arg1, arg2)
       except Exception:
             print("Error in %s" % keywords[instr])
#ftps.retrlines('LIST')
ftps.close()

 

Try to call this script from the PowerShell:

test.ps1

$commands = "
cwd Images;
dele circle.png
stor C:\Users\TheUser\Documents\kodfor\Images\circle.png circle.png;
cwd ..
cwd Algorithm
dele image001.gif;
dele image002.jpg;
dele image003.jpg;
ren image004.jpg image001.jpg
"

echo $commands
C:\Python\Python36-32\python.exe ftpcon.py $commands

 


Python

Categories

Share

Follow


KodFor Privacy Policy