Python CGI で 掲示板みたいなものを作る [プログラム三昧]
これまで、CGI内部で生成した文字列をデータベースに登録していく仕掛けを作ってきました。 今回は、HTML文書の "FORM" から文字列を入力して登録していく、掲示板みたいなものを作成してみました。
FORM の構成
HTML文書には、"TEXTAREA" を持った "FORM" が一つ埋め込んであります。 "Submit" ボタンを押すと、 CGI に "FORM" の情報が送信されるという仕組みになっています。 今回、送信に使用したのは、 "GET" という手法です。 これは、情報を URL に埋め込んで送信します。
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <!-- $Id: visitor_world3.html,v 1.1 2009/03/01 07:26:41 noritan Exp $ --> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" > <head profile="http://www.w3.org/2005/10/profile"> <title>VISITOR WORLD 3</title> </head> <body> <h1>VISITOR WORLD 3</h1> <form action="./visitor_world3.cgi" method="get"> <div> <textarea name="message" rows="4" cols="40"></textarea> </div> <p> <input type="submit" value="Submit" /> <input type="reset" value="Clear" /> </p> </form> </body> </html>
CGI の悩み
"FORM" からは、URLの一部として "TEXTAREA" の情報が送られてきます。 この情報自身は、URLの流儀に従って、エンコードされているので、Pythonでは、 cgi.parse_qs というメソッドを使って簡単に文字列として取り出すことができます。 問題は、この文字列をどうやってデータベースに格納するかです。
通常、データベースには、文字列を格納することができます。 文字列を格納するときには、しかるべきライブラリによって、適切なエンコードが行われます。 ところが、さくらのレンタルサーバ・ライトプランでは、 SQLite をコマンドラインで使わざるをえません。 そのため、エンコード部分も自分で考えなくてはなりません。
そこで、Pythonの標準ライブラリを探し回って、二つほど解決策を考えました。
- urllib.quote / urllib.unquote メソッドを使う
このメソッドは、特殊文字を含んでいた場合に % を使った十六進表記で置き換えます。 良く URL の表記に使われている方法です。
>>> urllib.quote("<p>\nHELLO\n</p>") '%3Cp%3E%0AHELLO%0A%3C/p%3E'
- base64.b64encode / base64.b64decode メソッドを使う
base64というのは、バイナリのデータを64種類の文字で置き換えるエンコード方法です。 良く、ファイルをメールに添付するときに使われます。
>>> base64.b64encode("<p>\nHELLO\n</p>") 'PHA+CkhFTExPCjwvcD4='
これらを見比べた結果、あとから人間が見たときによりわかりやすいと思われる、 "urllib.quote" を使うことにしました。
CGIの出来上がり
”FORM" 情報を受け取って、データベースに登録し、データベースの内容を表示する CGI に仕立てました。 使用したデータベースファイルは、前回の "VISITOR WORLD 2" で作成した "visitor.sqlite" をそのまま利用しました。
#!/usr/local/bin/python # $Id: visitor_world3.cgi,v 1.1 2009/03/01 07:26:41 noritan Exp $ import os import sys import cgi import urllib import time # Show error as a page description. sys.stderr = sys.stdout # Database releated information db_file = "visitor.sqlite" table_name = "visitor" command = "/usr/local/bin/sqlite3 %s" % (db_file) # Get and parse a query string query_string_key = 'QUERY_STRING' if query_string_key in os.environ: query = cgi.parse_qs(os.environ[query_string_key]) else: query = {} # Get Current time now = time.time() # Get and escape a MESSAGE message_key = 'message' if message_key in query: message = urllib.quote(cgi.escape(query[message_key][0])) else: message = "" # Compose a SQL sql = "SELECT time, description FROM %(table)s ORDER BY time DESC;" if len(message) > 0: sql = \ "INSERT INTO %(table)s VALUES (%(now)f, \"%(message)s\");\n" \ + sql # Show HTML header print """Content-type: text/html <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" > <head profile="http://www.w3.org/2005/10/profile"> <link rel="icon" href="/favicon.png" type="image/png" /> <title>VISITOR WORLD 3</title> </head> <body> <h1>VISITOR WORLD 3</h1> """ # Access to the DATABSE (pipe_out, pipe_in) = os.popen2(command) pipe_out.write( sql % {"table":table_name, "now":now, "message":message} ) pipe_out.close() # Show a list of visitor record print """<dl> """ # Make a list of messages try: for line in pipe_in: field = line.split("|") asctime = time.strftime( "%Y-%m-%d (%A) %H:%M:%S", time.localtime(float(field[0])) ) message = urllib.unquote(field[1]) print "<dt>%s</dt><dd>%s</dd>\n" % (asctime, message) finally: pipe_in.close() # Show footer print """ </dl> </body> </html> """
参考サイト
- VISITOR WORLD 3
- "FORM"入力ページは、ここにありますので、お試しください。 いちおう、"XHTML 1.1"認証済みです。
コメント 0