CGI环境变量、HTTP请求头、正则表达式及ASCII表详解
1. CGI环境变量
CGI程序能以多种形式接收信息,其中CGI环境变量是非常实用的一种。这些变量由父Web服务器进程提供给CGI程序,服务器依据三个不同来源的信息创建这些变量:
- 传入的HTTP请求:可提供
REMOTE_ADDR
信息。
- Web服务器程序自身:例如
SERVER_SOFTWARE
变量由Web服务器提供。
- Web客户端提供给Web服务器的HTTP请求头:像
REQUEST_METHOD
、
CONTENT_TYPE
、
QUERY_STRING
等信息,由Web服务器从HTTP请求头中提取并放入环境变量。
部分环境变量由上述多个来源的信息组合填充。例如,
REMOTE_HOST
需要
REMOTE_ADDR
,还要求服务器能为给定的IP地址解析出名称;
PATH_TRANSLATED
部分来自Web客户端请求的URL,部分来自Web服务器软件确定的服务器目录结构。
有些从HTTP请求头派生的环境变量并非CGI规范严格要求的,但CGI规范为Web客户端提供了扩展Web服务器提供给CGI程序的标准环境变量集的方法。一个非常流行的通过此扩展派生的CGI环境变量是
HTTP_USER_AGENT
,它包含用于调用CGI程序的Web客户端软件的名称,在创建生成特定浏览器网页的CGI程序时至关重要。扩展派生的变量以
HTTP_
为前缀。
以下是标准CGI规范环境变量以及一些非常流行的扩展派生变量的表格:
| CGI环境变量 | 描述 |
| — | — |
| AUTH_TYPE | 用于验证用户的特定协议认证方法(如适用) |
| CONTENT_LENGTH | Web客户端提供的附加注释的字节数,可参考
CONTENT_TYPE
环境变量 |
| CONTENT_TYPE | 附加到Web客户端创建的HTTP头的数据内容类型(如果有),例如
POST
和
PUT
|
| HTTP_ACCEPT | 客户端将接受的MIME类型,由HTTP响应头给出。这是一个扩展变量,虽不属于基本CGI环境变量规范,但使用极为普遍 |
| HTTP_USER_AGENT | 客户端用于发送请求的浏览器。这是一个扩展变量,虽不属于基本CGI环境变量规范,但使用极为普遍 |
| GATEWAY_INTERFACE | 此服务器遵循的CGI规范版本 |
| PATH_INFO | Web客户端提供的额外路径信息 |
| PATH_TRANSLATED | Web服务器创建的
PATH_INFO
的转换版本,会进行必要的虚拟到物理的映射 |
| QUERY_STRING | 引用相关CGI程序的URL中
?
后面的信息 |
| REMOTE_ADDR | 发出请求的远程主机的IP地址 |
| REMOTE_HOST | 发出请求的远程主机的DNS名称。如果服务器无法获取此信息,可能有两种情况:要么服务器不设置此变量,要么将其设置为与
REMOTE_ADDR
相同的值 |
| REMOTE_IDENT | 如果HTTP服务器和客户端都支持RFC 931标识,此变量将设置为从服务器检索到的远程用户名 |
| REMOTE_USER | 如果服务器支持用户认证且脚本受保护,这是用户认证的用户名 |
| REQUEST_METHOD | 用于发出HTTP请求的方法,最可能是
GET
或
POST
|
| SCRIPT_NAME | 正在执行的脚本的虚拟路径,用于自引用URL |
| SERVER_NAME | 服务器的主机名、DNS别名或IP地址,会出现在自引用URL中 |
| SERVER_PORT | HTTP请求发送到的端口号 |
| SERVER_PROTOCOL | 请求所使用的协议的名称和版本,几乎总是
HTTP
|
| SERVER_SOFTWARE | 响应请求的Web服务器软件的名称和版本 |
下面是一个简单实用的Perl程序
showenv.cgi
,用于输出所有适用的环境变量:
#!/usr/local/bin/perl
print "Content-type: text/plain\n\n";
while (($key,$value) = each %ENV) {
print "[$key]\t[$value]\n";
}
需要注意的是,
%ENV
是Perl用于存储环境变量信息的哈希数组。
运行上述代码后,可能会得到如下输出(名称和IP地址已更改):
[SERVER_SOFTWARE] [NCSA/1.5]
[GATEWAY_INTERFACE] [CGI/1.1]
[DOCUMENT_ROOT] [/var/spool/www]
[REMOTE_ADDR] [255.255.255.255]
[SERVER_PROTOCOL] [HTTP/1.0]
[REQUEST_METHOD] [GET]
[REMOTE_HOST] [www.mywebsite.com]
[QUERY_STRING] []
[HTTP_USER_AGENT] [Mozilla/4.04 [en] (WinNT; U) via Harvest Cache version 2.1-beta-internal-41]
[PATH] [/bin:/usr/bin:/usr/ucb:/usr/bsd:/usr/local/bin:.]
[HTTP_CONNECTION] [Keep-Alive]
[HTTP_ACCEPT] [image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*]
[HTTP_ACCEPT_LANGUAGE] [en]
[SCRIPT_NAME] [/show_env_var.cgi]
[SERVER_NAME] [www.mywebsite.com]
[HTTP_ACCEPT_CHARSET] [iso-8859-1,*,utf-8]
[SERVER_PORT] [80]
[HTTP_HOST] [www.mywebsite.com]
[HTTP_VHOSTING_AGENT] [255.255.255.255 via www.mywebsite.com:80 to www2.mywebsite.com:80]
[SERVER_ADMIN] [admin@mywebsite.com]
关于上述列出的环境变量,有两点需要说明:
- 一些以
HTTP_
开头的环境变量是扩展变量,但它们由Web服务器添加,而非HTTP请求头的内容所致。
-
PATH
环境变量确实是环境变量,但不是CGI环境变量,它是Perl脚本环境的产物。
2. HTTP请求头
当用户在Web客户端中输入URL并“发送”以获取网页时,Web客户端会使用该URL创建HTTP请求头。这个请求头发送到Web服务器,服务器对其进行解码并返回适当的HTTP回复。
简单的请求头可能只包含一个
GET
行,但实际上请求头可能更加复杂和广泛。例如,Netscape Web客户端请求一个虚拟网站的根索引时生成的请求头如下:
GET / HTTP/1.0
Connection: Keep-Alive
User-Agent: Mozilla/4.04 [en] (WinNT; U)
Host: www.mywebsite.com
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*
Accept-Language: en
Accept-Charset: iso-8859-1,*,utf-8
这个请求头的第一行很熟悉,类似于之前附录中使用的单个
GET
头命令,只是多了一些指定客户端可接受的HTTP版本的信息。可以注意到,这些头信息会对应到
REQUEST_METHOD
和
SERVER_PROTOCOL
CGI环境变量。
User-Agent
头行表明使用的Web客户端是Mozilla(Netscape的别名),三个
Accept
头行则会转换为前面列表中显示的
HTTP_
环境变量。
如果指定的URL是
http://www.mywebsite.com/mycgiprogram.cgi?this=that
并通过另一个页面的链接访问,HTTP请求头会稍有变化:
GET /mycgiprogram.cgi?this=that HTTP/1.0
Referer: http://www.mywebsite.com/refererlink.html
Connection: Keep-Alive
User-Agent: Mozilla/4.04 [en] (WinNT; U)
Host: www.mywebsite.com
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*
Accept-Language: en
Accept-Charset: iso-8859-1,*,utf-8
此时查询字符串隐藏在
GET
行中,Web服务器负责解码此信息并将其放入
QUERY_STRING
环境变量。
Referer
头行的内容会被放入
HTTP_REFERER
环境变量。
当表单以
ACTION
方式提交到CGI程序时,会生成不同的HTTP请求头。以下是HTML源代码:
<html><head><title>a test form</title></head>
<body>
<form method=post action=http://www.mywebsite.com/test.cgi>
<input type=text name=texttest value="first bit ‘o’ stuff"><br>
<textarea name=textareatest rows=4 cols=30> 2nd bit o stuff,
this time in a textarea.</textarea>
<input type=submit name=submit value=submit>
</form></body></html>
生成的HTTP请求头如下:
POST /test.cgi HTTP/1.0
Referer: http://www.mywebsite.com/formtest.html
Connection: Keep-Alive
User-Agent: Mozilla/4.04 [en] (WinNT; U)
Host: www.mywebsite.com
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*
Accept-Language: en
Accept-Charset: iso-8859-1,*,utf-8
Content-type: application/x-www-form-urlencoded
Content-length: 105
mytest=first+bit+%27o%27+stuff&bubba=2nd+bit+o+stuff%2C%0D%0Athis+time+in+a+text area.%0D%0A&submit=submit
可以看到,这里使用的方法是
POST
而非
GET
,并且添加了一些新的头信息。
Content-type
告知Web服务器,头信息附带了
application/x-www-form-urlencoded
MIME类型的内容,这是CGI编程中常见的标准编码方案的正式名称。
Content-length
显示了附带内容的字节长度。最后,提交表单的内容中,空格被转换为
+
,特殊字符被转换为
%-
转义的十六进制代码,这些内容通过
STDIN
文件流提供给CGI程序。
以下是HTTP请求头的简要参考列表:
| 头信息 | 描述 |
| — | — |
| From: | 请求用户的Internet电子邮件格式的名称 |
| Accept: | 以分号分隔的表示方案列表(
Content-Type
元信息值),表示此请求响应中可接受的内容 |
| Accept-Encoding: | 与
Accept
类似,但列出响应中可接受的
Content-Encoding
类型 |
| Accept-Language: | 与
Accept
类似,但列出响应中首选的语言值 |
| User-Agent: | 给出原始使用的Web客户端软件的名称,不受代理影响。虽然是可选的,但建议包含此头信息 |
| Referer: | 一个可选的头字段,用于告知服务器请求的URL是从哪个文档获取的 |
| Authorization: | 包含授权信息,可能是访问某些受保护Web文档所需的 |
| ChargeTo: | 包含用于货币计费的账户信息,为支持电子商务而引入 |
| If-Modified-Since: | 此请求头与
GET
方法一起使用,使请求具有条件性。如果请求的文档自该字段指定的时间以来未更改,Web服务器将发送
Not Modified 304
回复,而不是请求的文档 |
| Pragma: | 为中间和代理服务器提供的Pragma指令 |
3. 正则表达式总结
正则表达式是一种指定模式的方式,用于过滤文本并仅匹配特定的字符串。一旦匹配到字符串,就可以从较大的文本主体中提取该字符串或用另一个字符串替换它。在Perl中,另一种常见的技术是将正则表达式用作
if
语句的条件,这样当特定文本字符串包含与表达式匹配的文本时,语句将评估为
True
。
正则表达式由一系列合法符号和合法运算符组成。以下是正则表达式的元字符、元括号和元序列的详细说明:
3.1 元字符
| 元字符 | 描述 |
|---|---|
| ^ |
匹配字符串的开头,或者如果使用
/m
选项,则匹配行的开头。它是两个模式锚点之一,另一个是
$
|
| . |
匹配除换行符之外的任何单个字符(除非指定了
/s
选项,此时也会匹配换行符)
|
| $ |
匹配字符串的结尾,或者如果使用
/m
选项,则匹配行的结尾。它是两个模式锚点之一,另一个是
^
|
| | |
允许指定两个可以使匹配成功的值。例如,
m/a|b/
表示
$_
变量必须包含
a
或
b
字符才能匹配成功
|
| * |
表示其左侧的项应匹配0次或更多次才能评估为
True
。因此,
.*
可以匹配任意数量的字符
|
| + |
表示其左侧的项应匹配1次或更多次才能评估为
True
|
| ? |
表示其左侧的项应匹配0次或1次才能评估为
True
。当与
+
、
?
或
{n, m}
元字符和括号一起使用时,意味着正则表达式应采用非贪婪模式,匹配尽可能小的字符串
|
3.2 元括号
| 元括号 | 描述 |
|---|---|
| () | 括号可影响模式评估的顺序,并作为一种模式记忆形式 |
| (?…) | 如果左括号后紧跟一个问号,表示正在指定扩展模式组件(Perl 5新增) |
| (?#comment) |
扩展:
comment
可以是任何文本,用于添加注释
|
| (?:regx) |
扩展:
regx
可以是任何正则表达式,但括号不会作为反向引用保存
|
| (?=regx) | 扩展:允许匹配零宽度的正向预查字符(即正则表达式被匹配,但不返回为已匹配) |
| (?!regx) |
扩展:允许匹配零宽度的负向预查字符(即
(?=regx)
的否定形式)
|
| (?options) |
扩展:将指定的选项应用于模式,无需以常规方式指定选项。有效选项包括:
i
(不区分大小写)、
m
(视为多行)、
s
(视为单行)和
x
(允许空格和注释)
|
| {n, m} |
花括号用于指定其左侧的项应匹配的次数。
{n}
表示应精确匹配
n
次,
{n,}
表示至少匹配
n
次,
{n, m}
表示至少匹配
n
次但不超过
m
次
|
| [] |
方括号用于创建字符类。例如,
m/[abc]/
如果
$_
中包含
a
、
b
或
c
中的任何一个字符,则评估为
True
。方括号是
\|
元字符的更易读替代方案
|
3.3 元序列
| 元序列 | 描述 |
|---|---|
| \ |
转义其后的字符,使其忽略通常附带的特殊含义。例如,如果需要在模式中包含美元符号,必须使用
\$
以避免Perl的变量插值。使用
\\
指定模式中的反斜杠字符
|
| \nnn |
任何八进制字节,其中
nnn
表示八进制数,允许通过八进制数指定任何字符
|
| \a | 警报字符,打印时会产生警告铃声 |
| \A |
表示字符串的开头,其含义不受
/m
选项影响
|
| \b |
在字符类中表示退格字符,否则表示单词边界,即单词
(\w)
和非单词
(\W)
字符之间的位置。Perl认为
\W
元序列匹配字符串末尾的虚拟字符
|
| \B | 匹配非单词边界 |
| \cn |
任何控制字符(其中
n
是字符,例如
\cY
表示
Ctrl+Y
)
|
| \d | 匹配单个数字字符 |
| \D | 匹配单个非数字字符 |
| \e | 转义字符 |
| \E |
终止
\L
或
\U
序列
|
| \f | 换页字符 |
| \G |
仅匹配上一次
m//g
停止的位置
|
| \l | 将下一个字符转换为小写 |
| \L |
将后续字符转换为小写,直到遇到
\E
序列
|
| \n | 换行字符 |
| \Q |
逐字引用正则表达式元字符,直到遇到
\E
序列
|
| \r | 回车字符 |
| \s | 匹配单个空白字符 |
| \S | 匹配单个非空白字符 |
| \t | 制表符 |
| \u | 将下一个字符转换为大写 |
| \U |
将后续字符转换为大写,直到遇到
\E
序列
|
| \v | 垂直制表符 |
| \w | 匹配单个单词字符(单词字符包括字母数字和下划线字符) |
| \W | 匹配单个非单词字符 |
| \xnn | 任何十六进制字节 |
| \Z |
表示字符串的结尾,其含义不受
/m
选项影响
|
| \$ | 美元字符 |
| \@ | 与符号 |
| \% | 百分号字符 |
下面通过一个简单的mermaid流程图展示正则表达式匹配的基本流程:
graph TD;
A[开始] --> B[输入文本和正则表达式];
B --> C[进行匹配操作];
C --> D{是否匹配成功};
D -- 是 --> E[输出匹配结果];
D -- 否 --> F[输出未匹配信息];
E --> G[结束];
F --> G;
4. ASCII表
ASCII(美国信息交换标准代码)表定义了字符与数字之间的映射关系。以下是部分ASCII表内容:
| 十进制(Dec) | 十六进制(Hex) | 二进制(Binary) | ASCII字符 |
| — | — | — | — |
| 000 | 00 | 0000 0000 | null |
| 001 | 01 | 0000 0001 | A |
| 002 | 02 | 0000 0010 | B |
|… |… |… |… |
| 255 | FF | 1111 1111 | ˛ |
ASCII表涵盖了从控制字符到可打印字符的广泛范围,在计算机编程和数据处理中起着重要作用。例如,在处理文本文件、网络通信等场景中,经常需要根据ASCII码进行字符的编码和解码。
通过对CGI环境变量、HTTP请求头、正则表达式和ASCII表的详细了解,我们可以更好地进行Web开发和数据处理工作。在实际应用中,合理运用这些知识可以提高程序的效率和稳定性。例如,在编写CGI程序时,准确理解和使用环境变量和请求头信息,能够实现与Web客户端的有效交互;掌握正则表达式可以方便地进行文本的匹配和处理;而熟悉ASCII表则有助于处理字符编码和转换问题。
5. 正则表达式的应用示例
正则表达式在实际编程中有广泛的应用,下面通过几个具体的例子来展示其强大的功能。
5.1 验证邮箱地址
邮箱地址通常有特定的格式,我们可以使用正则表达式来验证一个字符串是否为有效的邮箱地址。以下是一个简单的Perl代码示例:
#!/usr/local/bin/perl
use strict;
use warnings;
my $email = "example@example.com";
if ($email =~ /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/) {
print "$email 是有效的邮箱地址\n";
} else {
print "$email 不是有效的邮箱地址\n";
}
在这个正则表达式中:
-
^
表示字符串的开头。
-
[a-zA-Z0-9._%+-]+
表示匹配一个或多个字母、数字、点、下划线、百分号、加号或减号,这部分用于匹配邮箱地址的用户名部分。
-
@
是邮箱地址中必须包含的符号。
-
[a-zA-Z0-9.-]+
匹配一个或多个字母、数字、点或减号,用于匹配域名部分。
-
\.
表示匹配一个点。
-
[a-zA-Z]{2,}
表示匹配两个或更多的字母,用于匹配顶级域名(如
.com
,
.org
等)。
-
$
表示字符串的结尾。
5.2 提取HTML标签中的内容
在处理HTML文档时,我们可能需要提取特定标签中的内容。以下是一个使用正则表达式提取
<title>
标签内容的Perl代码示例:
#!/usr/local/bin/perl
use strict;
use warnings;
my $html = '<html><head><title>这是标题</title></head><body></body></html>';
if ($html =~ /<title>(.*?)<\/title>/) {
my $title = $1;
print "提取到的标题是: $title\n";
} else {
print "未找到标题标签\n";
}
在这个正则表达式中:
-
<title>
匹配
<title>
标签的开头。
-
(.*?)
是一个捕获组,使用非贪婪模式匹配任意字符,直到遇到
</title>
标签。
-
<\/title>
匹配
</title>
标签的结尾。
5.3 替换文本中的特定内容
正则表达式还可以用于替换文本中的特定内容。以下是一个将文本中的所有数字替换为
X
的Perl代码示例:
#!/usr/local/bin/perl
use strict;
use warnings;
my $text = "abc123def456";
$text =~ s/\d/X/g;
print "替换后的文本是: $text\n";
在这个正则表达式中:
-
\d
匹配任意数字。
-
s///
是Perl中的替换操作符。
-
g
表示全局替换,即替换文本中所有匹配的数字。
下面通过一个mermaid流程图展示正则表达式在文本处理中的应用流程:
graph TD;
A[开始] --> B[输入文本和正则表达式及操作类型];
B --> C{操作类型};
C -- 验证 --> D[进行验证操作];
C -- 提取 --> E[进行提取操作];
C -- 替换 --> F[进行替换操作];
D --> G{验证结果};
G -- 通过 --> H[输出验证通过信息];
G -- 未通过 --> I[输出验证未通过信息];
E --> J[输出提取结果];
F --> K[输出替换后的文本];
H --> L[结束];
I --> L;
J --> L;
K --> L;
6. CGI环境变量和HTTP请求头的实际应用
6.1 根据用户代理生成不同页面
在Web开发中,我们可以根据
HTTP_USER_AGENT
环境变量生成不同的页面,以提供更好的用户体验。以下是一个简单的Perl CGI程序示例:
#!/usr/local/bin/perl
use strict;
use warnings;
print "Content-type: text/html\n\n";
my $user_agent = $ENV{HTTP_USER_AGENT};
if ($user_agent =~ /Mobile/) {
print "<html><body><h1>这是移动设备访问的页面</h1></body></html>";
} else {
print "<html><body><h1>这是桌面设备访问的页面</h1></body></html>";
}
在这个程序中,我们首先获取
HTTP_USER_AGENT
环境变量的值,然后使用正则表达式检查是否包含
Mobile
关键字。如果包含,则认为是移动设备访问,输出适合移动设备的页面;否则,输出适合桌面设备的页面。
6.2 处理表单提交数据
当用户通过表单提交数据时,我们可以使用
REQUEST_METHOD
和
CONTENT_TYPE
环境变量来处理不同类型的请求。以下是一个处理
POST
请求的Perl CGI程序示例:
#!/usr/local/bin/perl
use strict;
use warnings;
if ($ENV{REQUEST_METHOD} eq 'POST') {
my $content_length = $ENV{CONTENT_LENGTH};
my $input;
read(STDIN, $input, $content_length);
my %form_data;
my @pairs = split(/&/, $input);
foreach my $pair (@pairs) {
my ($key, $value) = split(/=/, $pair);
$key =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
$value =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
$form_data{$key} = $value;
}
print "Content-type: text/html\n\n";
print "<html><body>";
print "<h1>表单提交的数据如下:</h1>";
foreach my $key (keys %form_data) {
print "<p>$key: $form_data{$key}</p>";
}
print "</body></html>";
} else {
print "Content-type: text/html\n\n";
print "<html><body><h1>只支持POST请求</h1></body></html>";
}
在这个程序中:
1. 首先检查
REQUEST_METHOD
是否为
POST
。
2. 如果是
POST
请求,获取
CONTENT_LENGTH
环境变量的值,用于读取
STDIN
中的数据。
3. 将读取的数据按
&
分割成键值对,再按
=
分割每个键值对。
4. 对键和值进行
%-
转义的十六进制代码解码。
5. 最后将解码后的数据存储在哈希表中,并输出到页面上。
6.3 操作步骤总结
以下是处理表单提交数据的操作步骤列表:
1. 检查
REQUEST_METHOD
是否为
POST
。
2. 获取
CONTENT_LENGTH
环境变量的值。
3. 从
STDIN
读取指定长度的数据。
4. 将读取的数据按
&
分割成键值对。
5. 对每个键值对按
=
分割。
6. 对键和值进行
%-
转义的十六进制代码解码。
7. 将解码后的数据存储在哈希表中。
8. 输出表单提交的数据到页面上。
7. 总结与展望
通过对CGI环境变量、HTTP请求头、正则表达式和ASCII表的深入学习,我们了解了它们在Web开发和数据处理中的重要作用。CGI环境变量和HTTP请求头为Web服务器和CGI程序之间的通信提供了丰富的信息,正则表达式则为文本处理提供了强大的工具,而ASCII表则是字符编码和转换的基础。
在未来的Web开发中,这些知识将继续发挥重要作用。随着技术的不断发展,我们可以预见,正则表达式的功能将更加完善,能够处理更复杂的文本匹配和替换任务;CGI环境变量和HTTP请求头的使用也将更加灵活,以适应不断变化的Web应用需求。同时,随着Unicode等更广泛的字符编码标准的普及,ASCII表的应用可能会逐渐减少,但字符编码和转换的基本原理仍然是我们需要掌握的重要知识。
希望本文能够帮助读者更好地理解和应用这些技术,在Web开发和数据处理中取得更好的效果。
超级会员免费看
36

被折叠的 条评论
为什么被折叠?



