HDEラボの桜井です。
3月寒いっす。
なんとなく、困ったことがあります。
pythonでzipファイルをWebブラウザ経由でダウンロードさせるプログラムを作り、
さらにそのダウンロードじたzipファイルを再びアップロードするプログラムを作ったところ、
なんと、アップロード時に正しいzipファイルと認識されなかったのである。
問題のプログラムを見てみよう。
test.cgi
それから、テンプレートファイル(テンプレートの詳細はこちら)
./template/test.html
3月寒いっす。
なんとなく、困ったことがあります。
pythonでzipファイルをWebブラウザ経由でダウンロードさせるプログラムを作り、
さらにそのダウンロードじたzipファイルを再びアップロードするプログラムを作ったところ、
なんと、アップロード時に正しいzipファイルと認識されなかったのである。
問題のプログラムを見てみよう。
test.cgi
#!/usr/bin/env python # -*- coding: utf-8 -*- import zipfile, cgi, os, shutil import web.template form = cgi.FieldStorage() command = form.getfirst('command', '') message = "" error = 0 if command == "backup": zip = zipfile.ZipFile("/tmp/test.zip", 'w', zipfile.ZIP_DEFLATED) zip.write("/tmp/file1", "file1") zip.close() print "Content-Type: application/zip;\r\nContent-Disposition: attachment; filename=test.zip\r\n\r\n", f = open("/tmp/test.zip") print f.read(), f.close() os.unlink("/tmp/test.zip") else: if command == "restore": if form.has_key('zip'): item = form['zip'] if item.file: try: tmpFileObj = file("/tmp/test2.zip", 'wb') shutil.copyfileobj(item.file, tmpFileObj) tmpFileObj.close() os.chmod("/tmp/test2.zip", 0777) except Exception, ex: error = 1 message = "ファイルのアップロードに失敗しました" else: error = 1 message = "ファイルが選択されていません" else: error = 1 message = "ファイルが選択されていません" if error == 0 and zipfile.is_zipfile("/tmp/test2.zip"): zip = zipfile.ZipFile("/tmp/test2.zip") for name in zip.namelist(): f = open("/tmp/" + name, 'w') f.write(zip.read(name)) f.close() zip.close() os.unlink(tmpPath + file) message = "復元しました" else: error = 1 message = "復元できませんでした" os.unlink("/tmp/test2.zip") values = { "command" : command, "message" : message, "error" : error } render = web.template.render("./template") print 'Content-Type: text/html; charset=utf-8' print '' print render.test(values)
それから、テンプレートファイル(テンプレートの詳細はこちら)
./template/test.html
$def with (values) <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" id="sixapart-standard"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>zipダウンロードとアップロード</title> </head> <body> <h2>zipダウンロード</h2> $if values["command"] == "backup": $if values["error"] == 1: <h3><font color="red">$values["message"]</font></h3> $else: <h3>$values["message"]</h3> <form action="backup.cgi" method="POST"> <input type="hidden" name="command" value="backup"> <input type="submit" value="設定ファイルをバックアップする"> </form> <hr> <h2>zipアップロード</h2> $if values["command"] == "restore": $if values["error"] == 1: <h3><font color="red">$values["message"]</font></h3> $else: <h3>$values["message"]</h3> <form action="backup.cgi" method="POST" ENCTYPE="multipart/form-data"> <input type="hidden" name="command" value="restore"> バックアップファイル(ZIP形式):<input type="file" name="zip"><br/> <input type="submit" value="設定ファイルを復元する"> </form> </body></html>
こうするとどうなるかというと、ダウンロードした際にWebブラウザがzipファイルの末尾に改行コードを付けて保存するのです。
また、pythonのzipfileモジュールは、厳密にzipファイルをチェックしているようで、この改行コードがあるだけでzipファイルだとはみなしてくれません。
よって、アップロード時にはエラーになり「復元できません」の表示が出るのです。
解決策をいろいろ考えましたが、ダウンロード時にWebブラウザが改行を付加しない方法が思いつかなかったので、アップロード時に末尾の改行を1バイト削る方向で対応してみました。
下記のコードです。
#!/usr/bin/env python # -*- coding: utf-8 -*- import zipfile, cgi, os, shutil import web.template form = cgi.FieldStorage() command = form.getfirst('command', '') message = "" error = 0 if command == "backup": zip = zipfile.ZipFile("/tmp/test.zip", 'w', zipfile.ZIP_DEFLATED) zip.write("/tmp/file1", "file1") zip.close() print "Content-Type: application/zip;\r\nContent-Disposition: attachment; filename=test.zip\r\n\r\n", f = open("/tmp/test.zip") print f.read(), f.close() os.unlink("/tmp/test.zip") else: if command == "restore": if form.has_key('zip'): item = form['zip'] if item.file: try: tmpFileObj = file("/tmp/test2.zip", 'wb') shutil.copyfileobj(item.file, tmpFileObj) tmpFileObj.close() # めっちゃ泥臭いですが、強引に改行を削ります tmpFileObj2 = open("/tmp/test2.zip", 'r') tmpFileStr = tmpFileObj2.read() tmpFileObj2.close() tmpFileObj3 = open("/tmp/test2.zip", 'w') tmpFileObj3.write(tmpFileStr.rstrip()) tmpFileObj3.close() os.chmod("/tmp/test2.zip", 0777) except Exception, ex: error = 1 message = "ファイルのアップロードに失敗しました" else: error = 1 message = "ファイルが選択されていません" else: error = 1 message = "ファイルが選択されていません" if error == 0 and zipfile.is_zipfile("/tmp/test2.zip"): zip = zipfile.ZipFile("/tmp/test2.zip") for name in zip.namelist(): f = open("/tmp/" + name, 'w') f.write(zip.read(name)) f.close() zip.close() os.unlink("/tmp/test2.zip") message = "復元しました" else: error = 1 message = "復元できませんでした" os.unlink(tmpPath + tmpFile) values = { "command" : command, "message" : message, "error" : error } render = web.template.render("./template") print 'Content-Type: text/html; charset=utf-8' print '' print render.test(values)
もっと素敵な方法があったら知りたいもんです、マジで。
Leave a comment