用C语言写CGI程式-入门篇

原文链接:http://www.cs.tut.fi/~jkorpela/forms/cgic.html

    这是一篇用C语言写CGI程式的入门文章。假定读者对C语言有基本的认识,熟悉HTML并且会在WEB服务器上安装CGI脚本。

为什么要用CGI程式?

大家都应该知道如何用HTML写表单,那么写好表单后,为了可靠地使用、处理表单数据,你仍然需要服务端脚本。通常服务端脚本以简单、类似的方式处理表单提交,典型地如向某个邮件地址发送文本数据。

但是,如果你要处理更复杂的问题,如采集数据并写入文件或数据库、或者接收信息然后转发又或者对提交的数据做四则运算,那么你不得不自己写一个的服务端脚本。

简单地说,CGI是HTML表单和服务端脚本的接口。

但CGI不是唯一的选择。建议看下Lars Marius GarsholHow 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程序。(或者理论上来说,在一个相同架构的系统上也可以)

通常来说,你需要执行以下步骤:

  1. 在正常的交互环境下,编译并且测试C程序
  2. 为了适应CGI环境,对C程序做相应的修改。程序应该要读取表单提交的数据。使用默认的GTE方法,从环境变量输入“QUERY\_STRING”中读入输入。(当然程序也有可能从本机服器上的文件读取输入)程序应该在标准输出流(stdout)中产生输出,并且使用恰当的HTTP头。通常来说是HTML格式。
  3. 再次编译测试。在这个测试阶段,你可以设置环境变量QUERY\_STRING,把表单发送过来的测试数据赋给它。例如,如果你打算在表单中使用foo字段域,那么你可以这样设置环境变量=setenv QUERY_STRING "foo=42" =(when using the tcsh shell)

或者=QUERY_STRING="foo=42" =(when using the bash shell).

  1. 检查你编译的版本能够在服务器上运行。这可能会需要再次编译。你可能需要登陆服务器(使用Telnet, SSH或其他终端模拟工具)
  2. 新建一个简单的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;
}

以下略。。。