用C语言写CGI程式-入门篇
原文链接:http://www.cs.tut.fi/~jkorpela/forms/cgic.html
这是一篇用C语言写CGI程式的入门文章。假定读者对C语言有基本的认识,熟悉HTML并且会在WEB服务器上安装CGI脚本。
为什么要用CGI程式?
大家都应该知道如何用HTML写表单,那么写好表单后,为了可靠地使用、处理表单数据,你仍然需要服务端脚本。通常服务端脚本以简单、类似的方式处理表单提交,典型地如向某个邮件地址发送文本数据。
但是,如果你要处理更复杂的问题,如采集数据并写入文件或数据库、或者接收信息然后转发又或者对提交的数据做四则运算,那么你不得不自己写一个的服务端脚本。
简单地说,CGI是HTML表单和服务端脚本的接口。
但CGI不是唯一的选择。建议看下Lars Marius Garshol的 How the web works: HTTP and CGI explained 文章,可以使您了解CGI的概念和除CGI外的其他选择。
如果有人建议用javascript写CGI程式,让他看看这篇文章: JavaScript and HTML: possibilities and caveats. 简单说,如果不使用服务端服本备份的话,JavaScript根本不可靠。
先来测试下环境是否可能?
呵呵,我写了一个hello, world的cgi,把它放到cgi-bin目录下即可,猛击: http://roygu.com/cgi-bin/hello.cgi
一个简单的示例
假如有一个简单的表单(如下):
Multiplicand 1: Multiplicand 2:
效果如下:
Multiplicand 1:
Multiplicand 2:
试一下?呵呵,输入4和9, 结果如下:
Multiplication results
The product of 4 and 9 is 36.
对上面的示例进行分析
我们现在来分析下上面例子是如何工作的。
假设你在一个输入框中输入4,在另一个输入框中输入9,然后点击提交按钮。你的浏览器将会利用HTTP协议向服主机roygu.com发送一次请求。浏览器通过表单的Action属性来获得该主机名,而主机名只是action指定的URL的一部分。(很多时候,action属性使用相对URL指向同一服务器上的某个文件,当然像上面那个示例一样,这不是必须的。)
当发送请求时,浏览器会提供额外的信息,在这种情况下,它会指定一个相对的URL:如下
/cgi-bin/mult.cgi?m=4&n=9
这个是根据form表单的action属性主机名后面的那部分构建的,在后面添加问号和表单数据的编码形式。
主机接收到请求后,并会根据自己的规则来处理它。一般来说,主机的配置中定义了相对URLS和本地目录/文件的映射关系,并且定义了执行cgi程式的目录。那么URL中的cgi-bin部分就是由主机指定的可执行cgi程式的目录。也就是说,主机为仅令是收集数据然后返回HTML文件或其他格式文件,而是执行URL中指定的脚本或程序(在这里是mult.cgi),并且给它传递相关数据(在这里,数据是m=4&n=9)。
在实际生产环境中,上面的过程还是要取决于服务器。在本文中,主机执行了roygu站点下的cgi-bin目录下的mult.cgi程式。在你的主机上可能就不一样了,这取决于主机的配置。
那么,什么是CGI编程?
*CGI*的全称是*Common Gateway Interface*,这个术看上去很神秘,其实它只是一个规范,规定如何调用程序和参数如何传递的细节。
程序调用意思是不同的情况有不同的调用方法。例如,如果是Pel脚本,那么主机便会启动Perl解释器并且让以解释方式执行当前脚本。如果是那种已经编译好了的可执行程序(比如C语言),那么主机会启动一个新进程来执行它。
一般来说,“脚本”代表解释执行的代码,而CGI脚本即可以是解释型代码也可以是可执行程序。具体可以查看这里answer to question Is it a script or a program?
用C语言写CGI程式
要把一个C程序转变成一个CGI脚本,需要把它转换成二进制可执行的程序。这通常是一个问题,因为大部份人在windows平台上工作,而服务器一般使用的是UNIX或LINUX。你开发程序的系统和你要运行CGI脚本的服务器系统可能有完全不一样的架构,所以同一个可执行程序只能在它们中的某个上运行。
这可能是个无法解决的问题。如果你不能登陆服务器或者你找不到一个兼容的系统(或跨平台编译器),那么你很不走运。很多服务器允许你登陆并且交互模式下使用主机,也就是通常说的shell用户,并且主机包含有C编译器。
你必须在服务器上编辑并链接你的C程序。(或者理论上来说,在一个相同架构的系统上也可以)
通常来说,你需要执行以下步骤:
- 在正常的交互环境下,编译并且测试C程序
- 为了适应CGI环境,对C程序做相应的修改。程序应该要读取表单提交的数据。使用默认的GTE方法,从环境变量输入“QUERY\_STRING”中读入输入。(当然程序也有可能从本机服器上的文件读取输入)程序应该在标准输出流(stdout)中产生输出,并且使用恰当的HTTP头。通常来说是HTML格式。
- 再次编译测试。在这个测试阶段,你可以设置环境变量QUERY\_STRING,把表单发送过来的测试数据赋给它。例如,如果你打算在表单中使用foo字段域,那么你可以这样设置环境变量=setenv QUERY_STRING "foo=42" =(when using the tcsh shell)
或者=QUERY_STRING="foo=42" =(when using the bash shell).
- 检查你编译的版本能够在服务器上运行。这可能会需要再次编译。你可能需要登陆服务器(使用Telnet, SSH或其他终端模拟工具)
- 新建一个简单的HTML页面,在此矾面中创建一个FORM表单
现在呢,你把可执行文件放到某个合适的目录下,并且根据服务器规定给文件命名。即使是服务器端的编译命令和你正在使用的工作站的不一样。例如:如果服务器运行类Unix系统,并且装的是GNU C编译器,那么使用编译命令=gcc -o mult.cgi mult.c=,接着把= (mv) mult.cgi=移动某个目录下,比如=cgi-bin=,不过编译命令也可能是CC。强烈建议你检查服务器的指令。
文件后缀.cgi没有实际的意义。但是此命名方式由服务器规定。一般来说会是.cgi和.exe。
如何处理一个简单的表单
对于使用=METHOD="GET"=的表单(就像上面介绍的那个表单一样,GET也是表单默认的提交方式)来说,CGI规定数据通过环境变量=QUERY_STRING=传递给程序。
如何访问环境变量和脚本或程序语言有关。在C语言中,你可以使用库函数=getenv=(在标准库stdlib中定义)以字符串形式获取环境变量的值。接着你可以使用变量技术从字符串中提取数据,把数据转为数字类型等等。。。
脚本或程序输出是一种特殊的方式处理的,就好比C语言的=stdin=实际上,它是定向输出到浏览器。因此,通过写一个C程序,它的标准输出是一个HTML文件,这个文件将会出现在用户的屏幕上,作为对表单提交的回应。
C代码如下:
#include <stdio.h> #include <stdlib.h> int main(void) { char *data; long m,n; printf("%s%c%c\n", "Content-Type:text/html;charset=iso-8859-1",13,10); printf("<TITLE>Multiplication results</TITLE>\n"); printf("<H3>Multiplication results</H3>\n"); data = getenv("QUERY_STRING"); if(data == NULL) printf("<P>Error! Error in passing data from form to script."); else if(sscanf(data,"m=%ld&n=%ld",&m,&n)!=2) printf("<P>Error! Invalid data. Data must be numeric."); else printf("<P>The product of %ld and %ld is %ld.",m,n,m*n); return 0; }
以下略。。。