類別 CGI

概述

通用閘道介面 (CGI) 是一種簡單的協定,用於將 HTTP 要求從網路伺服器傳遞至獨立程式,並將輸出傳回至網路瀏覽器。基本上,CGI 程式會使用在環境 (GET) 或透過 $stdin (POST) 傳遞的請求參數來呼叫,而它列印至 $stdout 的所有內容都會傳回至客戶端。

這個檔案包含 CGI 類別。這個類別提供用於擷取 HTTP 請求參數、管理 Cookie 和產生 HTML 輸出的功能。

檔案 CGI::Session 提供階段管理功能;請參閱該類別以取得更多詳細資料。

請參閱 www.w3.org/CGI/ 以取得有關 CGI 協定的更多資訊。

簡介

CGI 是個大型類別,提供多種類別的方法,其中許多方法都混合自其他模組。有些文件說明在這個類別中,有些在 CGI::QueryExtensionCGI::HtmlExtension 模組中。請參閱 CGI::Cookie 以取得有關處理 Cookie 的具體資訊,以及 cgi/session.rb (CGI::Session) 以取得有關階段的資訊。

對於查詢,CGI 提供方法來取得環境變數、參數、Cookie 和多部分請求資料。對於回應,CGI 提供方法來寫入輸出和產生 HTML。

請繼續閱讀以取得更多詳細資料。範例提供在最下方。

查詢

CGI 類別會動態混合參數和 cookie 解析功能、環境變數存取,以及支援解析來自 CGI::QueryExtension 模組的多重部分要求(包括上傳的檔案)。

環境變數

標準的 CGI 環境變數可用作 CGI 物件的唯讀屬性。以下是這些變數的清單

AUTH_TYPE               HTTP_HOST          REMOTE_IDENT
CONTENT_LENGTH          HTTP_NEGOTIATE     REMOTE_USER
CONTENT_TYPE            HTTP_PRAGMA        REQUEST_METHOD
GATEWAY_INTERFACE       HTTP_REFERER       SCRIPT_NAME
HTTP_ACCEPT             HTTP_USER_AGENT    SERVER_NAME
HTTP_ACCEPT_CHARSET     PATH_INFO          SERVER_PORT
HTTP_ACCEPT_ENCODING    PATH_TRANSLATED    SERVER_PROTOCOL
HTTP_ACCEPT_LANGUAGE    QUERY_STRING       SERVER_SOFTWARE
HTTP_CACHE_CONTROL      REMOTE_ADDR
HTTP_FROM               REMOTE_HOST

對於這些變數中的每一個,都有對應的屬性具有相同的名稱,但全部小寫且沒有前置的 HTTP_。content_lengthserver_port 是整數;其餘的都是字串。

參數

params() 方法會傳回要求中所有參數的雜湊,作為名稱/值清單對,其中值清單是一個包含一個或多個值的 ArrayCGI 物件本身也會表現為參數名稱到值的雜湊,但只會傳回每個參數名稱的單一值(作為 String)。

例如,假設要求包含具有多個值「藍色」和「綠色」的參數「favourite_colours」。會發生下列行為

cgi.params["favourite_colours"]  # => ["blue", "green"]
cgi["favourite_colours"]         # => "blue"

如果參數不存在,前一個方法會傳回一個空陣列,後一個會傳回一個空字串。測試參數是否存在最簡單的方法是使用 has_key? 方法。

Cookie

HTTP Cookie 會自動從要求中解析。它們可從 cookies() 存取器取得,它會傳回從 cookie 名稱到 CGI::Cookie 物件的雜湊。

多重部分要求

如果要求的方法是 POST,而其內容類型是 multipart/form-data,則它可能包含上傳的檔案。這些檔案會由 QueryExtension 模組儲存在要求的參數中。參數名稱通常是檔案輸入欄位的 name 屬性。然而,值不是字串,而是 IO 物件,對於小檔案是 IOString,對於較大檔案是 Tempfile。這個物件也有下列額外的單例方法

local_path()

上傳的檔案在本地檔案系統中的路徑

original_filename()

用戶端電腦上的檔案名稱

content_type()

檔案的內容類型

回應

CGI 類別提供傳送標頭和內容輸出至 HTTP 用戶端的方法,並混合 CGI::HtmlExtension 和 CGI::TagMaker 模組的程式化 HTML 產生方法。用於 HTML 產生的 HTML 精確版本在物件建立時指定。

寫入輸出

傳送輸出至 HTTP 用戶端的最簡單方式是使用 out() 方法。這將 HTTP 標頭作為雜湊參數,並透過區塊傳送主體內容。標頭可以使用 http_header() 方法產生為字串。輸出串流可以使用 print() 方法直接寫入。

產生 HTML

每個 HTML 元素都有對應的方法,用於將該元素產生為 String。此方法的名稱與元素相同,全部小寫。元素的屬性作為雜湊傳入,主體則作為無參數區塊傳入,評估為 String。HTML 產生模組知道哪些元素始終為空,並靜默地捨棄任何傳入的主體。它也知道哪些元素需要匹配的關閉標籤,哪些則不需要。但是,它不知道哪些屬性對哪些元素是合法的。

還有一些額外的 HTML 產生方法混合自 CGI::HtmlExtension 模組。這些方法包括不同類型表單輸入的個別方法,以及通常採用特定屬性的元素的方法,其中屬性可以直接指定為參數,而不是透過雜湊。

實用程式 HTML 逸出和其他方法類似於函數。

有些實用程式工具定義在 cgi/util.rb 中。包含後,您可以像函數一樣使用實用程式方法。

使用範例

取得表單值

require "cgi"
cgi = CGI.new
value = cgi['field_name']   # <== value string for 'field_name'
  # if not 'field_name' included, then return "".
fields = cgi.keys            # <== array of field names

# returns true if form has 'field_name'
cgi.has_key?('field_name')
cgi.has_key?('field_name')
cgi.include?('field_name')

小心!cgi['field_name'] 會傳回一個 Array,包含舊的 cgi.rb(包含在 Ruby 1.6 中)

取得雜湊形式的表單值

require "cgi"
cgi = CGI.new
params = cgi.params

cgi.params 是雜湊。

cgi.params['new_field_name'] = ["value"]  # add new param
cgi.params['field_name'] = ["new_value"]  # change value
cgi.params.delete('field_name')           # delete param
cgi.params.clear                          # delete all params

將表單值儲存至檔案

require "pstore"
db = PStore.new("query.db")
db.transaction do
  db["params"] = cgi.params
end

從檔案還原表單值

require "pstore"
db = PStore.new("query.db")
db.transaction do
  cgi.params = db["params"]
end

取得多部分表單值

require "cgi"
cgi = CGI.new
value = cgi['field_name']   # <== value string for 'field_name'
value.read                  # <== body of value
value.local_path            # <== path to local file of value
value.original_filename     # <== original filename of value
value.content_type          # <== content_type of value

且值具有 StringIOTempfile 類別方法。

取得 Cookie 值

require "cgi"
cgi = CGI.new
values = cgi.cookies['name']  # <== array of 'name'
  # if not 'name' included, then return [].
names = cgi.cookies.keys      # <== array of cookie names

且 cgi.cookies 是雜湊。

取得 Cookie 物件

require "cgi"
cgi = CGI.new
for name, cookie in cgi.cookies
  cookie.expires = Time.now + 30
end
cgi.out("cookie" => cgi.cookies) {"string"}

cgi.cookies # { "name1" => cookie1, "name2" => cookie2, ... }

require "cgi"
cgi = CGI.new
cgi.cookies['name'].expires = Time.now + 30
cgi.out("cookie" => cgi.cookies['name']) {"string"}

將 http 標頭和 html 字串列印至 $DEFAULT_OUTPUT ($>)

require "cgi"
cgi = CGI.new("html4")  # add HTML generation methods
cgi.out do
  cgi.html do
    cgi.head do
      cgi.title { "TITLE" }
    end +
    cgi.body do
      cgi.form("ACTION" => "uri") do
        cgi.p do
          cgi.textarea("get_text") +
          cgi.br +
          cgi.submit
        end
      end +
      cgi.pre do
        CGI.escapeHTML(
          "params: #{cgi.params.inspect}\n" +
          "cookies: #{cgi.cookies.inspect}\n" +
          ENV.collect do |key, value|
            "#{key} --> #{value}\n"
          end.join("")
        )
      end
    end
  end
end

# add HTML generation methods
CGI.new("html3")    # html3.2
CGI.new("html4")    # html4.01 (Strict)
CGI.new("html4Tr")  # html4.01 Transitional
CGI.new("html4Fr")  # html4.01 Frameset
CGI.new("html5")    # html5

一些公用程式方法

require 'cgi/util'
CGI.escapeHTML('Usage: foo "bar" <baz>')

一些類似函式的公用程式方法

require 'cgi/util'
include CGI::Util
escapeHTML('Usage: foo "bar" <baz>')
h('Usage: foo "bar" <baz>') # alias

常數

CR

String 用於回車

EOL

標準網路換行序列

HTTP_STATUS

HTTP 狀態碼。

LF

String 用於換行

MAX_MULTIPART_COUNT

多部分時請求參數的最大數量

NEEDS_BINMODE

處理是否需要二進制與文字

PATH_SEPARATOR

不同環境中的路徑分隔符號。

VERSION

屬性

accept_charset[R]

傳回此 CGI 實例的接受字元組。

公開類別方法

accept_charset() 按一下以切換原始碼

傳回所有新 CGI 實例的接受字元組。

# File lib/cgi/core.rb, line 759
def self.accept_charset
  @@accept_charset
end
accept_charset=(accept_charset) 按一下以切換原始碼

Set 所有新 CGI 實例的接受字元組。

# File lib/cgi/core.rb, line 764
def self.accept_charset=(accept_charset)
  @@accept_charset=accept_charset
end
new(tag_maker) { block } 按一下以切換原始碼
new(options_hash = {}) { block }

建立新的 CGI 實例。

tag_maker

這與使用具有值 { :tag_maker => tag_maker }options_hash 表單相同。請注意,建議使用 options_hash 表單,因為它也允許您指定您將接受的字元組。

options_hash

一個 Hash 識別三個選項

:accept_charset

指定接收到的查詢字串編碼。如果省略,將使用 @@accept_charset。如果編碼無效,將引發 CGI::InvalidEncoding

範例。假設 @@accept_charset 是「UTF-8」

未指定時

cgi=CGI.new      # @accept_charset # => "UTF-8"

指定為「EUC-JP」時

cgi=CGI.new(:accept_charset => "EUC-JP") # => "EUC-JP"
:tag_maker

String 指定要使用的 HTML 產生方法版本。如果未指定,將不會載入任何 HTML 產生方法。

支援下列值

「html3」

HTML 3.x

「html4」

HTML 4.0

「html4Tr」

HTML 4.0 過渡

「html4Fr」

HTML 4.0 含框架

「html5」

HTML 5

:max_multipart_length

指定多部分資料的最大長度。可以是 Integer 純量或 lambda,它會在解析要求時評估。這允許在決定是否接受多部分資料時設定更複雜的邏輯(例如,諮詢註冊使用者上傳配額)

預設為 128 * 1024 * 1024 位元組

cgi=CGI.new(:max_multipart_length => 268435456) # simple scalar

cgi=CGI.new(:max_multipart_length => -> {check_filesystem}) # lambda
區塊

如果提供,則在遇到無效編碼時呼叫區塊。例如

encoding_errors={}
cgi=CGI.new(:accept_charset=>"EUC-JP") do |name,value|
  encoding_errors[name] = value
end

最後,如果 CGI 物件未在標準 CGI 呼叫環境中建立(也就是說,它無法在環境中找到 REQUEST_METHOD),則它將在「離線」模式中執行。在此模式中,它會從命令列或(如果失敗)從標準輸入中讀取其參數。否則,cookie 和其他參數會自動從標準 CGI 位置解析,這會根據 REQUEST_METHOD 而有所不同。

# File lib/cgi/core.rb, line 850
def initialize(options = {}, &block) # :yields: name, value
  @accept_charset_error_block = block_given? ? block : nil
  @options={
    :accept_charset=>@@accept_charset,
    :max_multipart_length=>@@max_multipart_length
  }
  case options
  when Hash
    @options.merge!(options)
  when String
    @options[:tag_maker]=options
  end
  @accept_charset=@options[:accept_charset]
  @max_multipart_length=@options[:max_multipart_length]
  if defined?(MOD_RUBY) && !ENV.key?("GATEWAY_INTERFACE")
    Apache.request.setup_cgi_env
  end

  extend QueryExtension
  @multipart = false

  initialize_query()  # set @params, @cookies
  @output_cookies = nil
  @output_hidden = nil

  case @options[:tag_maker]
  when "html3"
    require_relative 'html'
    extend Html3
    extend HtmlExtension
  when "html4"
    require_relative 'html'
    extend Html4
    extend HtmlExtension
  when "html4Tr"
    require_relative 'html'
    extend Html4Tr
    extend HtmlExtension
  when "html4Fr"
    require_relative 'html'
    extend Html4Tr
    extend Html4Fr
    extend HtmlExtension
  when "html5"
    require_relative 'html'
    extend Html5
    extend HtmlExtension
  end
end
parse(query) 按一下以切換來源

將 HTTP 查詢字串解析成一個 key=>value 成對的雜湊。

params = CGI.parse("query_string")
  # {"name1" => ["value1", "value2", ...],
  #  "name2" => ["value1", "value2", ...], ... }
# File lib/cgi/core.rb, line 393
def self.parse(query)
  params = {}
  query.split(/[&;]/).each do |pairs|
    key, value = pairs.split('=',2).collect{|v| CGI.unescape(v) }

    next unless key

    params[key] ||= []
    params[key].push(value) if value
  end

  params.default=[].freeze
  params
end

公開實例方法

標頭
別名:http_header
http_header
別名:header
out(content_type_string='text/html') 按一下以切換來源
out(headers_hash)

將 HTTP 標頭和本文印出至 $DEFAULT_OUTPUT ($>)

content_type_string

如果傳遞字串,則假設它是內容類型。

headers_hash

這是標頭的 Hash,類似於 http_header 使用的標頭。

區塊

需要區塊,且應評估為回應的本文。

Content-Length 會根據內容區塊傳回的 String 大小自動計算。

如果 ENV['REQUEST_METHOD'] == "HEAD",則只會輸出標頭(仍需要內容區塊,但會忽略它)。

如果字元集是「iso-2022-jp」或「euc-jp」或「shift_jis」,則內容會轉換為此字元集,且語言會設定為「ja」。

範例

cgi = CGI.new
cgi.out{ "string" }
  # Content-Type: text/html
  # Content-Length: 6
  #
  # string

cgi.out("text/plain") { "string" }
  # Content-Type: text/plain
  # Content-Length: 6
  #
  # string

cgi.out("nph"        => true,
        "status"     => "OK",  # == "200 OK"
        "server"     => ENV['SERVER_SOFTWARE'],
        "connection" => "close",
        "type"       => "text/html",
        "charset"    => "iso-2022-jp",
          # Content-Type: text/html; charset=iso-2022-jp
        "language"   => "ja",
        "expires"    => Time.now + (3600 * 24 * 30),
        "cookie"     => [cookie1, cookie2],
        "my_header1" => "my_value",
        "my_header2" => "my_value") { "string" }
   # HTTP/1.1 200 OK
   # Date: Sun, 15 May 2011 17:35:54 GMT
   # Server: Apache 2.2.0
   # Connection: close
   # Content-Type: text/html; charset=iso-2022-jp
   # Content-Length: 6
   # Content-Language: ja
   # Expires: Tue, 14 Jun 2011 17:35:54 GMT
   # Set-Cookie: foo
   # Set-Cookie: bar
   # my_header1: my_value
   # my_header2: my_value
   #
   # string
# File lib/cgi/core.rb, line 367
def out(options = "text/html") # :yield:

  options = { "type" => options } if options.kind_of?(String)
  content = yield
  options["length"] = content.bytesize.to_s
  output = stdoutput
  output.binmode if defined? output.binmode
  output.print http_header(options)
  output.print content unless "HEAD" == env_table['REQUEST_METHOD']
end
print(*options) 按一下以切換來源

將引數或引數清單印出至預設輸出串流

cgi = CGI.new
cgi.print    # default:  cgi.print == $DEFAULT_OUTPUT.print

私有執行個體方法

_no_crlf_check(str) 按一下以切換來源
# File lib/cgi/core.rb, line 191
def _no_crlf_check(str)
  if str
    str = str.to_s
    raise "A HTTP status or header field must not include CR and LF" if str =~ /[\r\n]/
    str
  else
    nil
  end
end
env_table() 按一下以切換來源

ENV 同義。

# File lib/cgi/core.rb, line 59
def env_table
  ENV
end
stdinput() 按一下以切換來源

與 $stdin 同義。

# File lib/cgi/core.rb, line 64
def stdinput
  $stdin
end
stdoutput() 按一下以切換來源

與 $stdout 同義。

# File lib/cgi/core.rb, line 69
def stdoutput
  $stdout
end