Ruby_08_CGI编程
Ruby CGI 编程
Ruby 是一门通用的语言,不仅仅是一门应用于WEB开发的语言,但 Ruby 在WEB应用及WEB工具中的开发是最常见的。
使用Ruby您不仅可以编写自己的SMTP服务器,FTP程序,或Ruby Web服务器,而且还可以使用Ruby进行CGI编程。
接下来,让我们花点时间来学校Ruby的CGI编辑。
网页浏览
为了更好的了解CGI是如何工作的,我们可以从在网页上点击一个链接或URL的流程:
- 1、使用你的浏览器访问URL并连接到HTTP web 服务器。
- 2、Web服务器接收到请求信息后会解析URL,并查找访问的文件在服务器上是否存在,如果存在返回文件的内容,否则返回错误信息。
- 3、浏览器从服务器上接收信息,并显示接收的文件或者错误信息。
CGI程序可以是 Ruby 脚本,Python 脚本,PERL 脚本,SHELL 脚本,C 或者 C++ 程序等。
CGI架构图
Web服务器支持及配置
在你进行CGI编程前,确保您的Web服务器支持CGI及已经配置了CGI的处理程序。
Apache 支持CGI 配置:
设置好CGI目录:
ScriptAlias /cgi-bin/ /var/www/cgi-bin/
所有的HTTP服务器执行CGI程序都保存在一个预先配置的目录。这个目录被称为CGI目录,并按照惯例,它被命名为/var/www/cgi-bin目录。
CGI文件的扩展名为.cgi,Ruby 也可以使用 .rb 扩展名。
默认情况下,Linux服务器配置运行的cgi-bin目录中为/var/www。
如果你想指定其他运行CGI脚本的目录,可以修改httpd.conf配置文件,如下所示:
<Directory "/var/www/cgi-bin">
AllowOverride None
Options +ExecCGI
Order allow,deny
Allow from all
</Directory>
在 AddHandler 中添加 .rb 后缀,这样我们就可以访问 .rb 结尾的 Ruby 脚本文件:
AddHandler cgi-script .cgi .pl .rb
编写 CGI 脚本
最脚本的 Ruby CGI 代码如下所示:
#!/usr/bin/ruby puts "HTTP/1.0 200 OK" puts "Content-type: text/html\n\n" puts "This is a test"
你可以将该代码保持到 test.cgi 文件中,上次到服务器并赋予足够权限,即可作为 CGI 脚本执行。
如果你站的的地址为http://www.example.com/ ,即可用过http://www.example.com/test.cgi 访问该程序,输出结果为: "This is a test."。
浏览器访问该网址后,Web 服务器会在站点目录下找到 test.cgi文件,然后通过Ruby解析器来解析脚本代码并访问HTML文档。
使用 cgi.rb
Ruby 可以调用 CGI 库来编写更复杂的CGI脚本。
以下代码调用了 CGI 库来创建一个脚本的CGI脚本。
#!/usr/bin/ruby
require 'cgi'
cgi = CGI.new
puts cgi.header
puts "<html><body>This is a test</body></html>"
以下代码中,创建了CGI 对象并打印头部信息。
表单处理
使用CGI库可以通过两种方式获取表单提交(或URL中的参数)的数据, 例如URL:/cgi-bin/test.cgi?FirstName=Zara&LastName=Ali。
你可以使用 CGI#[] 来直接获取参数FirstName和LastName:
#!/usr/bin/ruby
require 'cgi'
cgi = CGI.new
cgi['FirstName'] # => ["Zara"]
cgi['LastName'] # => ["Ali"]
另外一种获取表单数据的方法:
#!/usr/bin/ruby
require 'cgi'
cgi = CGI.new
h = cgi.params # => {"FirstName"=>["Zara"],"LastName"=>["Ali"]}
h['FirstName'] # => ["Zara"]
h['LastName'] # => ["Ali"]
以下代码用于检索所有的键值:
#!/usr/bin/ruby
require 'cgi'
cgi = CGI.new
cgi.keys # => ["FirstName", "LastName"]
如果表单包含了多个相同名称的字段,则该相同字段的值将保存在数组中。
以下实例中,指定表单中三个相同的字段"name",值分别为 "Zara", "Huma" 和 "Nuha":
#!/usr/bin/ruby
require 'cgi'
cgi = CGI.new
cgi['name'] # => "Zara"
cgi.params['name'] # => ["Zara", "Huma", "Nuha"]
cgi.keys # => ["name"]
cgi.params # => {"name"=>["Zara", "Huma", "Nuha"]}
注意:Ruby 会自动判断 GET 和 POST 方法,所以无需对两种方法区别对待。
以下是相关的HML代码:
<html>
<body>
<form method="POST" action="http://www.example.com/test.cgi">
First Name :<input type="text" name="FirstName" value="" />
<br />
Last Name :<input type="text" name="LastName" value="" />
<input type="submit" value="Submit Data" />
</form>
</body>
</html>
创建 Form 表单和 HTML
CGI 包含了大量的方法来创建 HTML,每个HTML标签都有相对应的方法。 在使用这些方法前,比必须通过 CGI.new 来创建 CGI 对象。
为了使标签的嵌套更加的简单,这些方法将内容作为了代码块,代码块将返回字符串作为标签的内容。如下所示:
#!/usr/bin/ruby
require "cgi"
cgi = CGI.new("html4")
cgi.out{
cgi.html{
cgi.head{ "\n"+cgi.title{"This Is a Test"} } +
cgi.body{ "\n"+
cgi.form{"\n"+
cgi.hr +
cgi.h1 { "A Form: " } + "\n"+
cgi.textarea("get_text") +"\n"+
cgi.br +
cgi.submit
}
}
}
}
字符串转义
当你在处理 URL 中的参数或者 HTML 表单数据时,需要对指定的特殊字符进行转义,如:引号("),反斜杠(/)。
Ruby CGI 对象提供了CGI.escape 和 CGI.unescape 方法来处理这些特殊字符的转义:
#!/usr/bin/ruby
require 'cgi'
puts CGI.escape(Zara Ali/A Sweet & Sour Girl")
以上代码执行结果如下:
#!/usr/bin/ruby
require 'cgi'
puts CGI.escape(Zara Ali/A Sweet & Sour Girl")
另一组实例:
#!/usr/bin/ruby
require 'cgi'
puts CGI.escapeHTML('<h1>Zara Ali/A Sweet & Sour Girl</h1>')
以上代码执行结果如下:
<h1>Zara Ali/A Sweet & Sour Girl</h1>'
CGI 类中常用的方法
以下是Ruby中完整的CGI类的相关方法
- Ruby CGI - 标准 CGI 库相关方法
Cookies 和 Sessions
- Ruby CGI Cookies - 如何处理 CGI Cookies.
- Ruby CGI Sessions - 如何处理 CGI sessions.
Ruby CGI方法
以下为CGI类的方法列表:
序号 | 方法描述 |
---|---|
1 | CGI::new([ level="query"]) 创建 CGI 对象。query可以是以下值:
|
2 | CGI::escape( str) 使用 URL 编码来转义字符串 |
3 | CGI::unescape( str) 对通过 escape() 编码的字符串进行解码。 |
4 | CGI::escapeHTML( str) 编码 HTML 特殊字符, 包括: & < >。 |
5 | CGI::unescapeHTML( str) 解码 HTML 特殊字符, 包括: & < >。 |
6 | CGI::escapeElement( str[, element...]) 在指定的 HTML 元素中编码 HTML 特殊字符。 |
7 | CGI::unescapeElement( str, element[, element...]) 在指定的 HTML 元素中解码 HTML 特殊字符。 |
8 | CGI::parse( query) 解析查询字符串,并返回包含哈希的 键=》值 对。 |
9 | CGI::pretty( string[, leader=" "]) 返回整齐的HTML格式。 如果指定了 leader ,它将写入到每一行的开头。 leader 默认值为两个空格。 |
10 | CGI::rfc1123_date( time) 根据 RFC-1123 来格式化时间 (例如, Tue, 2 Jun 2008 00:00:00 GMT)。 |
CGI 实例化方法
以下实例中我们将 CGI::new 的对象赋值给 c 变量,方法列表如下:
序号 | 方法描述 |
---|---|
1 | c[ name] 返回一个数组,包含了对应字段名为 name 的值。 |
2 | c.checkbox( name[, value[, check=false]]) c.checkbox( options) 返回 HTML 字符串用于定义 checkbox 字段。标签的属性可以以一个哈希函数作为参数传递。 |
3 | c.checkbox_group( name, value...) c.checkbox_group( options) >返回 HTML 字符串用于定义 checkbox 组。标签的属性可以以一个哈希函数作为参数传递。 |
4 | c.file_field( name[, size=20[, max]]) c.file_field( options) 返回定义 file 字段的HTML字符串。 |
5 | c.form([ method="post"[, url]]) { ...} c.form( options) 返回定义 form 表单的HTML字符串。 如果指定了代码块,将作为表单内容输出。标签的属性可以以一个哈希函数作为参数传递。 |
6 | c.cookies 返回 CGI::Cookie 对象,包含了cookie 中的键值对。 |
7 | c.header([ header]) 返回 CGI 头部的信息。如果 header 参数是哈希值,其键 - 值对,用于创建头部信息。 |
8 | c.hidden( name[, value]) c.hidden( options) 返回定义一个隐藏字段的HTML字符串。标签的属性可以以一个哈希函数作为参数传递。 |
9 | c.image_button( url[, name[, alt]]) c.image_button( options) 返回定义一个图像按钮的HTML字符串。标签的属性可以以一个哈希函数作为参数传递。 |
10 | c.keys 返回一个数组,包含了表单的字段名。 |
11 | c.key?( name) c.has_key?( name) c.include?( name) 如果表单包含了指定的字段名返回 true。 |
12 | c.multipart_form([ url[, encode]]) { ...} c.multipart_form( options) { ...} 返回定义一个多媒体表单(multipart)的HTML字符串。标签的属性可以以一个哈希函数作为参数传递。 |
13 | c.out([ header]) { ...} 生成 HTML 并输出。使用由块的输出来创建页面的主体生成的字符串。 |
14 | c.params 返回包含表单字段名称和值的哈希值。 |
15 | c.params= hash 设置使用字段名和值。 |
16 | c.password_field( name[, value[, size=40[, max]]]) c.password_field( options) 返回定义一个password字段的HTML字符串。标签的属性可以以一个哈希函数作为参数传递。 |
17 | c.popup_menu( name, value...) c.popup_menu( options) c.scrolling_list( name, value...) c.scrolling_list( options) 返回定义一个弹出式菜单的HTML字符串。标签的属性可以以一个哈希函数作为参数传递。 |
18 | c.radio_button( name[, value[, checked=false]]) c.radio_button( options) 返回定义一个radio字段的HTML字符串。标签的属性可以以一个哈希函数作为参数传递。 |
19 | c.radio_group( name, value...) c.radio_group( options) 返回定义一个radio按钮组的HTML字符串。标签的属性可以以一个哈希函数作为参数传递。 |
20 | c.reset( name[, value]) c.reset( options) 返回定义一个reset按钮的HTML字符串。 标签的属性可以以一个哈希函数作为参数传递 |
21 | c.text_field( name[, value[, size=40[, max]]]) c.text_field( options) 返回定义一个text字段的HTML字符串。标签的属性可以以一个哈希函数作为参数传递。 |
22 | c.textarea( name[, cols=70[, rows=10]]) { ...} c.textarea( options) { ...} 返回定义一个textarea字段的HTML字符串。 如果指定了块,代码块输出的字符串将作为 textarea 的内容。 标签的属性可以以一个哈希函数作为参数传递。 |
HTML 生成方法
你可以再 CGI 实例中使用相应的 HTML 标签名来创建 HTML 标签,实例如下:
#!/usr/bin/ruby
require "cgi"
cgi = CGI.new("html4")
cgi.out{
cgi.html{
cgi.head{ "\n"+cgi.title{"This Is a Test"} } +
cgi.body{ "\n"+
cgi.form{"\n"+
cgi.hr +
cgi.h1 { "A Form: " } + "\n"+
cgi.textarea("get_text") +"\n"+
cgi.br +
cgi.submit
}
}
}
}
CGI 对象属性
你可以再 CGI 实例中使用以下属性:
属性 | 返回值 |
---|---|
accept | 可接受的 MIME 类型 |
accept_charset | 可接受的字符集 |
accept_encoding | 可接受的编码 |
accept_language | 可接受的语言 |
auth_type | 可接受的类型 |
raw_cookie | Cookie 数据 (原字符串) |
content_length | 内容长度(Content length) |
content_type | 内容类型(Content type) |
From | Client e-mail 地址 |
gateway_interface | CGI 版本 |
path_info | 路径 |
path_translated | 转换后的路径 |
Query_string | 查询字符串 |
referer | 之前访问网址 |
remote_addr | 客户端主机地址(IP) |
remote_host | 客户端主机名 |
remote_ident | 客户端名 |
remote_user | 经过身份验证的用户 |
request_method | 请求方法(GET, POST, 等。) |
script_name | 参数名 |
server_name | 服务器名 |
server_port | 服务器端口 |
server_protocol | 服务器协议 |
server_software | 服务器软件 |
user_agent | 用户代理(User agent) |
Ruby CGI Cookies
HTTP协议是无状态协议。但对于一个商业网站,它需要保持不同的页面间的会话信息。
如用户在网站注册过程中需要跳转页面,但又要保证之前填写的信息部丢失。
这种情况下 Cookie 很好的帮我们解决了问题。
Cookie 是如何工作的?
几乎所有的网站设计者在进行网站设计时都使用了Cookie,因为他们都想给浏览网站的用户提供一个更友好的、人文化的浏览环境,同时也能更加准确地收集访问者的信息。写入和读取
Cookies集合是附属于Response对象及Request对象的数据集合,使用时需要在前面加上Response或Request。
用于给客户机发送Cookies的语法通常为:
当给不存在的Cookies集合设置时,就会在客户机创建,如果该Cookies己存在,则会被代替。由于Cookies是作为HTTP传输的头信息的一部分发给客户机的,所以向客户机发送Cookies的代码一般放在发送给浏览器的HTML文件的标记之前。
如果用户要读取Cookies,则必须使用Request对象的Cookies集合,其使用方法是: 需要注意的是,只有在服务器未被下载任何数据给浏览器前,浏览器才能与Server进行Cookies集合的数据交换,一旦浏览器开始接收Server所下载的数据,Cookies的数据交换则停止,为了避免错误,要在程序和前面加上response.Buffer=True。
集合的属性
- 1.Expires属性:此属性用来给Cookies设置一个期限,在期限内只要打开网页就可以调用被保存的Cookies,如果过了此期限Cookies就自动被删除。如: 设定Cookies的有效期到2004年4月1日,到时将自动删除。如果一个Cookies没有设定有效期,则其生命周期从打开浏览器开始,到关闭浏览器结束,每次运行后生命周期将结束,下次运行将重新开始。
- 2.Domain属性:这个属性定义了Cookies传送数据的唯一性。若只将某Cookies传送给_blank">搜狐主页时,则可使用如下代码:
- 3.Path属性:定义了Cookies只发给指定的路径请求,如果Path属性没有被设置,则使用应用软件的缺省路径。
- 4.Secure属性:指定Cookies能否被用户读取。
- 5、Name=Value : Cookies是以键值对的形式进行设置和检索的。
Ruby 中处理Cookies
你可以创建一个名为 cookie 的对象并存储文本信息,将该信息发送至浏览器,调用 CGI.out 设置cookie的头部:
#!/usr/bin/ruby
require "cgi"
cgi = CGI.new("html4")
cookie = CGI::Cookie.new('name' => 'mycookie',
'value' => 'Zara Ali',
'expires' => Time.now + 3600)
cgi.out('cookie' => cookie) do
cgi.head + cgi.body { "Cookie stored" }
end
接下来我们回到这个页面,并查找cookie值,如下所示:
#!/usr/bin/ruby
require "cgi"
cgi = CGI.new("html4")
cookie = cgi.cookies['mycookie']
cgi.out('cookie' => cookie) do
cgi.head + cgi.body { cookie[0] }
end
CGI::Cookie对象实例化时包含以下参数:
参数 | 描述 |
---|---|
name | 规定 cookie 的名称。 |
value | 规定 cookie 的值。 |
expire | 规定 cookie 的有效期。 |
path | 规定 cookie 的服务器路径。 |
domain | 规定 cookie 的域名。 |
secure | 规定是否通过安全的 HTTPS 连接来传输 cookie。 |
Ruby CGI Sessions
CGI::Session 可以为用户和CGI环境保存持久的会话状态,会话使用后需要关闭,这样可以保证数据写入到存储当中,当会话完成后,你需要删除该数据。
#!/usr/bin/ruby
require 'cgi'
require 'cgi/session'
cgi = CGI.new("html4")
sess = CGI::Session.new( cgi, "session_key" => "a_test",
"prefix" => "rubysess.")
lastaccess = sess["lastaccess"].to_s
sess["lastaccess"] = Time.now
if cgi['bgcolor'][0] =~ /[a-z]/
sess["bgcolor"] = cgi['bgcolor']
end
cgi.out{
cgi.html {
cgi.body ("bgcolor" => sess["bgcolor"]){
"The background of this page" +
"changes based on the 'bgcolor'" +
"each user has in session." +
"Last access time: #{lastaccess}"
}
}
}
访问 "/cgi-bin/test.cgi?bgcolor=red" 将跳转到指定背景颜色的页面。
会话数据存在在服务器的临时文件目录中,prefix 参数指定了会话的前缀,将作为临时文件的前缀。这样你在服务器上可以轻松的识别不同的会话临时文件。
CGI::Session 类
CGI::Session 保持了用户与 CGI 环境的持久状态。 会话可以在内存中,也可以在硬盘上。
类方法
Ruby 类 Class CGI::Session 提供了简单的方法来创建 session:
CGI::Session::new( cgi[, option])
启用一个新的 CGI 会话并返回相应的 CGI::Session 对象。选项可以是可选的哈希,可以是以下值:
- session_key: 键名保存会话 默认为 _session_id。
- session_id: 唯一的会话 ID。自动生成
- new_session: 如果为true,为当前会话创建一个新的Session id。 如果为 false, 通过 session_id 使用已存在的 session 标识。 如果省略该参数,如果可用则使用现有的会话,否则创建一个新的。
- database_manager: 用于保存 sessions 的类,可以是 CGI::Session::FileStore or CGI::Session::MemoryStore。默认为 FileStore。
- tmpdir: 对于 FileStore, 为 session 的错存储目录。
- prefix: 对于 FileStore, 为 session 文件的前缀。
实例化方法
序号 | 方法描述 |
---|---|
1 | [ ] 返回给定 key 的值。查看实例。 |
2 | [ ]= 设置给定 key 的值。 查看实例。 |
3 | delete 调用底层数据库管理的删除方法。对于 FileStore, 删除包含 session 的物理文件。 对于 MemoryStore, 从内存中移除 session 数据。 |
4 | update 调用底层数据库管理的更新方法。 对于 FileStore, 将 session 写入到磁盘中。 对于 MemoryStore则无效果。 |
未完待续,下一章节,つづく