サーバサイドのプログラミング能力が貧弱なので、勉強の第一歩として掲示板を作ってみた。ついでに Ruby も覚えてしまおうということで、Ruby で。
要件
mod_ruby を入れる
まずは Ruby を CGI で動かすために mod_ruby を入れる (参考)。
MySQL のドライバを入れる
データベースを作る
次にデータベースを作る。フィールドは id、名前、本文、日付の 4 つ。
CREATE DATABASE rubybbs; GRANT ALL ON rubybbs.* to hogehoge IDENTIFIED BY 'hogefoobar'; USE rubybbs; CREATE TABLE posts ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(20) NOT NULL, date DATETIME NOT NULL, body TEXT NOT NULL );
プログラム本体を書く
次にプログラム本体を書く。
prepare statement と html_escape で、ある程度のインジェクションを回避できるようだ。
また、ERB に外部ファイルを使うときは untaint しないと、eval のセキュリティエラーになる。
#!/usr/bin/ruby require 'rubygems' require 'cgi' require 'mysql' require 'erb' #config DB_HOST = "localhost" DB_USER = "hogehoge" DB_PASSWORD = "hogefoobar" TEMPLATE_FILE = "template.rhtml" NAME_MAX_CHARS = 20 BODY_MAX_CHARS = 100 cgi = CGI.new puts cgi.header({"content-type" => "text/html", "charset" => "utf-8"}) db = Mysql::new(DB_HOST, DB_USER, DB_PASSWORD, "rubybbs") db.query("set character set utf8") #add begin if (!cgi["name"].strip.empty? && !cgi["body"].strip.empty? && cgi["name"].length < NAME_MAX_CHARS && cgi["body"].length < BODY_MAX_CHARS) statement = db.prepare("INSERT INTO posts (name, body, date) VALUES (?, ?, ?)") statement.execute(cgi["name"], cgi["body"], Time.now) end rescue statement.close db.close puts "error" exit end #fetch begin statement = db.prepare("select name, body, date from posts") statement.execute posts = [] statement.each do |col| posts << {"name" => ERB::Util.html_escape(col[0]), "body" => ERB::Util.html_escape(col[1]).gsub(/¥n/, "<br>"), "date" => ERB::Util.html_escape(col[2])} end posts.reverse! rescue statement.close db.close puts "error" exit end #render begin puts ERB.new(File.read(TEMPLATE_FILE).untaint, 1).result(binding) rescue puts "error" exit end #end statement.close db.close
ビューのテンプレートを書く
最後にビュー の rhtml を書く。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html lang="ja"> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"> <meta http-equiv="content-language" content="ja"> <meta http-equiv="content-style-type" content="text/css"> <title>RubyBBS</title> <style type="text/css"> div.item { margin-bottom: 1em; background-color: #eee; } div.item p { margin: 0; } div.item p.name { font-size: 1.5em; } div.item p.body { font-size: 2em; } </style> </head> <body> <h1>RubyBBS</h1> <form method="post" action="rubybbs.rb"> <p>name:<br><input type="text" name="name"></p> <p>body:<br><textarea name="body" rows="2" cols="40"></textarea></p> <p><input type="submit" value="submit"></p> </form> <% posts.each do |item| %> <div class="item"> <p class="name"><%= item["name"] %></p> <p class="date"><%= item["date"] %></p> <p class="body"><%= item["body"] %> </p> </div> <% end %> </body> </html>
課題
とりあえず動くものはできたが、公開サーバで動かせるレベルではない。
気がついた課題は、
- 全体的にコードが汚い。無駄が多い。
- バリデートが甘い。get で投稿できてしまう。
- 設定ファイルを作るべき。
- テンプレートファイルは Apache が読めないようにすべき。
とりあえずこんなところ。