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!("&", "&amp;")
  str.gsub!("<", "&lt;")
  str.gsub!(">", "&gt;")
  str.gsub!("\"", "&quot;")
  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