Symfoware

Symfowareについての考察blog

Python + pyftpdlibでカスタムFTPサーバーを作成5 ファイルのアップロード

pyftpdlibで独自のFTPサーバーを作ってみています。
Python + pyftpdlibでカスタムFTPサーバーを作成4 データベース連携

ファイルのアップロードを試してみます。


close



アップロードされた内容をStringIOに退避。
closeが呼ばれたタイミングでデータベースに登録するようにしてみます。


  1. # -*- coding:utf-8 -*-
  2. from pyftpdlib.authorizers import AuthenticationFailed
  3. from pyftpdlib.handlers import FTPHandler
  4. from pyftpdlib.servers import FTPServer
  5. from cStringIO import StringIO
  6. import MySQLdb
  7. import datetime
  8. class MyAuthorizer(object):
  9.     
  10.     # ユーザー名、パスワードで認証
  11.     def validate_authentication(self, username, password, handler):
  12.         
  13.         msg = "Authentication failed."
  14.         
  15.         params = {
  16.             'name' : username,
  17.             'password' : password
  18.         }
  19.         
  20.         rows = execute(u'select id from user where name = %(name)s and password = %(password)s', params)
  21.         
  22.         if len(rows) != 1:
  23.             raise AuthenticationFailed(msg)
  24.     
  25.     # ユーザーのホームディレクトリを返す
  26.     def get_home_dir(self, username):
  27.         
  28.         params = { 'name' : username }
  29.         rows = execute(u'select id from user where name = %(name)s', params)
  30.         
  31.         return unicode(rows[0]['id'])
  32.     
  33.     # アクセス権限チェック
  34.     def has_perm(self, username, perm, path=None):
  35.         return 'elr'
  36.     
  37.     def get_perms(self, username):
  38.         return 'elr'
  39.     
  40.     # ログイン時に表示するメッセージ
  41.     def get_msg_login(self, username):
  42.         return 'Login successful.'
  43.     
  44.     # ログアウト時に表示するメッセージ
  45.     def get_msg_quit(self, username):
  46.         return 'Goodbye.'
  47.         
  48.     # ファイルにアクセスする前のフック
  49.     def impersonate_user(self, username, password):
  50.         pass
  51.     
  52.     # ファイルにアクセスした後のフック
  53.     def terminate_impersonation(self, username):
  54.         pass
  55.         
  56. class MyFileSystem(object):
  57.     
  58.     def __init__(self, root, cmd_channel):
  59.         self._cwd = u'/'
  60.         self._root = root
  61.         self.cmd_channel = cmd_channel
  62.     
  63.     # 現在のカレントディレクトリ
  64.     @property
  65.     def cwd(self):
  66.         return self._cwd
  67.         
  68.     # ftp要求パスをリアルパスに変換
  69.     def ftp2fs(self, ftppath):
  70.         return ftppath
  71.     
  72.     # 要求パスの妥当性検証
  73.     def validpath(self, path):
  74.         return True
  75.     
  76.     
  77.     # 指定されたパスがディレクトリであるか
  78.     def isdir(self, path):
  79.         return True
  80.     
  81.     # ディレクトリの内容をリストアップ
  82.     def listdir(self, path):
  83.         
  84.         if path == '/':
  85.             query = u"select name from folder where owner = %(owner)s"
  86.             rows = execute(query, {'owner':self._root})
  87.             dir_list = []
  88.             for row in rows:
  89.                 dir_list.append(row['name'])
  90.             
  91.             return dir_list
  92.         
  93.         folder_id = self._get_folder_id(path)
  94.         query = u"select id from image where folder_id = %(folder_id)s"
  95.         rows = execute(query, {'folder_id':folder_id})
  96.         dir_list = []
  97.         for row in rows:
  98.             dir_list.append(u'%(id)s.jpg' % row)
  99.         
  100.         return dir_list
  101.         
  102.     # フォーマット済の内容を返す
  103.     def format_mlsx(self, basedir, listing, perms, facts, ignore_err=True):
  104.         
  105.         if basedir == '/':
  106.         
  107.             query = u"select id, date_format(maketime, '%%Y%%m%%d%%k%%i%%s') as modify, name from folder where owner = %(owner)s"
  108.             
  109.             rows = execute(query, {'owner':self._root})
  110.             for row in rows:
  111.                 line = u'type=dir;size=0;perm=el;modify=%(modify)s; %(id)s.%(name)s\r\n' % row
  112.                 yield line.encode('utf8', self.cmd_channel.unicode_errors)
  113.         
  114.         else:
  115.             
  116.             folder_id = self._get_folder_id(basedir)
  117.             query = u"select id, date_format(maketime, '%%Y%%m%%d%%k%%i%%s') as modify, size from image where folder_id = %(folder_id)s"
  118.             rows = execute(query, {'folder_id':folder_id})
  119.             for row in rows:
  120.                 line = u'type=file;size=%(size)s;perm=r;modify=%(modify)s; %(id)s.jpg\r\n' % row
  121.                 yield line.encode('utf8', self.cmd_channel.unicode_errors)
  122.         
  123.         #line = u'type=dir;size=0;perm=el;modify=20071127230206; 1\r\n'
  124.         #yield line.encode('utf8', self.cmd_channel.unicode_errors)
  125.         
  126.         #line = u'type=file;size=202103;perm=r;modify=20071029155301; 2.png\r\n'
  127.         #yield line.encode('utf8', self.cmd_channel.unicode_errors)
  128.     
  129.     
  130.     def _get_folder_id(self, path):
  131.         folder_name = path.split('/')[-1]
  132.         folder_id = folder_name.split('.')[0]
  133.         return folder_id
  134.     
  135.     
  136.     def chdir(self, path):
  137.         
  138.         if path.startswith(u'/'):
  139.             self._cwd = path
  140.             return
  141.         
  142.         if path == '..':
  143.             dirs = self._cwd.split('/')
  144.             print dirs
  145.             self._cwd = u'/'.join(dirs)
  146.         else:
  147.             self._cwd += path
  148.         
  149.         
  150.     def open(self, filename, mode):
  151.         
  152.         # 読み取り要求の場合
  153.         if mode.find('r') != -1:
  154.         
  155.             image_id = filename.split('.')[0]
  156.             query = u"select id,data from image where id = %(image_id)s"
  157.             row = execute(query, {'image_id':image_id})[0]
  158.             
  159.             # nameプロパティが必要なのでラップする
  160.             class FileWrapper(object):
  161.                 def __init__(self, row):
  162.                     self.file = StringIO()
  163.                     self.file.write(row['data'])
  164.                     self.file.seek(0)
  165.                         
  166.                     self.name = u'%(id)s.jpg' % row
  167.                 def __getattr__(self, attr):
  168.                     return getattr(self.file, attr)
  169.                 
  170.             return FileWrapper(row)
  171.         
  172.             
  173.         # 書き込み要求の場合
  174.         class FileWrapper(object):
  175.             def __init__(self, owner_id, folder_id):
  176.                 self.file = StringIO()
  177.                 self.owner_id = owner_id
  178.                 self.folder_id = folder_id
  179.                 self.name = u'dummy.jpg'
  180.             def __getattr__(self, attr):
  181.                 return getattr(self.file, attr)
  182.                 
  183.             # closeが呼び出された時にデータベースへ登録する
  184.             def close(self):
  185.                 query = u'insert into image (folder_id, maketime, size, data) values (%s, %s, %s, %s)'
  186.                 data = self.file.getvalue()
  187.                 execute(query, [self.folder_id, datetime.datetime.now(), len(data), data])
  188.                 
  189.             
  190.         return FileWrapper(self._root, self._get_folder_id(self.cwd))
  191.     
  192.     
  193. def execute(query, params):
  194.     con = MySQLdb.connect(
  195.         host='192.168.1.110',
  196.         db='ftp',
  197.         user='admin',
  198.         passwd='P@ssw0rd',
  199.         charset='utf8')
  200.     cur = con.cursor(MySQLdb.cursors.DictCursor)
  201.     
  202.     cur.execute(query, params)
  203.     
  204.     rows = []
  205.     for row in cur:
  206.         rows.append(row)
  207.     
  208.     con.commit()
  209.     
  210.     cur.close()
  211.     con.close()
  212.     
  213.     return rows
  214. def main():
  215.     
  216.     # 認証用のオブジェクトを作成
  217.     authorizer = MyAuthorizer()
  218.     #authorizer = DummyAuthorizer()
  219.     # id:user,pass:12345というユーザーを作成 操作権限(perm)は全て与える
  220.     #authorizer.add_user('symfo', 'pass', '.', perm='elradfmwM')
  221.     # FTP通信のハンドラーを作成 ユーザー認証オブジェクトを設定する
  222.     handler = FTPHandler
  223.     handler.authorizer = authorizer
  224.     # 接続時に表示される文字列指定
  225.     handler.banner = "pyftpdlib based ftpd ready."
  226.     
  227.     # 使用するファイルシステム
  228.     handler.abstracted_fs = MyFileSystem
  229.     # ftpサーバーのポートを指定
  230.     address = ('localhost', 10021)
  231.     server = FTPServer(address, handler)
  232.     # サーバー起動
  233.     server.serve_forever()
  234. if __name__ == '__main__':
  235.     main()




openメソッドでひと工夫。
読み込みモードの時は、データベースからデータを取得。

書き込みモードの時は、StringIOのインスタンスを生成。
closeが呼び出された時にデータベースへの登録を実行します。


あっけないぐらい簡単に実装できました。

529_01.png

ライブラリの設計が良いと、カスタムするのも楽で良いです。
関連記事

テーマ:プログラミング - ジャンル:コンピュータ

  1. 2015/01/18(日) 15:23:32|
  2. Python
  3. | トラックバック:0
  4. | コメント:0
  5. | 編集
<<Python 実行しているスクリプトの絶対パスを取得する | ホーム | Python + pyftpdlibでカスタムFTPサーバーを作成4 データベース連携>>

コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック

トラックバック URL
http://symfoware.blog68.fc2.com/tb.php/1587-1e430e12
この記事にトラックバックする(FC2ブログユーザー)