RubyでCGIスクリプトを作る下準備・訪問者の環境変数を取得・一部訂正
http://d.hatena.ne.jp/BeForU/20040629#p2 でSocket.gethostbyaddrを使った時にホストの逆引きができないとエラーになって止まる。
CGIだと500 Internal Server Errorが出る。
Rubyではとりあえずgethostbyaddrはあきらめる。
host = ENV['REMOTE_HOST'] addr = ENV['REMOTE_ADDR'] ua = ENV['HTTP_USER_AGENT'] ref = ENV['HTTP_REFERER'] if host == nil host = addr end
RubyでCGIスクリプトを作る下準備・訪問者の環境変数を取得
作っておけば役に立ちそう。
これでグローバル変数に値がセットされる。
Perlだともう少し簡単になるのにRubyだと少々ややこしい。
def getenv $host = ENV['REMOTE_HOST'] $addr = ENV['REMOTE_ADDR'] $ua = ENV['HTTP_USER_AGENT'] $ref = ENV['HTTP_REFERER'] # デバッグ用 #$addr = "127.0.0.1" #$host = "127.0.0.1" if $host == nil || $host == $addr require "socket" $addr =~ /([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/ $host = Socket.gethostbyaddr([$1.to_i, $2.to_i, $3.to_i, $4.to_i].pack("C4"), Socket::AF_INET)[0] end end
RubyでCGIスクリプトを作る下準備・フォームデータを受け取る・改
前回 http://d.hatena.ne.jp/BeForU/20040628#p2 の改良。
GETとPOSTの両方に対応。
将来、掲示板スクリプトに使えるように"<"や">"を置き換える。
def tag(str) str.gsub!("&", "&") str.gsub!("<", "<") str.gsub!(">", ">") str.gsub!("\"", """) str.gsub!("\x0d\x0a", "\x0a") str.gsub!("\x0d", "<br>") str.gsub!("\x0a", "<br>") str end # コンソール上のデバッグ用に環境変数をセット #ENV['QUERY_STRING'] = "a=%A5%C6%A5%B9%A5%C8&b=t+e%0As+t" #ENV['CONTENT_LENGTH'] = "30" #ENV['REQUEST_METHOD'] = "GET" def decode(method) require "kconv" $input = {} if method == "GET" buf = ENV['QUERY_STRING'] elsif method == "POST" buf = STDIN.read ENV['CONTENT_LENGTH'].to_i end if buf == nil return end buf.split("&").each { |str| key = str.split("=")[0] value = str.split("=")[1] if value != nil value.tr!("+", " ") value.gsub!(/%([0-9a-fA-F]{2})/) { [$1.hex].pack("C") } value = value.toeuc # 文字コードはEUC value = tag(value) $input[key] = value end } end
RubyでCGIスクリプトを作る下準備・フォームデータを受け取る
標準で付いてるライブラリのcgi.rbを使えば楽そうだが、自分で作ってみる。
Perlでありがちな処理をRubyで再現。
Rubyの変数にnilがあるのを考慮しないと500 Internal Server Errorが出る。ややこしい。
#!/usr/local/bin/ruby # コンソール上のデバッグ用に環境変数をセット #ENV['CONTENT_LENGTH'] = "20" #ENV['REQUEST_METHOD'] = "POST" def decode require "kconv" $input = {} buf = STDIN.read ENV['CONTENT_LENGTH'].to_i buf.split("&").each { |str| key = str.split("=")[0] value = str.split("=")[1] if value != nil value.tr!("+", " ") value.gsub!(/%([0-9a-fA-F]{2})/) { [$1.hex].pack("C") } value = value.toeuc # 文字コードはEUC $input[key] = value end } end if ENV["REQUEST_METHOD"] == "POST" decode end print <<END Content-Type: text/html <html> <head> <title>Rubyでフォームデータをデコードするデモ</title> </head> <body> <h1>Rubyでフォームデータをデコードするデモ</h1> <hr> <form method=post> <input type=checkbox name=check> <input type=text name=text> <input type=submit> </form> END if $input != nil print "<hr>\n" print "<table border=1>\n" print "<tr><td><b>key</b></td><td><b>value</b></td></tr>\n" $input.each { |key, value| print "<tr><td>" + key + "</td><td>" + value + "</td></tr>\n" } print "</table>\n" end print <<END </body> </html> END
RubyでCGIスクリプトを作る下準備・日時を求める
後々役に立ちそうな日時をもとめるルーチンを作ってみる。
海外サーバでも使えるようにグリニッジ標準時との時差を利用。
曜日に日本語を使いたいのでこんな感じになる。
曜日に英語なら1行で済むのでこれは不要。
getdate.rb
# # getdate.rb 日時を求めるRubyライブラリ # OFFSET = 9 * 60 * 60 # グリニッジ標準時との時差(秒) TIME = Time.now.gmtime + OFFSET def getdate yy = "#{TIME.year}" mm = TIME.mon >= 10 ? "#{TIME.mon}" : "0#{TIME.mon}" dd = TIME.day >= 10 ? "#{TIME.day}" : "0#{TIME.day}" h = TIME.hour >= 10 ? "#{TIME.hour}" : "0#{TIME.hour}" m = TIME.min >= 10 ? "#{TIME.min}" : "0#{TIME.min}" s = TIME.sec >= 10 ? "#{TIME.sec}" : "0#{TIME.sec}" week = ["日", "月", "火", "水", "木", "金", "土"] w = week[TIME.wday] yy + "/" + mm + "/" + dd + " (" + w + ") "+ h + ":" + m + ":" + s end
ライブラリを呼び出すテストはこんな感じ。
test.rb
#!/usr/local/bin/ruby require "getdata.rb" DATE = getdate print DATE + "\n"
オブジェクト指向言語RubyでCGIスクリプト
手始めに環境変数を表示するテスト
#!/usr/local/bin/ruby print <<END Content-Type: text/html <html> <head> <title>ENV TEST</title> </head> <body> <h1>ENV TEST</h1> <table border=1> <tr><td><b>key</b></td><td><b>value</b></td></tr> END ENV.each { |key, value| print "<tr><td>#{key}</td><td>#{value}</td></tr>\n" } print <<END </table> </body> </html> END
表示をHTTP、REMOTEで始まる環境変数のみにしぼる
#!/usr/local/bin/ruby print <<END Content-Type: text/html <html> <head> <title>ENV TEST</title> </head> <body> <h1>ENV TEST</h1> <table border=1> <tr><td><b>key</b></td><td><b>value</b></td></tr> END ENV.each { |key, value| if key =~ /^HTTP/ || key =~ /^REMOTE/ print "<tr><td>#{key}</td><td>#{value}</td></tr>\n" end } print <<END </table> </body> </html> END