PythonでWebアプリを作っていて、ブラウザ上の表示は文字化けするのにデータベースには正常に入力されたという話

現在、今まで僕が取り扱ったことのないPythonという言語を使ってあるプログラムを組もうと企てています。

レンタルサーバーに環境を構築して・・・というのを考えていたのですが、その環境構築もまた面倒そう(というか僕がよく分かっていない)なので、とりあえずWindows上にApacheとPythonを入れてまずはそこで動くものを作ってしまおうと考えています。サーバー上にデプロイするのはまた後日という事で。

スポンサーリンク

不可解な文字化けが発生した

現在では文字コードはUTF-8を使うのが一般的らしいので、僕もソースからデータベースから全部UTF-8に統一して開発を行う事にしました。

とりあえずWeb画面上から入力した文字や数字などをデータベースに突っ込むという簡単なサンプルを作ってみました。こんなやつです。Webフレームワークも何も使っていません(これもまだよく理解できていないのでw)。

#! C:\Program Files (x86)\Python36-32\python
# coding: utf-8

print ('Content-type: text/html\n')
print ()

import pymysql, cgi
form = cgi.FieldStorage()

#Setup the HTML Page with name of call as title
print ('<html>')
print ('<head>')
print ('<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">')
print ('<title>INSERT SAMPLE</title>')
print ('</head>')
print ('<body>')
print ('<form action="/cgi-bin/dbsample3.py" method="POST">')

print ('<br>')
print ('名前: <input type="text" size="30" name="namae">')
print ('年齢: <input type="text" size="30" name="age">')
print ('<input type="submit" value="submit" name="button">')

namae = form.getvalue('namae', '')
toshi = form.getvalue('age', '')

sql = 'INSERT INTO 名簿 VALUES(%s, %s)'

connection = pymysql.connect(
	host='localhost', user='xxxx', passwd='xxxx', db='xxxx', charset='utf8')
cursor = connection.cursor()

try:
	cursor.execute(sql, (namae, int(toshi)))
	connection.commit()
except pymysql.Error as e:
	print('pymysql.Error: ', e)

connection.close()

print ('</form>')
print ("</body>")
print ("</html>")

するってーと、以下の現象が発生しました。

・ブラウザ上に表示される日本語は文字化けしている
・データベースに入った日本語は正しく表示される

じゃあ13行目の文字コードの指定(ブラウザに文字コードをお知らせする部分)をShift-JISにしたらどうなったかと言うと、次のようになりました。

・ブラウザ上は日本語が正しく表示される
・データベースに入った日本語は文字化けしている

僕はプログラミングは得意ではないので、もうわけが分からない状態に陥りました。

困ったときのGoogle先生

こういう場合は、Googleを検索するとまず間違いなく解決方法を見つけることができます。という事で僕もGoogleをひたすら検索したところ、3日ぐらい経ってようやく解決できました。

まず、以下のコードを実行してみました。

#! C:\Program Files (x86)\Python36-32\python
# coding: utf-8

import sys

print ('Content-type: text/html\n')
print ()

print (sys.getdefaultencoding())
print (sys.stdout.encoding)

その結果は、

utf-8 cp932

でした。つまり、デフォルトの文字コードはUTF-8だけど、標準出力(print文での出力)はCP932(Shift-JISみたいなもの)だと。

文字化けの現象を解釈すると、printで出力されたCP932の日本語を、ブラウザではUTF-8だと理解して表示したせいで表示が文字化けしたという事です。でもデフォルトがUTF-8だから、UTF-8で表示しているブラウザから入力した日本語はデータベースに正しく入ったと。(上手い説明ができていないかもしれません)

じゃあこの標準出力での文字コードもUTF-8にすることができれば問題は解決する、というところまで進みました。

標準出力の文字コードを設定する方法

これまたGoogleで検索したところsitecustomize.pyという設定ファイルを弄る方法もあったのですが、僕の環境ではそのファイルが見つからなかったので、ソース上で指定する方法を採用しました。

#! C:\Program Files (x86)\Python36-32\python
# coding: utf-8

import sys, io
sys.stdin = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8')
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')

print ('Content-type: text/html\n')
print ()

print (sys.getdefaultencoding())
print (sys.stdout.encoding)

5~7行目で、標準入力、標準出力、標準エラー出力の文字コードを全てUTF-8に指定することができます。

この1~7行目をおまじないの如く全てのソースに入れていけば、文字化けに関する問題は恐らく発生しないでしょう。

プログラミングの話まで始まってしまい、いよいよごちゃまぜブログの様相を呈してきました。しかし同じような事でお悩みの方にとって助けになればと思い、このエントリーを作ってみました。

スポンサーリンク

フォローする