2009年10月18日

【PythonでCGI】CGIでの例外Error処理 〜 Web版BlogでHTMLタグ表示

 本日のお題は、CGIプログラムでのError処理である。前稿と同じソースの再掲載での説明では芸がないので、フローは前稿のそのままで、処理だけをHTMLタグの入ったソースコードをブログら掲載する時に必要な「< ⇒ &lt;」等を行なうもので行なわせて頂く。この機能自体は以前、コンソールプログラムとして紹介しているもので珍しくもないので先ずは簡単にその変換部分だけを説明させて頂く。前稿との差は、
  前稿の「SPAM投稿切刻み」処理部分


ss=p=''
for s in html_text: #unicodeはMultiBite文字も文字単位処理
if s=='\n' or s=='\r' or p=='\n' or p=='\r' or ss=='': #改行符号と頭の文字の
ss=ss+s #前後には空白文字を加えず
else: #そうでないなら
ss=ss+' '+s #空白文字を加える
p=s #直前の文字を代入
html_text=ss #html_textを置換え
が、
  今回の「HTMLタグ表示」処理部分


ss = html_text.replace(u'&',u'&amp;').replace(u'<',u'&lt;')\
.replace(u'>',u'&gt;').replace(u'&',u'&amp;') #最後の&の変換がミソ!!
html_text = ss
に変わった程度の差に過ぎない。また、以前の同機能のコンソールプログラムとの差は「.replace(u'&',u'&amp;')」が、HTML内に記述し表示させる為に追加になっていることにご注意頂きたい。蛇足ながら、Stringオブジェクトのメソッドとして定義されている「'<処理文字列>'.replace('<検索文字>','<置換文字>')」を使うと、元文書に対し、特定のキーワードを強調や色付表示させたい時に重宝する。そんなツールはテキスト欄へのキーワード入力を求め、
「'<本文>'.replace('.replace(u'&',u'&amp;')','<b>.replace(u'&',u'&amp;')&;lt;/b>')」の様に処理すれば、「.replace(u'&',u'&amp;')」が全て太字表示に置換出来る。普通なら正規表現で考えることが簡単に達成出来る訳だ。

 さて、これより本論のCGIでのError処理の説明に移る。Web版の「BlogでHTMLタグ表示」のソースコードは次の通り。
  /Web/cgi-bin/html4blog.py


#!c:/Python26/python
# -*- coding: UTF8 -*-
# ※ Windows の場合1行目はdummyです

u"""
#####################################################################
# HTML CODE_TEXT for BLOG 0.0.0 (C) Mire 2009-10-15 #
#####################################################################
 blogを持っていると
怒り^^;;を込めて、SPAM迷惑投稿を切り刻みます。コピペで上書きすれば、
内容はそのままでも目的のURL linkは全てはずれレンダリングも消えます。
USEGE:
1.SPAM迷惑投稿をテキスト欄に貼付けボタンをクリックして下さい。
2.別窓または別タブで1文字毎の半角スペース区切りテキストが表示。
3.このスペース区切テキストのCopy&PaseteでSPAM迷惑投稿を置換え
"""

__author__ = "Mire in Japan"
__version__ = '0.0.0'
__copyright__ = 'Copyright (c) 2009 Mire'
__license__ = 'GPL'
__url__ = 'http://pythonlife.seesaa.net/'

debug = 0 #debugレベル


########################################
## 当Tool専用関数の定義contents()のみ ##
########################################

def contents(debug=1):
u"""
コンテンツ「入出力フォーム」を表示します
"""
try:
from mire.htm import display_err, cgi_params #, tag_encode

print u'<table width="590px" style="background-color:#F0F0F0;"><tr>'
print u'<td><font size="-1"><b>HTMLのタグをそのまま表示するものに変換します。</b>\
</font></td></tr><tr><td align="center">',
prms=cgi_params() #> mire.htm.cgi_params(): CGI引数情報の辞書を返します


if debug > 1: #debugレベル2: CGI引数の名前と値を表示します。
print '<table><tr><td align="right"><pre align="left" style="text-align:center;\
pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap;\
white-space: -o-pre-wrap; word-wrap: break-word; ">'
for p in prms:
print '%s: %s' % (p,prms[p])
print '</pre></td></tr></table>'

if 'html_text' in prms: #cgi引数が存在したら、
html_text=unicode(prms['html_text']) # CGIの引数の値はunicode化しないと駄目の様だ
ss = html_text.replace(u'&',u'&amp;').replace(u'<',u'&lt;')\
.replace(u'>',u'&gt;').replace(u'&',u'&amp;') #最後の&の変換がミソ!!
html_text=ss #html_textを置換え

else: #引数がないなら
html_text='' #0長文字列

#コンテンツ本体: table,form textarea,inputタグで入出力画面を表示
print u'<table><form method="post" target="_blank"><tr>'
print u'<td><textarea cols="88" rows="20" style="font-size:8pt;" name="html_text"',
print u'mire_val="html4blog_text(html_text)">%s</textarea></td>' % (html_text)
print u'</tr><tr><td><pre>%s<pre></td>' % (html_text.replace(u'&amp;',u'&'))
print u'</tr><tr><td><center>',
print u'<input type="submit" style="font-size:8pt; width:567px">',
print u'</td></tr></form></table></center></td></tr></table>'


except: #vividな作成部分はhtm.display_err()
if debug > 0: #でdebug情報を取得。運用時はdebug=0
print '' #とし障害内容は表示させない。
display_err(locals()) #>mire.htm.display_err()#Web用の例外処理で障害切分
print '</span>'
else: #運用中のdebug message表示はセキュリティ上不適格。通常はdebug=0で以下のmessage
print '<pre>Error was occured.\nPlease, contact your system administrators.\n'
print 'You? Do Your Best!\n Test html4spam.py with debug=2. Good luck.</pre>'


########################################
## ##
## 処理実行開始位置 ##
## ##
########################################
try:
from mire.htm import display_err, html_header, html_footer
html_header(charset='UTF-8', title=u'HTML CODE_TEXT for BLOG 0.0.0 (C) 2009 Mire GPL license'
, body=['style="right-margin:0px; background-color:#808080;"'])
contents(debug=debug)
html_footer()

except:
if debug > 0:
display_err(locals()) #こちらは最後の抑え
else: #運用中のdebug message表示はセキュリティ上不適格。通常はdebug=0で以下のmessage
print 'Content-type: text/html\n\n<html>\n<head></head><body>'
print '<pre>Error was occured.\nPlease, contact your system administrators.\n'
print 'You? Do Your Best!\n Test html4spam.py with debug=2.\n\nGood luck.</pre>'
print '</pre></body></html>'


 昔々、例外Error処理がなかった当時は、全ての条件を頭に置いてif分での条件分岐を行ないエラー処理を書いていたものだ。当初、この「try:〜;except:〜;」は、いい加減な詰めの甘い仕組みに見えてしまい、使う気にならなかったものだ。でも、それはシステム言語や使用する開発ツールが完璧であり且つ、関わるシステム作成者全員間で完全無欠なコミュニケーションが取れる場合に言えることで、現実の開発環境ではありえないことだ。
 従って、例外Error処理を使うときの発想は、逆に想定外のエラーは起きて当り前、起きた場合の無難な処理を予め書いて置き、「1.システム作成中は効率的なDEBUG」を、「2.実用運転時には、次善の策として、利用者側に障害アクションをとってもらうメッセージや、システム管理者への通知、そして応急処理を組んで置くことに使うもの、そう言う逆転の発想で使うものと考える。

 従って、この説明用のサンプルソースコードの様に最低でも、先ずは、実行処理全体について、そして、作成中のvividな部分には必ず、「try:〜;except:〜;」で例外処理を入れて置く必要がある。そして、同時に、特にWebシステムの場合利用者は不特定多数となることを前提にセキュリティ上の配慮も加味し、debugレベルにより、表示する内容を抑制しする対処をすることになる。

 このサンプルでは、運用での障害発生時には、いずれも次の様なものが表示される様になっている。
Error was occured.
Please, contact your system administrators.

You? Do Your Best!
Test html4spam.py with debug=2. Good luck.
文字コード処理の不具合も考慮して敢えて英語のみのメッセージにしている。

 開発修正時のDEBUG時には、mire.htm.display_err()の定義に従い例外Errorの内容とローカル変数とその値が表示される。前稿と重複するが定義は次の通りである。
  mire.htm.py 内の display_err()関数


## エラー表示関数(コメント行文字化け対策+thread実行時のエラー情報表示の時系列混乱軽減) ##
def display_err(self,local, title = '\n\n#### EXCEPTION ERROR ####'):
"""
##########################################################################################
#エラー表示関数(コメント行文字化け対策 + thread実行時のエラー情報表示の時系列混乱軽減) #
#USAGE: 第一引数に「locals()」を指定することで、処理時の変数値を表示します。 #
# waitingはthread実行時のエラー情報表示の時系列混乱軽減の為のWAIT処理です。 #
# waiting = 0 #
# def foo(): #
# global waiting #
# sleep(waiting) #
# try: #
# 処理 #
# waiting = 0 #
# except: #
# display_err(locals(),'<例外処理の場所を表すタイトル>')# locals()指定は必須 #
# waiting = 1 #
# foo() #
##########################################################################################
"""
import traceback
from time import sleep
print('Content-type: text/html\n\n<html>\n<head>')
print('<body><pre>')
if local is None:
local =locals()
global waiting
frame0 = '\n*******************************************************************************'
frame1 = '*******************************************************************************\n\n'
errs = [frame0, title]
errs.append('%s' % (self.dsp_hex(traceback.format_exc()))) #> dsp_hex(s): コメント文字化け対策
sleep(waiting)
ls = local
keys = list(ls.keys())
errs.append('')
for key in keys: # display_err()関係の変数の表示を省く
# if not key in ['v', 'ls', 'keys', 'key', 'errs', 'txt', 'er', 'sleep']:
er = '* %s: %s' % (repr(key).ljust(24),repr(ls[key]))
errs.append(er)
errs.append(frame1)
txt = '\n'.join(errs)
print(txt)
print('</pre></body></html>')

## コメント文字化け対策 ##
def dsp_hex(self,s):
from re import search
charsets=['UTF-8','Shift_JIS','EUC-JP','iso-2022-jp'] # どれでもいいので、charsetで、
for charset in charsets: # unicode化し、コメント部分の
try: # 文字化けを防ぐ
return str(s,charset)
except:
print('%sでは変換不能でした' % (charset))
pass
sss=''
for ss in s: # 想定外のcharsetのときは16進数表記に
if (ord(ss)>=32 and ord(ss)<=126) or ss.isspace(): # Windowsにはcurses.ascii.isprint()が
sss=sss+ss # ないのでcurses/ascii.pyの中身を展開
else:
sss=sss+'\\'+hex(ord(ss))[2:].upper()
return sss
で実際にどの様なエラーメッセージが出るかというと以下の様になる。

ちょいと、長くなって息切れしたので、後ほど追記。(ソースコードも一部差替えます。)続きを読む
タグ:CGI Python
posted by Mire at 01:51 | Comment(0) | TrackBack(0) | Pythonプログラミング | このブログの読者になる | 更新情報をチェックする
月額見放題1,000円開始キャンペーンバナー(画像ありver)
紺碧の艦隊 ルパン三世 GREAT CHASE クリックプロモーション
<< 2009年10月 >>
        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
カテゴリ
タグクラウド
ファン
利用中のオープンソース
最近のコメント
最近の記事
過去ログ
QRコード
レガシーなアプリはいかが?
Dell 法人のお客様ページ
  • 【法人様向け】デル、お得なキャンペーン情報
  • 法人のお客様向け ストレージソリューション
  • 法人のお客様向け ネットワークソリューション
  • 【SOHO法人様向け】デル・オンライン広告限定ページ
  • デル-個人のお客様ページ
  • 【個人のお客様向け】デル・オンライン広告限定ページ
  • オンライン広告限定キャンペーンページ
  • ソフトウェア&周辺機器 パソコン工房
    ツートップインターネットショップ(twotop.co.jp) マウスコンピューター/G-Tune