Ruby で CGI > 出力方法
ここでは、ruby の使い方というよりは、HTTP の仕様とその使い方について、解説します。
CGI では、puts や print などで標準出力に書き出された内容が、そのまま読者のブラウザへと送られます。
標準出力へ書き出す内容は、ファイル名やファイルの種類などのデータの特性を表す「ヘッダ」部分と、表示させる本体を表す「ボディ」に分かれていて、その境い目は、最初の空行で表されます。
下記内容のファイルを作成し、ファイル名を test.cgi として、サーバーにアップロードし、接続してみてください。
#!/usr/local/bin/ruby
puts "Content-type: text/plain" # ヘッダ(データの情報)を出力
puts # 仕切りとして、空行を出力
puts "Hello world!" # ボディ(表示させる本体)を出力
#!/usr/local/bin/ruby print <<KEYWORD Content-type: text/plain Hello world! KEYWORD
test.cgi を下記の内容に書き直して、サーバーにアップロードし、接続してみてください。
#!/usr/local/bin/ruby -Ks print <<KEYWORD Content-type: text/plain;charset=Shift_JIS 世界のみなさん、こんにちは。 KEYWORD
文字コード | オプション | 特徴 |
Shift_JIS | -Ks | Windows標準。とっても古い文字体系。ボロいケータイ端末でも表示できる。 |
EUC-jp | -Ke | UNIX系サーバーで多く採用されている。Shift_JIS より新しい。 |
UTF-8 | -Ku | 世界中の文字を表せる。これからの標準。なるべくこれを使いたい。 |
test.cgi を下記の内容に書き直して、サーバーにアップロードし、接続してみてください。
#!/usr/local/bin/ruby -Ks
print <<KEYWORD
Content-Disposition: filename="hello.txt"
Content-type: text/plain;charset=Shift_JIS
世界のみなさん、こんにちは。
KEYWORD
test.cgi を下記の内容に書き直して、サーバーにアップロードし、接続してみてください。
#!/usr/local/bin/ruby -Ks print <<KEYWORD Content-Disposition: filename="hello.html" Content-Type: text/html;charset=Shift_JIS <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS"> <title>テストページ</title> </head> <body> <p>世界のみなさん、こんにちは。</p> </body> </html> KEYWORD
-Ks
、Content-Type:
の charset
、html 文中のmetaタグ等による文字コード指定、ファイル保存時の文字コード。
通信が完了する前にプログラムが終了してしまうことに起因して、受信されるデータが途中で切れてしまう場合があります。 送受信双方の仕様によっては、この問題はめったに起こりませんが、送信側の設定が特殊だったり、受信側が i-mode などだったりすると、どうなるかわかりません。 予めデータの長さが明示されていれば、送信の完了が受け手側でわかるので、このような中断を未然に防ぐことができます。(たぶん)
#!/usr/local/bin/ruby -Ks html = <<KEYWORD <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS"> <title>テストページ</title> </head> <body> <p>世界のみなさん、こんにちは。</p> </body> </html> KEYWORD print <<KEYWORD Content-Disposition: filename="hello.html" Content-Type: text/html;charset=Shift_JIS Content-Length: #{ html.length } KEYWORD print html
Content-Length: 10
とするならば、データ長さは10バイト(=アルファベット 10 文字分)ということになります。(注意:単位はビットではない。)#{ }
を使って、値を文字列として代入することができます。(文字列).length
で、文字列のデータ長さを測ることができます。これは、文字数ではないので注意。文字数を測りたい場合は、例えば、1文字づつの配列に直して、要素の数を数えます。文字コード Shift_JIS の場合:html.split(//s).length
test.cgi を下記の内容に書き直して、サーバーにアップロードし、接続してみてください。
同じディレクトリ内に、ファイル名 hogahoge.gif の GIF 画像も置いてください。
#!/usr/local/bin/ruby # ↓ヘッダ部分と空行を出力 print <<KEYWORD Content-Disposition: filename="hello.gif" Content-type: image/gif Content-Length: #{ File.size("hogahoge.gif") } KEYWORD f = File.open("hogahoge.gif","rb") # 画像ファイルを開く STDOUT.binmode # ←たいていは不要。一部のマイクロソフト社製サーバーで有効。 while line = f.gets do # データを1行づつ読み込み変数lineに写し取る print line # 画像データを出力 end f.close # 画像ファイルを閉じる
while ○ do 〜 end
は、○が true か又は何かの値がある間、〜を繰り返します。○が nil(=空っぽ) か false(=偽) の場合は、〜を実行せずに、繰り返しを終了します。⇒ whileline = f.gets
は、開いたファイル f から、値を1行だけ読み出し、line に代入します。一度読み出した行は、再び読まれることが無いので、これを繰り返すことによって、行を次々と逐次取り出すことができます。もう読み出す行が残っていない場合は、f.gets
は nil を出力します。⇒ getstest.cgi を下記の内容に書き直して、サーバーにアップロードし、接続してみてください。
同じディレクトリ内に、ファイル名 hogahoge.gif の GIF 画像も置いてください。
#!/usr/local/bin/ruby puts "Location: ./hogahoge.gif" puts
#!/usr/local/bin/ruby puts "Location: #{ File.dirname( ENV['SCRIPT_NAME'] ) }/hogahoge.gif" putsENV['SCRIPT_NAME'] は、CGI 自体の URL です。File.dirname() で、ディレクトリの記述部分だけを抜き出します。
#!/usr/local/bin/ruby puts "Location: http://#{ ENV['HTTP_HOST'] }#{ File.dirname( ENV['SCRIPT_NAME'] ) }/hogahoge.gif" putsより多く一般の場合:
#!/usr/local/bin/ruby puts "Location: #{ File.dirname( ENV['REQUEST_URI'].split(/\?/).shift ) }/hogahoge.gif" puts
#!/usr/local/bin/ruby r = rand(2) puts "Location: http://www.hokudai.ac.jp/" if r == 0 puts "Location: http://www.google.co.jp/" if r == 1 puts
HTTP/1.1 301 Moved Permanently
Location: http://www.google.com/
Set-Cookie: (省略)
Content-Type: text/html
Server: GWS/2.1
Content-Length: 219
Date: Fri, 07 Sep 2007 00:37:26 GMT
<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>301 Moved</TITLE></HEAD><BODY>
<H1>301 Moved</H1>
The document has moved
<A HREF="http://www.google.com/">here</A>.
</BODY></HTML>
「状態コード301」に関しては、次のリンクを参照願います。Connection: Keep-Alive信号が途絶えても、切らずに受信を続けろという意味です。
Expires: -1 Pragma: no-cache Cache-Control: no-cache…たぶん、これでいけると思いますが、使えなかったらすみません。
#!ruby for file in Dir.glob("**/*.cgi") do f = open(file) s = f.read f.close if /^...#/ =~ s then f = open(file,"w") f.print s.sub(/^...#/,"#") f.close puts file end end
ヘッダは通常は表示されませんが、必ずページの内容と一緒に送られてくるものなので、簡単に見ることができます。 いろいろなサイトや CGI のヘッダを観察して、意味を調べてみてください。
コマンドラインから、下記のように入力してみる
curl -I http://www.google.co.jpcurl が使えなかった場合、下記のスクリプトで、ヘッダの値を取得できます。
#!ruby
require 'net/http'
uri = <<URLHERE
http://www.ruby-lang.org/ja/man/?cmd=view;name=Net%3A%3AHTTP
URLHERE
dom,pth = uri.to_s.chomp.sub(/\A[\s\w]+:\/\/+/,"").split(/\//,2)
pth = "/" + pth.to_s
h = nil
Net::HTTP.version_1_2
Net::HTTP.start(dom) {|http|
h = http.head(pth)
}
h.each do |key,val|
key += ": "
print key.ljust(16)
puts val
end
以上です。