为什么买的虚拟主机的 "public_html" 目录下总有那么一个空 "cgi-bin" 目录?再者为什么我将 cgi 文件不放刚才那个"cgi-bin" 目录下也同样也能运行?什么时候需要用到 AddType 指令?
一、基础知识
1.1、什么是 CGI?
见前文《Linux 从源码编译安装 PHP 5.3.4》,简单说 CGI 是一种口,所有对 CGI 文件的访问请求,Web 服务器必须先作执行处理而不能直接把内容返回浏览器。
1.2、什么是 Apache PMA
Apache PMA,即多路处理模块,详细介绍见 ,apache2.2 官方文档
apache2.2 默认使用 prefork ,如果需要选择 worker ,那么必须在apache2.2 编译时使用“--with-mpm=” 选项静态编译进核心。可通过"httpd -l"查询当前的PMA模式。
prefork 采用进程的方式,Worker 采用进程与线程混合方式,海量的请求时,prefork 较快但耗资源,worker 相反。
1.3、mod_cgi 和 mod_cgid 区别
Apache PMA 为 prefork 时使用mod_cgi模块,PMA 为worker 时使用mod_cgid模块。详细介绍见文档 Apache Module mod_cgi、Apache Module mod_cgid。即在用户层面,这两个模块本质上是相同的。
二、执行 CGI 的方法
2.1、指定ScriptAlias目录为CGI文件目录
在 ScriptAlias 目录的文件均被认为是 CGI i脚本,另外要设置该目录属性,但无需添加 ExecCGI 选项。
指定目录别名及路径,注意是“ScriptAlias”而不是“Alias”
1 |
ScriptAlias /cgi-bin/ "/usr/local/apache/cgi-bin/" |
设置该目录属性,绝对路径,千万不要漏了 "Allow from all" 切记!
1 2 3 4 5 6 |
<Directory "/usr/local/apache/cgi-bin"> AllowOverride None Options None Order allow,deny Allow from all </Directory> |
2.2、指定特定文件后缀为CGI文件
在 ScriptAlias 目录的文件均被认为是 CGI i脚本,那么目录之外是否可以?可以!但要指定后缀、设置目录属性,且启用ExecCGI选项。
指定后缀有两种方法,一是定义MIME类型为application/x-httpd-cgi,二是使用 AddHandler 或 SetHandler 指令激活内置的 cgi-script 处理器
1 2 |
AddType application/x-httpd-cgi .cgi #方法一 AddHandler cgi-script .cgi #方法二 |
设置CGI的目录属性,必须在Options指令中启用ExecCGI选项
1 2 3 4 5 6 |
<Directory "/usr/local/apache/htdocs/cgi-bin"> Options ExecCGI AllowOverride None Order allow,deny Allow from all </Directory> |
简介
相关模块 相关指令
mod_alias
mod_cgi
AddHandler
Options
ScriptAlias
配置Apache以允许CGI
要让CGI程序能正常运作,必须配置Apache以允许CGI的执行,其方法有多种。
ScriptAlias指令使Apache允许执行一个特定目录中的CGI程序。当客户端请求此特定目录中的资源时,Apache假定其中所有的文件都是CGI程序并试图运行它。
由于安全原因,CGI程序通常被限制在ScriptAlias指定的目录中,这样,管理员就可 以严格控制谁可以使用CGI程序。但是,如果采取了恰当的安全措施,则没有理由不允许其他目录中的CGI程序运行。比如,你可能希望用户在UserDir 指定的宿主目录中存放页面,而他们有自己的CGI程序,但无权访问cgi-bin目录,这样,就产生了运行其他目录中CGI程序的需求。
可以在主配置文件中,使用Options指令显式地允许特定目录中CGI的执行:
.htaccess指南示范了怎样在没有权限修改httpd.conf文件的情况下激活CGI程序。
为了允许用户目录中所有以".cgi"结尾的文件作为CGI程序执行,你可以使用以下配置:
AddHandler cgi-script .cgi
SetHandler cgi-script
编写CGI程序
编写CGI程序和"常规"程序之间有两个主要的不同。
这个CGI程序的例子在浏览器中打印一行文字。把下列存为first.pl文件,并放在你的cgi-bin目录中。
print "Content-type: text/html\n\n";
print "Hello, World.";
程序还是不能运行!
使用浏览器从网络访问CGI程序,可能会发生四种情况:
太好了!这说明一切正常。如果输出正常但是浏览器处理出错,请确认你在CGI程序中使用了正确的 Content-Type 。
CGI程序的源代码或者一个"POST Method Not Allowed"消息
这说明Apache没有被正确配置以执行CGI程序,重新阅读配置Apache看看遗漏了什么。
一个以"Forbidden"开头的消息
这说明有权限问题。参考Apache错误日志和下面的文件权限。
一个"Internal Server Error"消息
查阅Apache错误日志,可以找到CGI程序产生的出错消息"Premature end of script headers"。对此,需要检查下列各项,以找出不能产生正确HTTP头的原因。
文件的权限
记住,服务器不是以你的用户身份运行的,在服务器启动后,拥有的是一个非特权用户的权限(通常是nobody或www)而需要更大的权限以允许文件的执行。通常,给予nobody足够的权限以执行文件的方法是,对文件赋予任何人皆可执行的权限:
当你在命令行执行一个程序,某些信息会自动传给shell而无须你操心,比如PATH ,告诉shell你所引用的文件可以在哪儿找到。
多数CGI程序失败的原因在于程序本身有问题,尤其是在已经消除上述两种错误而CGI挂起的情况下。在用浏览器测试以前,先在命令行中执行你的程序,能够发现大多数的问题。比如:
./first.pl
错误日志是你的朋友。任何错误都会在错误日志中有所记载,所以你应该首先查看它。如果你的网站空间提供者不允许访问错误日志,那么你应该考虑换一个空间提供者。学会阅读错误日志,可以快速找出问题并快速解决。
suexec允许CGI程序根据其所在虚拟主机或用户宿主目录的不同而以不同的用户权限运行。suexec有极其严格的权限校验,任何校验失败都会使CGI程序遭遇 Premature end of script headers 错误。
幕后是怎样操作的?
当你的CGI编程逐渐深入,理解幕后的操作(尤其是浏览器和服务器之间是如何通讯的)就变得很有用了。因为虽然成功地写了一个程序打印"Hello, World",但并没有实际的用处。
环境变量是使用计算机时到处都会用到的变量,比如路径(对实际文件的一个搜索路径以补全你的输入)、你的用户名以及你的终端类型等等。在命令行输入 env ,可以得到当天标准的环境变量列表。
print "Content-type: text/html\n\n";
foreach $key (keys %ENV) {
服务器和客户端之间的其他通讯都通过标准输入设备(STDIN)和标准输出设备(STDOUT)完成。通常,STDIN是指键盘或者一个程序所作用的一个文件,STDOUT指控制台或显示器。
CGI模块/库
编写CGI程序时,你应该考虑使用代码库或模块来完成大多数琐碎的工作,以减少错误并更快地开发。
更多信息
网上有大量的CGI资源。可以在Usenet组comp.infosystems.www.authoring.cgi和别人讨论CGI相关问题。HTML Writers Guild 的邮件列表是一个优秀的问题解答资源。更多资源在http://www.hwg.org/lists/hwg-servers/
注意,不要把CGI相关问题提交到Apache bug数据库,除非你坚信发现的是Apache源代码中的问题。