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

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

新規登録して質問してみよう
ただいま回答率
85.51%
CGI

CGI(Common Gateway Interface)とは、Webサーバー上でユーザプログラム動作させる仕組みのこと。また、動かす前提のプログラムをCGIと呼ぶこともあります。HTMLなどの静的な情報に限らず、プログラムの処理結果をベースにした動的情報の提供が可能です。

Python 3.x

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

Q&A

解決済

1回答

3137閲覧

pythonでcgiを書いて登録フォームを作成したが、文字化けする

yamatail

総合スコア77

CGI

CGI(Common Gateway Interface)とは、Webサーバー上でユーザプログラム動作させる仕組みのこと。また、動かす前提のプログラムをCGIと呼ぶこともあります。HTMLなどの静的な情報に限らず、プログラムの処理結果をベースにした動的情報の提供が可能です。

Python 3.x

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

0グッド

0クリップ

投稿2020/04/22 08:28

編集2020/04/22 15:08

前提・実現したいこと

登録フォームを作っています。
文字コードは、utf-8で統一したいと思っています。
index.htmlは、terapadを用いて文字コードもutf-8で作成しましたので、
最初の確認ページは、pythonで書いたcgiでformの日本語(「name='姓'」や「name='名'」)も認識できております(日本語あってるかな??)

しかし、その次のページに行くと日本語(「name='姓'」や「name='名'」)が認識されなくなってしまいます。
「姓」「名」が「None」「None」になってします。

pythonでかいたcgiの中のdef checkScreen内のヒアドキュメントで書いている部分がutf-8でないのが原因かなと思っているのですが、どうすればうまくいくかわかりません。

かなり分かりにくい日本語で申し訳ありませんが、何かアドバイスいただけると助かります。

発生している問題・エラーメッセージ

文字コードが統一できない

該当のソースコード

indexhtml

1 2<meta charset="UTF-8"> 3<div id="main"> 4<!---------------------------------------------------------> 5 6<div id="invisible"> 7<!---------------------------------------------------------> 8<div class="bar">Testフォーム</div> 9 10<form name="myForm" method="post" action="cgi-bin/test.py"> 11 12<table> 13 <tr> 14 <td>氏名 :</td> 15 <td><input type="text" name="姓" size="12"> <input type="text" name="名" size="12"></td> 16 </tr> 17</table> 18<br> 19<div align="center"> 20<input type="submit" value="入力内容の確認"> <input type="reset" value="リセット"> 21</div> 22</form> 23 24 25</div><!-- makeup 終わり --> 26</div><!-- main 終わり --> 27

python

1# -*- coding: utf-8 -*- 2""" 3Created on Tue Feb 19 16:33:29 2019 4 5""" 6import cgi 7import cgitb 8cgitb.enable() 9 10import sys 11sys.stdout.reconfigure(encoding='utf-8') 12 13 14""" --- データの受け取り --- """ 15param = cgi.FieldStorage() 16param_dict = param.list 17 18# ユーザー姓(メール件名に表記) 19Sei = param.getvalue('姓') 20 21# ユーザー名(メール件名に表記) 22Mei = param.getvalue('名') 23 24""" --- 内容確認画面 --- """ 25def checkScreen(): 26 mail_table = '' 27 for i in param_dict: 28 if i.name != '': 29 param_i = param.getvalue(i.name) 30 else: 31 param_i = '' 32 mail_table += '<tr><th>' + i.name + '</th><td class=\"a\">' + param_i + '<input type=\"hidden\" name=\"' + i.name + '\" value=\"' + param_i + '\"></td></tr>\n' 33 34 """ --- ヒアドキュメント --- """ 35 36 import textwrap 37 38 string = textwrap.dedent(''' 39 Content-type: text/html 40 41 <html><head> 42 <title>FormMail</title> 43 <style type="text/css"> 44 <!-- 45 table{{ 46 border: none; 47 }} 48 td{{ 49 font-size: 14px; 50 }} 51 table.a{{ 52 border: 1px #888888 solid; 53 border-collapse: collapse; 54 }} 55 th{{ 56 width: 120px; 57 text-align: left; 58 font-size: 14px; 59 background-color: #fffacd; 60 padding: 5px 10px; 61 border: 1px #888888 solid; 62 font-weight: normal; 63 }} 64 td.a{{ 65 padding: 5px 10px; 66 border: 1px #888888 solid; 67 font-size: 14px; 68 }} 69 .font12 {{ font-size: 12px; }} 70 a {{ color: #0033CC; }} 71 a:hover {{ color: #CC0000; }} 72 }} 73 --> 74 </style> 75 </head> 76 77 <body bgcolor="#FFFFFF" text="#000000"> 78 <table width="600" align="center"> 79 <tr> 80 <td><br><b><font size="4">確認画面</font></b><br><br></td> 81 </tr> 82 83 <tr> 84 <td> 85 ※入力した内容を確認してください。 86 <br> 87 88 <form method="post" action="test.py"> 89 <input type="hidden" name="mode" value="check"> 90 91 <table class="a" border="1" width="580"> 92 {mail_table} 93 </table> 94 95 <br> 96 <input type="submit" value=" 確 認 "> 97 <input type="button" value="もどる" onClick="JavaScript:history.back()"><br><br> 98 <br><br> 99 </form> 100 101 </td> 102 </tr> 103 </table> 104 105 </body> 106 </html> 107 ''').format(mail_table=mail_table).strip() 108 print(string) 109 110def sub(): 111 import textwrap 112 113 string = textwrap.dedent(''' 114 Content-type: text/html 115 <meta charset="UTF-8"> 116 <html><head> 117 118 <title>文字化けテスト</title> 119 120 <style type="text/css"> 121 <!-- 122 td {{ font-size: 14px}} 123 a {{ color: #003399}} 124 a:hover {{ color: #CC0000}} 125 --> 126 </style> 127 </head> 128 <body bgcolor="#FFFFFF" text="#000000"> 129 130 <br> 131 <table width="550" border="2" bordercolor="#4169E1" cellpadding="3" cellspacing="0" align="center"> 132 <tr> 133 <td bgcolor="#4169E1"><font color="#FFFFFF"><b>確認完了</font></td> 134 </tr> 135 <tr> 136 <td> 137 <br> 138 <blockquote> 139 <b>「 {sei} {mei} 」</b><br>文字化けテストへのご協力ありがとうございました。<br><br> 140 <p><font size=2><a href="javascript:history.go(-2)">入力フォームに戻る</a></font> 141 </blockquote> 142 </td> 143 </tr> 144 </table> 145 </body></html> 146 147 ''').format(sei=Sei, mei=Mei).strip() 148 print(string) 149 150 151""" --- メインシーケンス ---""" 152if not param.getvalue('mode'): 153 checkScreen() 154else: 155 sub() 156exit() 157

試したこと

def checkScreen内のヒアドキュメントに<mate charset="utf-8">を入れたりしたのですが、
ページ全体が文字化けしてします。

補足情報(FW/ツールのバージョンなど)

windows10 64bit
python3.7

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

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

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

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

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

guest

回答1

0

ベストアンサー

  • サーバの設定 (拡張子 .py に対する設定)
  • CGIを実行するユーザのロケールや環境変数の影響

等が考えられます。

サーバの設定については、環境が解らないと答えられないので
サーバ環境の詳細をお知らせください。

下の件については、該当するか解りませんが、
windows上でサーバーを起動してる場合。
以下の3行をファイルの先頭の方に追加して見て下さい。出力エンコーディングの変換

python

1import sys 2import io 3sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')

追記: 3.7 での対応方法

3.7 であれば直接 stdout.encoding を設定できるようになったので、
io.TextIOWrapper .. の代わりに

import sys sys.stdout.reconfigure(encoding='utf-8')

でも良いようです。


win10/64bit にて、Python標準ライブラリのCGIサーバーを起動して確認。

> py -3.6 -m http.server --cgi 8080

イメージ説明
イメージ説明

フォームの name="姓" の文字コードがおかしくなり、
Sei = param.getvalue('姓') で値を取れていませんでした。

出力を確認すると、Shift_JIS になっていたので、
(test.py自身はutf-8なのを確認)
ブラウザの自動判別で正常に表示されている
フォーム等は文字化けしたまま?

追記: meta タグや content-type で charset=utf-8 を指定すると、
実際の文字コードとcharsetに指定されたコードに相違がある為、文字化けが発生する。

試しに、"Content-Type: text/html; charset=utf-8" とすると
同じく、べージ全体が文字化けしました。

上記の3行を追加したところ正常な結果を確認。

イメージ説明


  • 出力エンコーディングに影響があるかもしれない項目: CGIスクリプトを実行しているユーザ

LANGPYTHONIOENCODING 等の環境変数。

投稿2020/04/22 10:13

編集2020/04/22 14:47
teamikl

総合スコア8664

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

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

yamatail

2020/04/22 13:27

teamikl様 とても詳しくご教授いただきありがとうございます。私も現在はwindows上で、pythonのローカルサーバー > python -m http.server 8000 --cgi でいろいろと試行錯誤しているところです。 ご助言いただきました3行を追加したところ。 ①.pyの一番上に追加 →確認画面 確認完了ページともに全体が文字化けしました。 これは、「CGIを実行するユーザのロケールや環境変数の影響」がteamikl様と私で違うからなのでしょうか?
teamikl

2020/04/22 14:05 編集

sys.stdout.encoding の値を CGI から確認できますか。 もし cp932 だった場合、上記の3行ではこれを utf-8 に変更します。 (新規ファイルを作って、 io.TextIOWrapperを加える前後でencodingの値を確認して見て下さい) 他の方法としては、環境変数を設定 > set PYTHONIOENCODING=utf-8 と、することでも出力を utf-8 に出来ます。 (※ただし環境変数の設定は、他のスクリプトの実行にも影響が出る可能性があるので注意) もし、sys.stdout.encodingが utf-8 なのに文字化けが発生した場合は、 他の原因かもしれません。追記。ブラウザはChromeで確認しました。
yamatail

2020/04/22 14:19

加える前はUTF-8でした!? 加えた後は、AttributeError: 'OutStream' object has no attribute 'buffer'が出ました。??? つまり、もとからPYTHONIOENCODING=utf-8ってことですかね
teamikl

2020/04/22 14:28

元々 utf-8 の様ですね、 > AttributeError: 'OutStream' object has no attribute 'buffer'が python2.7~3.8 まで確認してみましたが OutStream はありませんでした。 これはもしかして、IDE や Jupyter等から実行されてますか? 自分のは DOS プロンプトからです。
teamikl

2020/04/22 14:32

若しくは、CGIを実行している python が別バージョンという事はないでしょうか sys.version を CGI側から確認して見て下さい。
yamatail

2020/04/22 14:32

確認のためのコードはAnacondaのspyderで行いました コードは以下--- import sys import io print('加える前',sys.stdout.encoding) sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') print(sys.stdout.encoding)
yamatail

2020/04/22 14:33

申し訳ありません。cgi側からというのはどういうことなのでしょうか…
teamikl

2020/04/22 14:34

> 確認のためのコードはAnacondaのspyderで行いました ここは重要なポイントです。CGIにしてブラウザから確認して見て下さい。 IDE や エディター上では独自の標準入出力を持つので、 CGIで実行する場合と環境が違ってしまいます。
yamatail

2020/04/22 14:39

ブラウザで確認したところ >3.7.0 (default, Jun 28 2018, 08:04:48) [MSC v.1912 64 bit (AMD64)] spyder でも同じでした。 ※python3.7でした。。。
teamikl

2020/04/22 14:40

ブラウザからローカルサーバ経由でアクセスです。 # 例えば test_env.py として、サーバ経由で /cgi-bin/test_env.py にアクセス import sys print("Content-type: text/html\r\n\r\n") print(sys.version) print(sys.stdout.encoding)
teamikl

2020/04/22 14:46

sys.stdout.encoding をブラウザからもう一度確認して見て下さい。
yamatail

2020/04/22 14:49

たしかにブラウザで確認したところ sys.stdout.encodeing がcp932になっております! versionは同じようです。
yamatail

2020/04/22 14:51

そして3行足すとutf-8に変わります! そして、ページ全体文字化けします
teamikl

2020/04/22 14:54

3.7 での対応を、回答に追記しました。 自分の環境ではこれで治りましたが、もう一つ心配なのは入力のエンコーディング (POSTで送られてくるデータのエンコード) 影響があるか解りませんが、 フォーム名の name="姓" や name="名" は、日本語を避けたほうが無難です。 文字化けは別として、最後の画面に値を渡す問題はnameを(半角の)英語やローマ字に変更でも治ります。
teamikl

2020/04/22 15:02

質問を編集して、その3行足したものを含む 現在実行してるスクリプトのソースに更新して頂けますか。 ここで絞り込めなければ、HTTPのヘッダ等も調べる必要がありそう - 何処かに 誤ったcharset指定が残っていないか。 - CGIではなく、サーバーが出力するヘッダで何か付け加えられている。 - ブラウザのキャッシュを読んでいる。 後、ブラウザは何をお使いでしょうか
yamatail

2020/04/22 15:07

了解しました。編集いたします。 ブラウザはchromeです バージョン: 81.0.4044.122(Official Build) (64 ビット)
teamikl

2020/04/22 15:18

IEにてページ全体の文字化けを確認出来ました。 自分の環境では chrome では正常です。 81.0.4044.113(Official Build) (64 ビット)・・・バージョン確認したら更新が始まった 文字コードの指定がない状態なので、自動判別に失敗してるのかもしれません。 Content-Type の部分に2か所修正で、IEでも正常な表示を確認しました。 Content-type: text/html; charset=utf-8
yamatail

2020/04/22 15:30

私も、teamikl様の指摘のように > Content-type: text/html > Content-type: text/html <meta charset="UTF-8"> の二か所を Content-type: text/html; charset=utf-8 に書き直したら、表示が正常になりました!(T^T) ありがとうございます!!m ( ___ ___ ) m 結局そこが原因だったということなのでしょうか......
teamikl

2020/04/22 15:33

両方の様ですね。以前は 出力がcp932(shift jis) なのに utf-8 指定をして文字化け 出力が utf-8 に直っても、キャッシュや文字コード判別の問題等で文字化け 出力をutf-8 にして charset=utf-8 指定することで解消 直ったようで良かったです。お疲れ様でした
yamatail

2020/04/22 15:36

一から丁寧に教えていただきまして本当にありがとうございました。 こんなに遅くまでお付き合いいただきまして、感謝いたします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.51%

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

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

質問する

関連した質問