質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

1回答

15550閲覧

HTMLでアップロードされたファイルを保存するCGIスクリプトを作成するにはどうすればいいでしょうか

mmss

総合スコア46

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

2グッド

2クリップ

投稿2017/10/01 01:08

以下のサイトを参考に、HTMLからアップロードされたfileを受け取り保存するCGIスクリプトをpythonで作成したいと考えております。
http://www.gesource.jp/programming/python/cgi/0115.html

しかしながらいざ実行してみると、HTMLはちゃんと作成できファイル送信フォームも生成できたのですが、送信すると以下のエラーが出てしまいます。

Error response
Error code: 501
Message: Can only POST to CGI scripts.
Error code explanation: 501 - Server does not support this operation.

test15.html

html

1<html> 2<head> 3 <meta http-equiv="Content-Type" content="text/html" charset="UTF-8" /> 4 <title>ファイルをアップロードする</title> 5</head> 6<body> 7<h1>ファイルをアップロードする</h1> 8<p>%s</p> 9<form action="test15.cgi" method="post" enctype="multipart/form-data"> 10 <input type="file" name="file" /> 11<input type="submit" /> 12</form> 13</body> 14</html>

test15.cgi

python

1import cgi 2import os, sys 3 4try: 5 import msvcrt 6 msvcrt.setmode(0, os.O_BINARY) 7 msvcrt.setmode(1, os.O_BINARY) 8except ImportError: 9 pass 10 11result = '' 12form = cgi.FieldStorage() 13if form.has_key('file'): 14 item = form['file'] 15 if item.file: 16 fout = file(os.path.join('/tmp', item.filename), 'wb') 17 while True: 18 chunk = item.file.read(1000000) 19 if not chunk: 20 break 21 fout.write(chunk) 22 fout.close() 23 result = 'アップロードしました。' 24 25print html % result 26print("upload is done") 27 28```---------------------------- 29 30 31当方、CGIについて最近勉強したばかりで筋違いな質問であれば大変申し訳ないです。 32HTMLで送信したファイルがtmpフォルダに保存されるようなCGIを作りたいと考えております。 33何卒、よろしくお願いいたします。
taro373👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

こんにちは。

サーバーがステータス501を返しているので、cgiスクリプトが正しく動作して
いないようです。ご提示のコードですと、何点か問題ありそうでした。

  1. 1行目でシバン(Shebang)にてスクリプトが指定されていないので、

pythonスクリプトとして動作できない。

  1. 日本語部分があるので、文字コードを指定しないと文字化けの恐れがある。
  2. HTTPレスポンスとして返す時のContent-Type が指定されていない。
  3. 'html' 変数に初期値が設定(宣言)されていない。未定義変数エラー。

プログラムを造ってサーバーに設置したときは、cgiとしてサーバーに
実行させる前に端末上で文法チェックしてみると良いです。

以下で簡単に文法チェックすることができます。
(もちろん、実行時のエラーはこれでは分かりません)

$ python -m py_compile test15.cgi

ご提示のコードですが、以下のように直すことで動作しました。
確認用のコードを残していますので、差分を取って比較してみてください。
尚、文字コードはutf-8で保存してください。

python2

1#!/usr/bin/env python 2# -*- coding: utf-8 -*- 3 4import cgi 5import os, sys 6 7try: 8 import msvcrt 9 msvcrt.setmode(0, os.O_BINARY) 10 msvcrt.setmode(1, os.O_BINARY) 11except ImportError: 12 pass 13 14result = 'DUMMY' 15form = cgi.FieldStorage() 16if form.has_key('file'): 17 item = form['file'] 18 if item.file: 19 fout = file(os.path.join('/tmp', item.filename), 'wb') 20 while True: 21 chunk = item.file.read(1000000) 22 if not chunk: 23 break 24 fout.write(chunk) 25 fout.close() 26 #result = 'upload is done' 27 result = 'アップロード' 28 29#print html % result 30 31print "Content-Type: text/html" 32print 33html = "<html><body>%s</body><html>" 34print html % result 35

###python3に関して追記
python3 でのご質問だったのかもしれませんので、すみませんが以下、追記させていただきます。

参考にされたサイト様のサンプルプロはpython2 のものです。
私が提示したコードもpython2 のものなので、サーバー上でpython3でcgiを
稼動させる場合、文法エラーで動作しません。
コードをpython3でほぼ等価なものに書き直し、動作確認したものを以下に示します。
※「アップロード」の部分はそのままだとエラーになり、
コードが煩雑になるのでASCII文字列に直させてもらいました。

今後pythonでcgiを造られる場合は、バージョンの違いに注意する必要があるかとは思います。

python3

1#!/usr/bin/python3 2# -*- coding: utf-8 -*- 3import cgi 4import os, sys 5 6try: 7 import msvcrt 8 msvcrt.setmode(0, os.O_BINARY) 9 msvcrt.setmode(1, os.O_BINARY) 10except ImportError: 11 pass 12 13result = 'DUMMY' 14form = cgi.FieldStorage() 15#if form.has_key('file'): 16if 'file' in form: 17 item = form['file'] 18 if item.file: 19# fout = file(os.path.join('/tmp', item.filename), 'wb') 20 fout = open(os.path.join('/tmp', item.filename), 'wb') 21 while True: 22 chunk = item.file.read(1000000) 23 if not chunk: 24 break 25 26 fout.write(chunk) 27 fout.close() 28 result = 'upload is done' 29 #result = "アップロード" 30 31print("Content-Type: text/html") 32print("") 33html = "<html><body>{0}</body><html>" 34print(html.format(result))

投稿2017/10/01 02:17

編集2017/10/01 03:39
dodox86

総合スコア9183

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mmss

2017/10/01 03:40 編集

早速ご回答いただき、たいへんありがとうございます。 大変恐縮ですが、ご教授いただいたCODEで修正しても依然として同じエラーが出てしまいましたので、再度ご助力いただけますと幸いです。 ご教授いただいた文法チェックのCODEを試してみたところ、とくに問題なさそうでしたので恐らくCODE以前の問題ではないかと考えております。 C:\server>python -m py_compile test15.cgi 例えば、フォルダ構成が以下のようになっておりますが、特に問題ございませんでしょうか。 server -- test15.html -- test15.cgi -- cgi-bin -- test15.cgi , tmp ※test15.cgiはどこに置けば起動するかわからなかったため、同じものを2つserverとcgi-binに置いております。 また、サーバーに関してはコマンドプロンプトに以下のCODEを入力して構築しております。 C:\server>python -m http.server --cgi Serving HTTP on 0.0.0.0 port 8000 ... 127.0.0.1 - - [01/Oct/2017 12:28:41] "GET / HTTP/1.1" 200 - 127.0.0.1 - - [01/Oct/2017 12:28:43] "GET /test15.html HTTP/1.1" 200 - 127.0.0.1 - - [01/Oct/2017 12:28:49] code 501, message Can only POST to CGI scripts 127.0.0.1 - - [01/Oct/2017 12:28:49] "POST /test15.cgi HTTP/1.1" 501 - 何卒、よろしくお願いいたします。
dodox86

2017/10/01 03:43

コメントが僅差ですれ違いました。python のバージョンをご確認ください。python3ですと、前のコードは動作しません。
dodox86

2017/10/01 03:48

Windowsをお使いでしたか。でしたら、tmp ディレクトリの位置も問題です。 os.path.join('/tmp' の部分で、'/tmp'では無く、Windowsでの書き込み可能ディレクトリPATHを指定してください。
mmss

2017/10/01 04:22

大変ご丁寧な返答、誠にありがとうございます。 大変恐縮ですが、書き込み可能なディレクトリ作成方法を色々調べておりますので、少々お待ちいただければと思います。
mmss

2017/10/01 07:00

書き込み可能なwriteディレクトリを作成し、以下のように変更してみたのですがまたもや同じエラーでした。。。 fout = open(os.path.join('C:\server\cgi-bin\write', item.filename), 'wb') フォルダの属性を表示させるとD(ディレクトリ属性)A(アーカイブ属性)となっておりR(読み出し属性、書き込み禁止)がなかったため書き込みはできるものと思われますが、他に気になる点とうございませんでしょうか。
dodox86

2017/10/01 07:34

こちらのcygwin環境下でも問題が再現しました。 "POST /test15.cgi HTTP/1.1" 501 -" の部分のアクセスログを見落としていましたが、 cgi-bin/の下のtest15.cgi を動かす必要があります。test15.html を直してください。 具体的には<form action="test15.cgi" の部分を、"cgi-bin/test15.cgi" にします。 cgi-bin/下でないと、cgi用のハンドラーを動かさないようになっていると思われます。
mmss

2017/10/01 08:56

度重なりご丁寧な対応、ありがとうございます。 ご教授の通りにaction=""の点を修正したところ今までのエラーが出なくなりました!! 本当にありがとうございます。 とはいえ、どうやら私の利用しているpythonが32bitであるせいか、以下のエラーが出てしまいまだ上手くはいきませんが、、、 OSError: [WinError 193] %1 は有効な Win32 アプリケーションではありません。 とはいえ、CODE上の問題はすべて上手くいきそうですので、あとは自身の開発環境を組みなおして頑張ってみたいと思います!!本当にありがとうございました!!
dodox86

2017/10/01 09:26

進展があり、的外れではなかったようで安心しました。今回のケースのデバッグですが、スクリプト中で標準エラー出力にprintすることでアクセスログの方に出ます。例えば print("STEP#1: ", file=sys.stderr) と記述すると、アクセスログには 127.0.0.1 - - [01/Oct/2017 18:16:53] "POST /cgi-bin/test17.cgi HTTP/1.1" 200 - STEP#1: のように出ますので、デバッガーを用意するのが大変な場合は代替策のひとつになります。また、Windows環境では '/tmp'の代わりに TEMP環境変数で出力されるディレクトリが書き込み可能です。 書き込み可能なディレクトリを新設するのが難しい場合、コンソール(コマンドプロンプト)上で C> echo %TEMP% で表示されたディレクトリを'/tmp'の代わりに利用することもできます。ご参考まで。
dodox86

2017/10/01 09:31

%TEMP%で示されるディレクトリは他のWindowsアプリも使用しているので、既にたくさんのファイルがあるかもしれません。競合しないようファイル名に注意してください。その下に更に専用のディレクトリを作って、そこに保存する方法がおすすめです。
mmss

2017/10/01 09:39

ご丁寧にアドバイスまでいただき恐縮です。 書き込み可能、のところも少々疑心暗鬼でしたので、ぜひご教授いただいたアドバイスを利用させていただきます!!何から何までご助力いただき、誠にありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問