gawkで掲示板CGI
誰得。
euc-jpで保存したあとawkをCGIとして動かせるサーバーで実行してね。排他制御は一切行っていないので,同時に複数人が書き込みを行うとマスターファイルが壊れちゃう予感。
#!/usr/local/bin/gawk -f BEGIN { header("SimpleBBS by gawk"); RS = "&"; FS = "="; } { key = decode($1); value = decode($2); params[key] = value; } END { RS = "\n"; FS = " "; if (length(params["confirm"]) != 0) { confirm(); } else if (length(params["post"]) != 0) { post(); } else { view(); } footer(); } ################################################# # action functions ################################################# # validate a message function validate() { # erase html elements gsub(/</, "\\<", params["name"]); gsub(/>/, "\\>", params["name"]); gsub(/</, "\\<", params["text"]); gsub(/>/, "\\>", params["text"]); # validate inputs is_valid = 1; if (length(params["name"]) == 0) { error["name"] = "名前を入力してください"; is_valid = 0; } if (length(params["text"]) == 0) { error["text"] = "本文を入力してください"; is_valid = 0; } if (length(params["text"]) > 256) { error["text"] = "本文が長すぎます"; is_valid = 0; } return is_valid; } # confirm a message function confirm() { validate(); confirm_template(); } # post a message function post( filename, date) { if (validate()) { filename = "bbs.dat"; date = strftime("%c"); print params["name"] "<>" params["text"] "<>" date >> filename; close(filename); } post_template(); } # view messages function view( filename, i) { n = 0; filename = "bbs.dat"; while ((getline line < filename) > 0) { messages[n++] = line; } close(filename); view_template(); } ################################################# # template functions ################################################# # header template function header(title) { print "Content-Type: text/html"; print ""; print "<html>"; print "<head>"; print "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=euc-jp\" />"; print "<title>" title "</title>"; print "</head>"; print "<body>"; print "<h1>" title "</h1>"; } # footer template function footer() { print "</body>"; print "</html>"; } # confirm template function confirm_template() { if (is_valid) { # confirm print "<h2>投稿確認</h2>"; print "<form action=\"./bbs.awk\" method=\"post\">"; print "<dl>"; print "<dt>名前</dt>"; print "<dd>" params["name"]; print "<input type=\"hidden\" name=\"name\" value=\"" params["name"] "\" /></dd>"; print "<dt>本文</dt>"; print "<dd>" params["text"]; print "<input type=\"hidden\" name=\"text\" value=\"" params["text"] "\" /></dd>"; print "</dl>"; print "<p><input type=\"submit\" name=\"post\" value=\"この内容で投稿する\" />"; print "<input type=\"submit\" name=\"view\" value=\"投稿を中止する\" /></p>"; print "</form>"; } else { # error print "<h2>投稿フォーム</h2>"; print "<form action=\"./bbs.awk\" method=\"post\">"; print "<dl>"; print "<dt>名前</dt>"; print "<dd><input type=\"text\" name=\"name\" value=\"" params["name"] "\" /></dd>"; print "<dd><strong>" error["name"] "</strong></dd>"; print "<dt>本文</dt>"; print "<dd><input type=\"text\" name=\"text\" value=\"" params["text"] "\" /></dd>"; print "<dd><strong>" error["text"] "</strong></dd>"; print "</dl>"; print "<p><input type=\"submit\" name=\"confirm\" value=\"投稿内容を確認する\" />"; print "<input type=\"submit\" name=\"view\" value=\"投稿を中止する\" /></p>"; print "</form>"; } } # view template function view_template( i, array) { # form print "<h2>投稿フォーム</h2>"; print "<form action=\"./bbs.awk\" method=\"post\">"; print "<dl>"; print "<dt>名前</dt>"; print "<dd><input type=\"text\" name=\"name\" /></dd>"; print "<dt>本文</dt>"; print "<dd><input type=\"text\" name=\"text\" /></dd>"; print "</dl>"; print "<p><input type=\"submit\" name=\"confirm\" value=\"投稿内容を確認する\" /></p>"; print "</form>"; # messages print "<h2>メッセージ</h2>"; print "<dl>"; for (i=n-1;i>=0;i--) { if (split(messages[i], array, "<>") < 3) { continue; } print "<dt>" array[1] "</dt>"; print "<dd>" array[2], "@", array[3] "</dd>"; } if (n == 0) { print "<dt>SimpleBBS</dt>"; print "<dd>メッセージがありません</dd>"; } print "</dl>"; } # post template function post_template() { if (is_valid) { # done print "<h2>投稿完了</h2>"; print "<p><a href=\"./bbs.awk\">SimpleBBS</a>に戻る。</p>"; } else { # error print "<h2>投稿エラー</h2>"; print "<ul>"; for (key in error) { print "<li><strong>" error[key] "</strong></li>"; } print "</ul>"; print "<p><a href=\"./bbs.awk\">SimpleBBS</a>に戻る。</p>"; } } ################################################# # utility functions ################################################# # urldecode function decode(s, filename, i, hex, ret) { # init temporary file filename = "decode.dat" # init hex table for (i=0;i<10;i++) { hex[i] = i; } hex["A"] = hex["a"] = 10; hex["B"] = hex["b"] = 11; hex["C"] = hex["c"] = 12; hex["D"] = hex["d"] = 13; hex["E"] = hex["e"] = 14; hex["F"] = hex["f"] = 15; # plus2space gsub(/\+/, " ", s); # put decoded string to temporary file while (match(s, /%../)) { if (RSTART > 1) { printf "%s", substr(s, 1, RSTART-1) > filename; } printf "%c", hex[substr(s, RSTART+1, 1)] * 16 + hex[substr(s, RSTART+2, 1)] > filename; s = substr(s, RSTART + RLENGTH); } printf "%s", s > filename; close(filename); # get decoded string from temporary file while ((getline line < filename) > 0 && length(line) != 0) { ret = ret line; } close(filename); return ret; }
URLデコードの実装はhttp://geni.ath.cx/unix.html#_awkを参考にした。モダンなスクリプト言語なら1行で済むっていうかそもそもPOSTパラメータを受け取るための組み込み変数があるのでわざわざデコードのためのコードを書く必要すらないんだけどな。