CGI 类

概述

通用网关接口 (CGI) 是一个简单的协议,用于将 HTTP 请求从 Web 服务器传递到独立程序,并将输出返回到 Web 浏览器。基本上,CGI 程序使用在环境 (GET) 或通过 $stdin (POST) 中传递的请求参数进行调用,并且它打印到 $stdout 的所有内容都会返回给客户端。

此文件包含 CGI 类。此类提供用于检索 HTTP 请求参数、管理 Cookie 和生成 HTML 输出的功能。

文件 CGI::Session 提供会话管理功能;有关更多详细信息,请参阅该类。

有关 CGI 协议的更多信息,请参阅 www.w3.org/CGI/。

简介

CGI 是一个大型类,提供几类方法,其中很多都从其他模块混合而来。一些文档位于此类中,一些位于模块 CGI::QueryExtensionCGI::HtmlExtension 中。有关处理 cookie 的具体信息,请参阅 CGI::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”,其值有多个“blue”和“green”。将出现以下行为

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
block

如果提供,则在遇到无效编码时调用此块。例如

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

最后,如果 CGI 对象不是在标准 CGI 调用环境中创建的(即,它无法在其环境中找到 REQUEST_METHOD),那么它将在“脱机”模式下运行。在此模式下,它从命令行或(如果失败)从标准输入读取其参数。否则,cookie 和其他参数会根据 REQUEST_METHOD 从标准 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

公共实例方法

header
别名: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 使用的头。

block

需要一个块,并应评估为响应的主体。

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