登录 用户中心() [退出] 后台管理 注册
   
您的位置: 首页 >> 程序员学前班[不再更新,只读] >> 主题: 用C语言进行CGI程序设计[zt]     [回主站]     [分站链接]
标题
用C语言进行CGI程序设计[zt]
我是马甲
浏览(0) + 2007-09-12 14:50:07 发表 编辑

关键字:

用C语言进行CGI程序设计
作者: li2002 出处:ChinaUnix论坛  ( 5 ) 砖 ( 12 ) 好 评论 ( 0 ) 条  进入论坛
更新时间:2005-09-22 14:51
关 键 词:语言 进 C I
阅读提示:本文详细介绍如何用C语言实现CGI程序设计

一、CGI概述



CGI(公用网关接口)规定了Web服务器调用其他可执行程序(CGI程 序)的接口协议标准。Web服务器通过调用CGI程序实现和Web浏览器的交互,也就是CGI程序接受Web浏览器发送给Web服务器的信息,进行处理,将响应结果再回送给Web服务器及Web浏览器。CGI程序一般完成Web网页中表单(Form)数据的处理、数据库查询和实现与传统应用系统的集成等工作。CGI程序可以用任何程序设计语言编写,如Shell脚本语言、Perl、Fortran、Pascal、C语言等。但是用C语言编写的CGI程序具有执行速度快、安全性高(因为C语言程序是编译执行且不可被修改)等特点。

CGI接口标准包括标准输入、环境变量、标准输出三部分。

1.标准输入

CGI程序像其他可执行程序一样,可通过标准输入(stdin)从Web服务器得到输入信息,如Form中的数据,这就是所谓的向CGI程序传递数据的POST方法。这意味着在操作系统命令行状态可执行CGI程序,对CGI程序进行调试。POST方法是常用的方法,本文将以此方法为例,分析CGI程序设计的方法、过程和技巧。

2.环境变量

操作系统提供了许多环境变量,它们定义了程序的执行环境,应用程序可以存取它们。Web服务器和CGI接口又另外设置了自己的一些环境变量,用来向CGI程序传递一些重要的参数。CGI的GET方法还通过 环境变量QUERY-STRING向CGI程序传递Form中的数据。

3.标准输出

CGI程序通过标准输出(stdout)将输出信息传送给Web服务器。传送给Web服务器的信息可以用各种格式,通常是以纯文本或者HTML文本的形式,这样我们就可以在命令行状态调试CGI程序,并且得到它们的输出。

下面是一个简单的CGI程序,它将HTML中Form的信息直接输出到We b浏览器。
代码:



#include

#include

main()

{

 int,i,n;

printf (″Contenttype:text/plain\n\n″);

n=0;

if(getenv(″CONTENT-LENGTH″))

n=atoi(getenv(CONTENT-LENGTH″));

for (i=0;i
putchar(getchar());

putchar (′\n′);

fflush(stdout);

}




下面对此程序作一下简要的分析。

 
代码:

 prinft (″Contenttype:text/plain\n\n″);




此行通过标准输出将字符串″Contenttype:text/plain\n\n″传送给Web服务器。它是一个MIME头信息,它告诉Web服务器随后的输出是以纯ASCII文本的形式。请注意在这个头信息中有两个新行符,这是因为Web服务器需要在实际的文本信息开始之前先看见一个空行。


代码:

if (getenv(″CONTENT-LENGTH″))

n=atoi (getenv(″CONTENT-LENGTH″));




此行首先检查环境变量CONTENT-LENGTH是否存在。Web服务器在调用使用POST方法的CGI程序时设置此环境变量,它的文本值表示Web服务器传送给CGI程序的输入中的字符数目,因此我们使用函数atoi() 将此环境变量的值转换成整数,并赋给变量n。请注意Web服务器并不以文件结束符来终止它的输出,所以如果不检查环境变量CONTENT-LENGTH,CGI程序就无法知道什么时候输入结束了。
代码:

for (i=0;i
putchar(getchar());




此行从0循环到(CONTENT-LENGTH-1)次将标准输入中读到的每一个字符直接拷贝到标准输出,也就是将所有的输入以ASCII的形式回送给Web服务器。

通过此例,我们可将CGI程序的一般工作过程总结为如下几点。

1.通过检查环境变量CONTENT-LENGTH,确定有多少输入;

2.循环使用getchar()或者其他文件读函数得到所有的输入;

3.以相应的方法处理输入;

4.通过″Contenttype:″头信息,将输出信息的格式告诉Web服务器;

5.通过使用printf()或者putchar()或者其他的文件写函数,将输出传送给Web服务器。

总之,CGI程序的主要任务就是从Web服务器得到输入信息,进行处理,然后将输出结果再送回给Web服务器。

二、环境变量

环境变量是文本串(名字/值对),可以被OS Shell或其他程序设置 ,也可以被其他程序访问。它们是Web服务器传递数据给CGI程序的简单手段,之所以称为环境变量是因为它们是全局变量,任何程序都可以存取它们。

下面是CGI程序设计中常常要用到的一些环境变量。

HTTP-REFERER:调用该CGI程序的网页的URL。

REMOTE-HOST:调用该CGI程序的Web浏览器的机器名和域名。

REQUEST-METHOD:指的是当Web服务器传递数据给CGI程序时所采用的方法,分为GET和POST两种方法。GET方法仅通过环境变量(如QUERY-STRING)传递数据给CGI程序,而POST方法通过环境变量和标准输入传递数据给CGI程序,因此POST方法可较方便地传递较多的数据给CGI程序。

SCRIPT-NAME:该CGI程序的名称。

QUERY-STRING:当使用POST方法时,Form中的数据最后放在QUERY-STRING中,传递给CGI程序。

CONTENT-TYPE:传递给CGI程序数据的MIME类型,通常为″applica tion/x-www-form-url encodede″,它是从HTML Form中以POST方法传递数据给CGI程序的数据编码类型,称为URL编码类型。

CONTENT-LENGTH:传递给CGI程序的数据字符数(字节数)。

在C语言程序中,要访向环境变量,可使用getenv()库函数。例如:
代码:

if (getenv (″CONTENT-LENGTH″))

 n=atoi(getenv (″CONTENT-LENGTH″));


请注意程序中最好调用两次getenv():第一次检查是否存在该环境变量,第二次再使用该环境变量。这是因为函数getenv()在给定的环境变量名不存在时,返回一个NULL(空)指针,如果你不首先检查而直接引用它,当该环境变量不存在时会引起CGI程序崩溃。

三、From输入的分析和解码

1.分析名字/值对

当用户提交一个HTML Form时,Web浏览器首先对Form中的数据以名字/值对的形式进行编码,并发送给Web服务器,然后由Web服务器传递给CGI程序。其格式如下:

name1=value1&name2=value2&name3=value3&name4=value4&...

其中名字是Form中定义的INPUT、SELECT或TEXTAREA等标置(Tag)名字,值是用户输入或选择的标置值。这种格式即为URL编码,程序中需要对其进行分析和解码。要分析这种数据流,CGI程序必须首先将数据流分解成一组组的名字/值对。这可以通过在输入流中查找下面的两个字符来完成。

每当找到字符=,标志着一个Form变量名字的结束;每当找到字符& ,标志着一个Form变量值的结束。请注意输入数据的最后一个变量的值不以&结束。一旦名字/值对分解后,还必须将输入中的一些特殊字符转换成相应的ASCII字符。这些特殊字符是:

+:将+转换成空格符;

%xx:用其十六进制ASCII码值表示的特殊字符。根据值xx将其转换成相应的ASCII字符。

对Form变量名和变量值都要进行这种转换。下面是一个对Form数据进行分析并将结果回送给Web服务器的CGI程序。
代码:

#include

#include

#include

int htoi(char *);

main()

{

 int i,n;

char c;

printf (″Contenttype: text/plain\n\n″);

n=0;

if (getenv(″CONTENT-LENGTH″))

 n=atoi(getenv(″CONTENT-LENGTH″));

for (i=0; i
 int is-eq=0;

c=getchar();

switch (c){

 case ′&′:

c=′\n′;

break;

 case ′+′:

c=′ ′;

break;

 case ′%′:{

char s[3];

s[0]=getchar();

s[1]=getchar();

s[2]=0;

c=htoi(s);

i+=2;

 }

 break;

case ′=′:

 c=′:′;

 is-eq=1;

 break;

};

putchar(c);

if (is-eq) putchar(′ ′);

}

putchar (′\n′);

fflush(stdout);

}

/* convert hex string to int */

int htoi(char *s)

{

 char *digits=″0123456789ABCDEF″;

if (islower (s[0])) s[0]=toupper(s[0]);

if (islower (s[1])) s[1]=toupper(s[1]);

return 16 * (strchr(digits, s[0]) -strchr (digits,′0′)

)

+(strchr(digits,s[1])-strchr(digits,′0′));

}


上面的程序首先输出一个MIME头信息给Web服务器,检查输入中的字符数,并循环检查每一个字符。当发现字符为&时,意味着一个名字/值对的结束,程序输出一个空行;当发现字符为+时,将它转换成空格; 当发现字符为%时,意味着一个两字符的十六进制值的开始,调用htoi()函数将随后的两个字符转换为相应的ASCII字符;当发现字符为=时,意味着一个名字/值对的名字部分的结束,并将它转换成字符:。最后将转换后的字符输出给Web服务器。



四、产生HTML输出

CGI程序产生的输出由两部分组成:MIME头信息和实际的信息。两部分之间以一个空行分开。我们已经看到怎样使用MIME头信息″Cont enttype:text/plain\n\n″和printf()、put char()等函数调用来输 出纯ASCII文本给Web服务器。实际上,我们也可以使用MIME头信息″C ontenttype:text/html\n\n″来输出HTML源代码给Web服务器。请注意任何MIME头信息后必须有一个空行。一旦发送这个MIME头信息给We b服务器后,Web浏览器将认为随后的文本输出为HTML源代码,在HTML源代码中可以使用任何HTML结构,如超链、图像、Form,及对其他CGI程 序的调用。也就是说,我们可以在CGI程序中动态产生HTML源代码输出 ,下面是一个简单的例子。
代码:

#include

#include

main()

{

 printf(″Contenttype:text/html\n\n″);

printf(″\n″);

printf(″An HTML Page From a CGI\n″);

printf(″
\n″);

printf(″

This is an HTML page generated from with i n a CGI program.. .

\n″);

printf(″

\n″);

printf(″ Go back to out put.html page <

/b>
\n″);

printf(″\n″);

printf(″\n″);

fflush(stdout);

}




上面的CGI程序简单地用printf()函数来产生HTML源代码。请注意在输出的字符串中如果有双引号,在其前面必须有一个后斜字符\, 这是因为整个HTML代码串已经在双引号内,所以HTML代码串中的双引号符必须用一个后斜字符\来转义。

五、结束语



本文详细分析了用C语言进行CGI程序设计的方法、过程和技巧。C语言的CGI程序虽然执行速度快、可靠性高,但是相对于Perl语言来说,C语言缺乏强有力的字符串处理能力,因此在实际应用中,应根据需 要和个人爱好来选择合适的CGI程序设计语言。

我是马甲
2007-9-12 15:11:10 发表 编辑

教你利用CGI方式实现Web查询

摘要:本文分析讨论了将WEB与后以数据源相连的方法之一——公共网关界面CGI的概念与特点,并以成绩查询系统作为实例详细分析了用C语言进行CGI程序设计的方法与过程。

  一CGI简述�

  公共网关界面(CGI)是一种编程标准,它规定了Web服务器调用其它可执行程序(CGI程序)的接口协议标准。CGI程序通过Web服务器与运行Web服务器调用其它可执行程序交互,它接受Web浏览器发送给Web服务器的信息,并进行处理,然后将结果再送回给Web服务器及Web浏览器。CGI程序可以用任何程序设计语言编写,如Shell、perl、C、Java等,用C语言编写的CGI程序具有速度快、安全性高等特点。CGI程序通常用于加入查询机制、搜索机制、交互式应用及其它一些应用。�

  CGI接口标准包括输入、环境变量、标准输出三部分,CGI程序可以通过标准输入(stdin)从Web服务器得到输入信息,例如从FORM中得到数据,这就是常用的POST方法。由于不同的操作系统采用了不同的信息交换机制,其参数传递的处理过程也有差别,在Unix与DOS中,环境信息反映着本级程序运行时的某些系统状况,可用于父程序与子程序间的信息传递,CGI正是通过设量环境变量在服务器与客户机间传递数据的,各操作系统都提供了许多环境变量,它们定义了程序的执行环境,应用程序可以存取它们。Web服务器和CGI接口也设置了一些环境变量用以传递一些重要的参数。CGI程序通过标准输出(stdout)将输出信息传送给Web服务器,传送给服务器的信息可以是HTML文本也可以是纯文本。本文将利用C语言编写一个CGI应用程序——学生成绩查询系统,并分析了CGI程序设计的方法、过程、技巧。

  二、成绩查询系统介绍�

  一个在WWW环境下的学生成绩公布栏必将成为日后各类成绩发布的主要手段,每位学生交将有自己的密码,所以不必担心成绩上网之后的保密性。任何学生以任何形式上网进入本站点的成绩查询系统之后,只要输入自己的系列、班别、学号及密码,便可以利用这个学生绩查询系统查询自己的成绩,该设计思路与系统不仅适合各类高校内部的成绩发布,也适合于全国高考、统考等大规模考试的成绩发布。本文介绍的只是一个功能单一的查询系统,若需完善还需加入成绩维护部分,由成绩管理者进行内容维护,包括成绩输入、修改、删除等功能。  

  三、HTML FORM格式部分

  3.1 FORM输放的分解

  在UNIX系统上,CGI信息是利用STDIN/STDOUT方式传输的,所以若要编写一个C语言的CGI程序,就必须要了解如何解剖与截取STDIN的CGI信息。当用户提交一个HTMLFORM时,WEB浏览器首先对FORM中的数据以名字/值对的形式进行编码,并发送给WEB服务器,然后再由WEB服务器传递给CGI程序,其格式如下:

  NAME1=VALUEL&NAME2=VALUE2&NAME3····

  名字是FORM中定义的INPUT,SELECT等标置名字,值是用户输入或选择的标值,在程序中将对其进行分析与解码,将其分解成一组组的名字/值对,这个过程是通过在输入流中查找字符“=”与“&”来完成的,每当找到字符“=”,标志着一个FORM变量名字的结束,当找到字符“&”,标志着一个FORM变量值的结束。当名字/值对分解完之后,还须将输入中的一些特殊字符转换成相应的ASCII字符,如需将“+”转换成空格符,将一些特殊字符转换成ASCII字符,对以上分所分析的分解与转换过程,在下面的程序中有详细注明。

  3.2HTML FORM文件

  成绩查询系统的HTML文件P.htrnl

  �

  
学生成绩查询系统


  

  
系列:�

  计算机系�

  英语系�

  无线电系�

  



  学号:



  密码:



  �

  
  len=atoi(getenv("CONTENT_LENGITH"));�

  for(i=0;len && (!feof(stdin));i++){

  m=i�

  inputs[i].val=readdstdin(stdin,&,&len);/*读STDiN信息*/�

  AddToSpace(inputs[i].val);�

  Convert(inputs[i].val);�

  inputs[i].name=ReadData(inputs[i].val,=);�

  }�

  strcpy(filename1,"/score/setup/");�

  stucpy(filename2,"/xcore/data/");�

  if(strcmp(inputs[o].val,"计算机系/)==0�

  strcat(filename1,"compusb.dat");�

  strcat(filename2,"compscore.dat");�

  }�

  if(strcmp(inputs[o].val,"英语系")==0�

  strcat(filenamel,"engsub.dat");�

  strcat(filename2,"engscore.dat");�

  }�

  if(strcmp(inputs[o].val,"无线电系")==0�

  }�

  strcat(filename1,"elecsub.dat");�

  strcat(filename2,"elecscore.dat");�

  }�

  fp=fopen(filename1,"r");/*打开文件*/�

  kind=0;�

  while(fscanf(fp,"%s",subject[kind]!=EOF�

  kind=kind+1;�

  fclose(fp);�

  

  fp1=fopen(filename2,"r");/*打开文件*/�

  allsum=0;�

  for(i=0;i<100;i++)�

  {�

  numbde=i;�

  if(fscanf(fp1,"%s%s",id[i],�

  password[i]!=EOF){�

  sum[i]=0;�

  for{j=0;j
  fscanf(fp1,"%d",&score[i][j]);�

  sum[i]+=score[i][j];�

  }�

  avg[i]=sum[i]/kind;�

  allsum+=sum[i];�

  }�

  else�

  break;�

  }�

  fclose(fp1);�

  find=0;�

  if(strcmp(inputs[2].val,id[i])==0&&�

  strcmp(inputs[3].val,password[i]==0){�

  index=i;�

  find=i;�

  }�

  }�

  if(find==0)�

  {�

  printf{"输入有误,请再输一次!
\n");�

  }�

  else�

  {�

  rank=1�

  for(i=o;i
  if(sum[index]
  rank=rank+1;�

  slltotalavg=allsum/number;�

  printf("
学生成绩查询系统
");�

  pritf("\n
查询学生学号:%s

",�

  inputs[2].val);�

  printf("\n
成绩如下:
");�

  

  for(i=0;i
  printf{"%s\t",subject[kind]);�

  printf("总分\n");�

  for(i=0;i
  printf("%d\t",score[index][i]);�

  printf["%d\n",sum[index]);

  }

  }

  五、结束语

  本文以学竽成绩查询系统作为实例,详细分析了用C语言进行CGI程序设计的方法与过程,随着INTERET/INTRANET应用的深入,将WEB与多台数据库联接的需求也日益迫切,CGI可以使得WEB能够能最低程序的复杂性与其后台信息集成,成为一种支持多种类型的通用环境,但是由于在CGI方式中每执行一次交互都需启动一个外部程序,因此其在实时应用方面受到了限制,因而,WEB SENER API及JOCBC等应用方式也正在成熟.  

我是马甲
2007-9-12 15:11:48 发表 编辑

类型 变量 含义
服务 器信 息变 量 SERVER_SOFTWARE 服务器软件的名称和版本
SERVER_NAME 服务器的名称
GATEWAY_INTERFACE CGI网关的名称和版本
SERVER_PROTOCAL 服务器传输协议的名称和版本
SERVER_PORT 服务器连接的端口,一般为80
REMOTE_HOST 发出请求的客户机的域名,若无域名则为NULL
客户 端信 息变 量 REMOTE_IP 发出请求的客户机的IP地址
REMOTE_USER 若某个HTML文档是受口令保护的,由此变量获得访问者的名称和密码
REMOTE_IDENT 访问者在服务器上登陆的用户名和密码
HTTP_**** HTTTP协议传输客户端附加信息
Script 信息 变量 REQUEST_METHOD 客户端请求的方法
PATH_INFO 所请求的GRL在CGI目录以下的路径信息
PATH_TRANSLATED 所请求的URL在服务器上的全路径信息(包括CGI目录)
SCRIPT_NAME CGI脚本的文件名
QUERY_STRING 使用GET方法时,请求中的查询的信息
CONTENT_LENGTH 在STDIN中存的用户信息长度
DOCUMENT_URI 请求的文档的URL路径和名称

我是马甲
2007-9-12 15:23:02 发表 编辑

    在 以 前, 我 们 曾 列 出 了 CGI 程 序 所 用 的 几 乎 所 有 环 境 变 量。 其 中, 有 相 当 一 部 分 是 同 数 据 的 输 入 和 输 出 有 密 切 关 系 的。 下 面, 我 们 就 分 类 列 出 其 中 最 常 用 的 环 境 变 量:

    与 服 务 器 相 关 的 环 境 变 量:

GATEWAY_INTERFACE
SERVER_NAME
SERVER_PORT
SERVER_PROTOCOL
SERVER_SOFTWARE

    与 客 户 机 相 关 的 环 境 变 量:

HTTP_ACCEPT
HTTP_ACCEPT_ENCODING
HTTP_ACCEPT_LANGUAGE
HTTP_AUTHORIZATION
HTTP_CHARGE_TO
HTTP_FROM
HTTP_IF_MODIFIED_SINCE
HTTP_PRAGMA
HTTP_REFERER
HTTP_USER_AGENT

    与 请 求 相 关 的 环 境 变 量:

AUTH_TYPE
CONTENT_FILE
CONTENT_LENGTH
CONTENT_TYPE
OUTPUT_FILE
PATH_INFO
PATH_TRANSLATED
QUERY_STRING
REMOTE_ADDR
REMOTE_USER
REQUEST_LINE
REQUEST_METHOD
SCRIPT_NAME

我是马甲
2007-9-12 15:23:39 发表 编辑

zalilea(zali)
回复于 2000-05-30 20:49:00 得分 0

对于xubin_sh恢复的解答我感到不是很好。只提到了一种解决方法。标准CGI中页面上传方式有GET和POST两中方式。他的解决方案中只提到了用POST的方式。GET方式数据的输入是通过QUERY_STRING环境变量传入的,对于POST方式数据是通过标准输入设备stdin输入的。对于GET方式可以用getenv("QUERY_STRING")函数得到输入的数据,相当于perl中的变量=$ENV{'QUERY_STRING'}。对于POST方式用直接从stdin读入的方式可以得到,相当于PERL中的read(STDIN,变量,$ENV{'CONTENT_LENGTH'})。具体的源码可以根据实际的情况有不同的表现。

我是马甲
2007-9-12 15:26:32 发表 编辑

CGI应用程序开发基础 作者:佚名

CGI应用程序开发基础

   CGI应用程序开发基础

当脚本被服务器引发时,服务器常常以两种途径之一向脚本传递信息:GET或POST。这两种方法被称为请求方法。所使用的请求方法是通过环境变量传给脚本,该环境变量叫作REQUEST_METHOD(还定义了另外两种请求方法一HEAD和PUT,但它们不是特别应用于CGI,并且不鼓励使用它们)。

1)GET是对数据的一个请求——同样的方法被用于获得静态文档。GET方法以附加在URL后面的参数发送请求信息。这些参数将放在环境变量QUERY_STRING中传给CGI程序。例如,有一个叫作Myprog.exe的脚本,从如下的链接启动它:

REQUEST_METHOD是GET,QUERY_STRING包含lname=b1ow&fname=joe。在“URL一编码”中将讨论QUERY_STRING的格式。

问号从QUERY_STRING的起始处分隔开脚本名字。在一些服务器上,问号是强制性的,即使后面没有跟着QUERY_STRING。另一些服务器则允许用一个正斜杠代替问号或与之附加在一起。如果使用斜杠,服务器则用PATH_INFO而不是QUERY_STRING变量将信息传给脚本。


2)当浏览器将数据从一个填写表单传给服务器时,发生POST操作。对于POST,QUERY一STRING可能为空或不空,这有赖于服务器。如果有信息,则其如GET的情况一样被格式化和传递。

来自POST查询的数据使用STDIN从服务器传到脚本。由于STDIN是一个源,脚本需要知道有多少有效数据。于是服务器还提供了另一个变量,CONTENT_LENGTH,以指出到来数据的字节数。而POST的数据格式为:
variable1=value1&variable2=value2&etc

你的程序必须检查REQUEST_METHOD环境变量以知道是否要读取STDIN。CONTENT_LENGTH变量一般只在REOUEST_METHOD为POST时有用。


CGI应用的基本结构既简单又直接明了:初始化、处理、输出和终止。由于讨论的是概念、数据源、编程规则,所以在例子中将使用伪码而不是使用某种特定语言。

理想情况下,一个脚本具有如下形式(do-initialize,do-process和do-output代表恰当的子例程):

程序开始
调用 do-initialize
调用 do-proces
调用 do一output
程序结束。
实际情况并非这么简单。

1.1 初始化

脚本启动后必须做的第一件事是确定其输入、环境和状态。基本操作系统环境信息能以通常方式得到:在Windows NT或windows95中从系统注册区得到,在Unix系统中从标准环境变量得到,在别的Windows版本中从INI文件得到,等等。

状态信息来自于输入,而不是操作环境或静态变量。记住:每当CGI脚本被引发时,它都好象此前从未被引发过。脚本不在调用之间持续运行,所有的东西都必须从头初始化,如下:

1.确定脚本是如何被引发的
典型情况下,这涉及读取REQUEST_METHOOD环境变量并分析其中的单词GET或POST。

注意
尽管当前定义应用于coi的操作只有GET和posT,你或许会时不时地遇到PUT或HEAD,假王口你的服务器支持它并且用户的剜览器或一个机器人使用它就可能发生这种情况。 PUl7k作为PosT的另选提供,但从未得多(认可的RFC资格,一般不被使用。HEAD被一些剜览器fotL器人(自动剜览器账用,仅用于提取HTML文在的头部,不适用于C6路程。此外还有一些古怪的请求方法。你的代码应该检查是否为GET和PosT,拒绝任何其他方法,不要假设请求方法如果不是GET便是PosT,或者相反。

2.提取输入数据
如果方法是GET,必须获得、分析、解码QUERY_STRING环境变量。如果方法是POST,必须检查QUERY_STRING并还要分析STDIN。如果CONTENT_TYPE环境变量是设为application/x-www-form-urlencoded,来自STDIN的源也需要解码。

1.2处理

脚本通过读取和分析其输入从而对环境初始化之后,便准备进入工作。在此阶段发生的事情则远没有初始化阶段那样确定。在初始化时,参数是知道的(或是可以被发现),所要做的任务对于各个脚本都多多少少地相同。然而,处理阶段是脚本的核心,在此时要做的事情几乎完全依赖于脚本的目标。


1.处理输入数据
此时做什么取决于脚本。例如,你可以忽略全部输入而仅仅输出数据,可能以有条理格式化的HTML将输入在吐出去,或许会在一个数据库中猎取信息在将其显示出来,或者是从前没有想到的任何事情。处理数据一般意味着,以某种方式对其进行转换。在传统的数据处理术语中,这叫做转换步骤,因为,在面向批作业的处理中,程序读取一个记录并对其施加一些规则(转换它),然后将其写回。CGI 程序很少被看作传统的数据处理,但思想是一样的。程序的处理数据阶段不同的CGI 程序,——在数据处理阶段,你拿到输入,并从其中做出一些新的东西来。

2.输出结果
在一个简单的CGI脚本中,输出常常只是一个头部和一些HTML。更复杂些的脚本可能;输出图形、图形与文本的混和,或者为了用一些附加信息再次调用脚本而必要的全部信息。一个常用并且更精巧的技术是使用GET调用脚本一次,这可以用一个标准的标记做到。脚本可以感知它是用GET调用的,并动态地创建HTML表单一一包括隐藏变量和再次用POST调用脚本所需的代码。

兼容性问题

在UNIX世界中,字符流是一种特殊的文件。默认地,STDIN和STDOUT是字符流。操作系统很有帮助地为你分析流,确保所通过的全是正确的7-bitASCII码,或者是认可的控制码。


7-bit?是的。对于HTML,这没有问题。然而,如果你的脚本发送图形数据,使用面向字符的流则意味着立即失败。解决方法是将流切换到二进制模式。在C语言中,可以使用setmode函数:setmode(fileno(stdout),O_BINARY)。通过setmode(fi1eno(stdout),O_TEXT)在流当中进行切换。一个典型的图形脚本以字符模式输出头部,而后切换到二进制模式用于图形数据。

在windows NT世界中,为了兼容性,流有着同样方式的行为。输出中的一个简单\n,当写到STDOUT时,被变换为\\r\\n。一般的windows NT调用,如write Fi1e(),不发生上述变换,如果同时想要一个回车和一个换行,则必须显式地指出\\r\\n。

字符模式和二进制模式的另一种说法是cooked和raw,知道这两个名词的人或许会使用它们,而不是更常见的说法。不管使用什么词,在什么平台上,关于流存在着另一问题:默认情况下,它们是有缓冲区的,意思是操作系统挂起数据,直至看见一个行结束符、缓冲区满或者流被关闭。这意味着,你如果将有缓冲区的prinif()语句同无缓冲区的fwriie()或fprintf()语句混合在一起,事情可能就变得混乱了,尽管它们都会是写到STDOUT。printf()有缓冲区地将数据写到流,面向文件的例程则无缓冲区地输出数据。结果是乱序的一团糟。

你可能将此归咎于后向兼容性。除了许多老程序之外,流实在没理由将默认定为有缓冲区和cooked。这应当是在需要时可以打开的选项,而不是在不要时关闭。幸运的是,你能够用setvbuf(stdout,NULL,_IONBF,0)解决这一困难,这个函数关闭UTDOUT流的全部缓冲区。

另一个解决是避免混和不同类型的输出语句,即使这样,也不能使cooked输出变成raw。所以最好是关闭所有缓冲区。许多服务器和浏览器不喜欢接收单调乏味的输入。

注意
那些常把UNIX挂在嘴边的人可能会对名词CRLF(回车与换行)皱眉,而那些在其他平台上编程的人也许不认识\\n或\\r\\n。CRLF等于\\r\\n。C编程者用\\r表示一个回车(CR)符号,用\\n表示一个换行(LF)符。(对于Basic编程,LF是Chr$(10,CR是Chr$(13)。)

1.3 终止

终止就是清理和退出。你如果对任何文件加了锁,则必须在程序结束前释放它们。你如果分配了内存、信号量或其他对象,也必须进行释放。不正确完成这些会导致脚本“昙花只能一现”。即脚本在第一次调用时能工作,而在以后的调用中就会崩溃。更有甚者,脚本由于没有正确释放资源和锁,将会妨碍甚至破坏其他脚本或服务器本身。

在一些平台上一Windows NT最显著, UNIX次之——文件句柄和内存对象在进程终止时会被关闭和收回。即使这样,依赖操作系统为你清理垃圾也非明智之举。例如,在Windows NT上,如果一个程序对一个文件全部或部分加锁,而后不释放锁便终止,则文件系统的行为将是不确定的。

必须确保你的出错一退出例程——如果有(也应该有)——了解脚本的资源并能象主退出例程一样彻底地对它们进行清理。

我是马甲
2007-9-12 15:37:45 发表 编辑

CGI原理 - 服务器环境变量


以前一直不清楚CGI具体是怎么工作的,只知道CGI是“向一个socket print”。今天玩了下IIS6的CGI,发现了环境变量,很多是标准HTTP头,还有Web基本IO的工作方式。

首先是一个批处理,用来检测系统

@echo off
more +5 "%~f0"set /p stdin=
set
exit
HTTP/1.1 200 OK
Content-Type: text/html; charset=gb2312











得到的返回的是:





ALLUSERSPROFILE=C:\Documents and Settings\All Users
APP_POOL_ID=DefaultAppPool
ClusterLog=C:\WINDOWS\Cluster\cluster.log
CommonProgramFiles=C:\Program Files\Common Files
COMPUTERNAME=est-Vista
ComSpec=C:\WINDOWS\system32\cmd.exe
FP_NO_HOST_CHECK=NO
NetSamplePath=C:\PROGRA~1\MICROS~3\SDK\v2.0\
NUMBER_OF_PROCESSORS=1
OS=Windows_NT
Path=C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\Program Files\Microsoft SQL Server\80\Tools\BINN
PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.VBS;.VBS
PROCESSOR_ARCHITECTURE=x86
PROCESSOR_IDENTIFIER=x86 Family 6 Model 8 Stepping 6, GenuineIntel
PROCESSOR_LEVEL=6
PROCESSOR_REVISION=0806
ProgramFiles=C:\Program Files
PROMPT=$P$G
stdin=param2=%B2%E2%CA%D4222
SystemDrive=C:
SystemRoot=C:\WINDOWS
TEMP=C:\WINDOWS\TEMP
TMP=C:\WINDOWS\TEMP
USERPROFILE=C:\Documents and Settings\Default User
windir=C:\WINDOWS
HTTP_CACHE_CONTROL=no-cache
HTTP_CONNECTION=Keep-Alive
HTTP_CONTENT_LENGTH=22
HTTP_CONTENT_TYPE=application/x-www-form-urlencoded
HTTP_ACCEPT=image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*
HTTP_ACCEPT_ENCODING=gzip, deflate
HTTP_ACCEPT_LANGUAGE=zh-cn
HTTP_AUTHORIZATION=Negotiate 这里是NTLMSSP验证的Base64字串
HTTP_HOST=127.0.0.1:800
HTTP_REFERER=http://127.0.0.1:800/1.bat
HTTP_USER_AGENT=Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)
HTTP_UA_CPU=x86
APP_POOL_ID=DefaultAppPool
AUTH_TYPE=Negotiate
AUTH_PASSWORD=
AUTH_USER=est-Vista\est
CERT_COOKIE=
CERT_FLAGS=
CERT_ISSUER=
CERT_SERIALNUMBER=
CERT_SUBJECT=
CONTENT_LENGTH=22
CONTENT_TYPE=application/x-www-form-urlencoded
GATEWAY_INTERFACE=CGI/1.1
HTTPS=off
HTTPS_KEYSIZE=
HTTPS_SECRETKEYSIZE=
HTTPS_SERVER_ISSUER=
HTTPS_SERVER_SUBJECT=
INSTANCE_ID=87257011
LOCAL_ADDR=127.0.0.1
LOGON_USER=est-Vista\est
PATH_INFO=/1.bat
PATH_TRANSLATED=C:\temp\iis\1.bat
QUERY_STRING=param1=%B2%E2%CA%D4111
REMOTE_ADDR=127.0.0.1
REMOTE_HOST=127.0.0.1
REMOTE_USER=est-Vista\est
REQUEST_METHOD=POST
SCRIPT_NAME=/1.bat
SERVER_NAME=127.0.0.1
SERVER_PORT=800
SERVER_PORT_SECURE=0
SERVER_PROTOCOL=HTTP/1.1
SERVER_SOFTWARE=Microsoft-IIS/6.0
UNMAPPED_REMOTE_USER=est-Vista\est


可以看出,HTTP GET的工作方式是系统环境变量QUERY_STRING,如果是HTTP POST,则数据从stdin标准输入读取。其他的HTTP请求头都是通过各种各样的环境变量来实现的。
原来Common Gateway Interface就是这么简单,把系统的stdin/stdout转换为Web的IO,很聪明。
不过从今天来看,这种方式已经绝对过时了,特别是Web2.0时代,WebFramework对各种HTTP行为要求很严格,比如说URL Rewrite,绝大多数网站都需要User friendly URL,所以像django这样的框架已经把URL重写做成了基本功能。还有缓存控制、AJAX的domain问题、REST标准等等。CGI实现这些还是too costy了一点。所以IIS有ISAPI,用dll来接管各种Web IO。apache则通过各种mod实现了更加丰富的功能。
不过CGI方式也有其优点,那就是IO效率很高,CGI could stand a high network load。用来实现Web File Distribution最好不过了,呵呵。


总数:6 页次:1/1 首页 尾页  
总数:6 页次:1/1 首页 尾页  


所在合集/目录



发表评论:
文本/html模式切换 插入图片 文本/html模式切换


附件:



NEWBT官方QQ群1: 276678893
可求档连环画,漫画;询问文本处理大师等软件使用技巧;求档softhub软件下载及使用技巧.
但不可"开车",严禁国家敏感话题,不可求档涉及版权的文档软件.
验证问题说明申请入群原因即可.

Copyright © 2005-2020 clq, All Rights Reserved
版权所有
桂ICP备15002303号-1