Ruby で CGI > 送受信_環境変数 ENV
ページの閲覧者が何もしなくても、ページを閲覧するだけで、閲覧者側のブラウザやサーバーが、CGI が置かれているサイト側のサーバーにいろいろなデータを送信しています。ここでは、これらを読み取って利用する方法を紹介します。
#!ruby p ENV
ハッシュの例:{"apple" => "ringo", "grape" => "budou"}
#!/usr/local/bin/ruby print <<EOS Content-Disposition: filename="env.txt" Content-type: text/plain EOS puts "%26s %s" % [ "key", "ENV[key]" ] puts "%26s %s" % ["--------------------------", "--------------------------"] for key in ENV.keys.sort do puts "%26s %s" % [ key , ENV[key] ] end puts "%26s %s" % ["--------------------------", "--------------------------"]
"%26s %s" % ["A", "B"]
は、書式化文字列です
プログラム: | print "%6s-%s**%03d" % ["A", "B", 7] |
出力結果⇒ | A-B**007 |
puts "%26s %s" % ["A", "B"]は、printf を使って、
printf("%26s %s\n", "A", "B")と書くこともできます。
\n
は改行。ENV.keys
は ENV のキーを列挙した配列です。.sort
をくっ付けて順番をアルファベット順に並べ替えています。
もしかしたら.sort
をつけない方が見やすいかもしれません。
for 要素 in 配列 do 動作 end
は、配列で与えられた要素を、次々とブロック do 〜 end に代入して実行させるものです。
プログラム: | for k in ["A","B"] do puts k end |
実行結果⇒ | A B |
プログラム: | for n in 1..3 do puts n end |
実行結果⇒ | 1 2 3 |
環境変数 | 内容 |
---|---|
ENV['REQUEST_URI'] | 接続に要求されたアドレス。アドレスの後ろにくっ付けられた「?」以降も表示。 |
ENV['SCRIPT_NAME'] | CGIプログラム自身が置かれている場所/ファイル名。携帯端末に対するLocation適用に便利。 |
ENV['SCRIPT_FILENAME'] | 上記のサーバー内部での値。 |
ENV['REMOTE_ADDR'] | 閲覧者が受信に使っているサーバーのIPアドレス(数字の組)。たいていは使用しているプロバイダーが割り出せる。 |
ENV['HTTP_REFERER'] | そのCGIに接続するためにクリックされたファイルの場所。「戻る」やリンク元の記録に便利。 |
ENV['HTTP_USER_AGENT'] | 閲覧者が使っているブラウザの名前。携帯電話の機種を自動判別するときなどに便利。 |
ENV['QUERY_STRING'] | アドレスの後ろに付けた「?」以降の文字列。外部から CGI への値の入力に便利。 |
ENV['HTTP_COOKIE'] | 閲覧者のブラウザに保存してあった cookie の内容 |
#!/usr/local/bin/ruby -Ks ua = ENV['HTTP_USER_AGENT'].to_s.gsub(/&/,"&").gsub(/</,"<").gsub(/>/,">").gsub(/"/,""") html = <<EOS <!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>Test CGI</title> </head> <body> <p>ご利用中の端末は、</p><pre>#{ ua }</pre><p>です。</p><hr> </body> </html> EOS print <<EOS Content-Disposition: filename="ua.html" Content-type: text/html Content-Length: #{ html.length } EOS print html
ENV['HTTP_USER_AGENT']
の値を html ファイルで表示させるのは、素のテキストファイルを表示できないケータイ端末があるからです.to_s
は文字列への変換を意味します。ENV['HTTP_USER_AGENT']の中身が空(nil)だった場合、空文字列に変換しておかないと、次の .gsub で例外が発生(=エラー)してしまうので、これを防止します。.gsub(/&/,"&")
は、文字「&」を見つけたら、「&」に取り替えます。続くその他も同様。html の表示を正しくするための対策です。#!/usr/local/bin/ruby -Ks f = File.open("user-agents.txt","a") f.print Time.now f.puts " ----------------" f.puts ENV['HTTP_USER_AGENT'] f.close ua = ENV['HTTP_USER_AGENT'].to_s.gsub(/&/,"&").gsub(/</,"<").gsub(/>/,">").gsub(/"/,""") html = <<EOS <!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>Test CGI</title> </head> <body> <p>接続ありがとうございます。ご利用中の端末は、</p><pre>#{ ua }</pre><p>です。</p><hr> </body> </html> EOS print <<EOS Content-Disposition: filename="ua.html" Content-type: text/html Content-Length: #{ html.length } EOS print html
/\bMSIE\b/ =~ ENV['HTTP_USER_AGENT'] && /\bOpera\b/ !~ ENV['HTTP_USER_AGENT']これが true なら ie 、false ならそれ以外です。 Opera を含まないようにするのは、 windows の場合に、opera がデフォルト(=無設定状態)で ie を偽装するから。
#!/usr/local/bin/ruby file = "pc.html" if /DoCoMo/i =~ ENV['HTTP_USER_AGENT'] then file = "docomo.html" elsif /(J\-PHONE)|Vodafone|SoftBank/i =~ ENV['HTTP_USER_AGENT'] then file = "softbank.html" elsif /(UP\.Browser)/i =~ ENV['HTTP_USER_AGENT'] then file = "au.html" end puts "Location: http://web9.ec.hokudai.ac.jp/123456z/" + file puts
DoCoMo | http://www.nttdocomo.co.jp/service/imode/make/content/spec/useragent/ |
au | http://www.au.kddi.com/ezfactory/tec/spec/4_4.html |
SoftBank | http://developers.vodafone.jp/dp/tool_dl/web/useragent.php |
/DoCoMo/i =~ hogehoge
は、hogehoge の中に「DoCoMo」という文字列が含まれていたら true、含まれていなかったら false となります。/DoCoMo/i の i は大文字と小文字を区別しないことを意味します。⇒ 正規表現#!/usr/local/bin/ruby print <<EOS Content-Disposition: filename="qs.txt" Content-type: text/plain ------/ ENV['QUERY_STRING'] /------ EOS puts ENV['QUERY_STRING']
h = Hash.new for q in ENV['QUERY_STRING'].to_s.split(/;/) do key,val = q.split(/=/,2) # = を境目にして2つに分ける h[key] = val if key && val # キーと値が空でなければ、ハッシュに格納(=代入)する end
h = Hash.new
は、h がハッシュであることを定めます.to_s
は文字列への変換を行います。ENV['QUERY_STRING']
が nil(=なにもない)だった場合に、空文字列に変換して、次に続く.split
による例外(=エラー)発生を未然に防ぎます。str.split(/;/)
は、文字列str
を;
を境目にして分割した配列を生成します.split(/=/,2)
の ,2
は、=
が複数あったとしても全部は分けずに、最初の=
で2つに分けることを意味します。ENV['HTTP_COOKIE']
を読み出しますSet-Cookie: (cookieの記述)
を書き込みます#!/usr/local/bin/ruby cookie1 = "QS=#{ ENV['QUERY_STRING'].to_s.gsub(/[;,\s]/,'') }; " cookie1 += ( Time.now + 15 ).gmtime.strftime("expires=%a, %d-%b-%Y %H:%M:%S %Z; ") cookie1 += "path=/; " print <<EOS Content-Disposition: filename="qs.txt" Content-type: text/plain Set-Cookie: #{ cookie1 } ------/ ENV['HTTP_COOKIE'] /------ #{ ENV['HTTP_COOKIE'] } ------/ ENV['QUERY_STRING'] /------ #{ ENV['QUERY_STRING'] } ------/ Set-Cookie: cookie1 /------ #{ cookie1 } EOS
ENV['HTTP_COOKIE']
の欄に、一つ前のアクセスで入力した QUERY_STRING が表示されているはずですTime.now + 15
の 15 をもっと大きな数字に変えてください。キーワード=記録させたい内容;
の部分は必ず冒頭に持ってきてください,
セミコロン;
スペース
が使えません。日本語は「URIエンコード」しなければなりません。path=/;
domain=web1.ec.hokudai.ac.jp;
)となりますdomain=.ec.hokudai.ac.jp;
と記述しておけば、
web.ec.hokudai.ac.jpでも、
web1.ec.hokudai.ac.jpでも、
web2.ec.hokudai.ac.jpでも使えます。Time.now + 15
は、今から15秒後を意味します.gmtime
は時刻の表記をグリニッジ標準時(協定世界時)にすることを意味します.strftime()
は時刻を書式化文字列に変換します ⇒ 詳細:Time#!/usr/local/bin/ruby cookie1 = "CK=" cookie1 += "qs=#{ ENV['QUERY_STRING'].to_s.gsub(/[:;,\s]/,"") }:" if ENV['QUERY_STRING'].to_s.length > 0 cookie1 += "TM=#{ Time.now.to_i }" cookie1 += "; " cookie1 += "path=/; " cookie1 += ( Time.now + 15 ).gmtime.strftime("expires=%a, %d-%b-%Y %H:%M:%S %Z; ") cookie2 = "ID=" if /ID=(\d+)\b/ =~ ENV['HTTP_COOKIE'].to_s then cookie2 += $1 else cookie2 += rand(100000000).to_s end cookie2 += "; path=/; " cookie2 += ( Time.now + 60*60*24*90 ).gmtime.strftime("expires=%a, %d-%b-%Y %H:%M:%S %Z; ") print <<EOS Content-Disposition: filename="qs.txt" Content-type: text/plain Set-Cookie: #{ cookie1 } Set-Cookie: #{ cookie2 } ------/ ENV['HTTP_COOKIE'] /------ #{ ENV['HTTP_COOKIE'] } ------/ ENV['QUERY_STRING'] /------ #{ ENV['QUERY_STRING'] } ------/ Set-Cookie: cookie1 /------ #{ cookie1 } ------/ Set-Cookie: cookie2 /------ #{ cookie2 } EOS
h = Hash.new for q in ENV['HTTP_COOKIE'].to_s.split(/;/) do key,val = q.split(/=/,2) # = を境目にして2つに分ける key = key.to_s.strip # 前後の空白を取り除く next if key == "" # 空っぽならスキップ h[key] = val # ハッシュに格納(=代入)する end
以上です。