cgi语言:CGI之C语言篇



为什么要进行CGI编程?

  在HTML中当客户填写了表单并按下了发送(submit)按钮后表单内容被发送到了服务器端这时就需要有个服务器端脚本来对表单内容进行些处理或者是把它们保存起来或者是按内容进行些查询或者是些别什么没有了CGIWEB世界就完全失去了它交互性所有信息都变成单向而不能够有任何反馈


  有人认为可以用javascript来代替CGI这其实是个概念上javascript只能够在客户浏览器中运行而CGI却是工作在服务器上他们所做工作有些交集比如表单数据验证但是javascript是绝对无法取代CGI但可以这样说如果项工作即能够用javascript来做又可以用CGI来做那么绝对要使用javascript在执行速度上javascript比CGI有着先天优势只有那些在客户端解决不了问题比如和某个远程数据库交互这时就应该使用CGI了


  简单说来CGI是用来沟通HTML表单和服务器端接口(erface)说它是接口也就是说CGI并不是种语言而是可以被其他语言所应用个规范标准集理论上讲你可以用任何语言来编写CGI只要在编程时候符合CGI规范标准所定义些东西就可以了由于C语言在平台无关性上表现不错(几乎在任何系统平台下都有其相应编译器)而且对大多数员而言都算得上很熟悉(不像Perl)因此C是CGI编程首选语言的这儿我们介绍就是如何使用C来编写CGI


  作为CGI编程最为简单例子就是进行表单处理因而在这篇文章中我们主要介绍就是如何用C来编写CGI来进行表但处理

  GET表单处理

  对于那些使用了属性“METHOD=GET”表单(或者没有METHOD属性这时候GET是其缺省值)CGI定义为:当表单被发送到服务器断后表单中数据被保存在服务器上个叫做QUERY_STRING环境变量中这种表单处理相对简单只要读取环境变量就可以了点对区别语言有区别做法在C语言中你可以用库getenv(定义在标准库stdlib中)来把环境变量值作为串来存取你可以在取得了串中数据后运用些小窍门技巧进行类型转换这都是比较简单在CGI标准输出(output)(比如在C中stdout文件流)也是经过重定义了它并没有在服务器上产生任何输出内容而是被重定向到客户浏览器这样如果编写个CCGI时候个HTML文档输出到它stdout上这个HTML文档会被在客户端浏览器中显示出来这也是CGI个基本原理

  我们来看看具体实现下面是段HTML表单:

<formACTION="/cgi-bin/mult.cgi">

<P>请在下面填入乘数和被乘数按下确定后可以看到结果

<INPUTNAME="m"SIZE="5">

<INPUTNAME="n"SIZE="5"><BR>

<INPUTTYPE="SUBMIT"values="确定">

</form>


  我们要实现功能很简单就是把表单中输入数值乘起来然后输出结果其实这个功能完全可以用javascript来实现但为了让尽量简单易懂我还是选择了这个小小乘法来作为举例


  下面就是处理这个表单CGI对应于form标签中ACTION属性值


#<stdio.h>

#<stdlib.h>

(void)

{

char*data;

longm,n;

prf("%s%c%c","Content-Type:text/html;char=gb2312",13,10);

prf("<TITLE>乘法结果</TITLE>");

prf("<H3>乘法结果</H3>");

data=getenv("QUERY_STRING");

(dataNULL)

prf("<P>!数据没有被输入或者数据传输有问题");

(sscanf(data,"m=%ld&n=%ld",&m,&n)!=2)

prf("<P>!输入数据非法表单中输入必须是数字");



prf("<P>%ld和%ld成绩是:%ld",m,n,m*n);

0;

}


  具体C语法就不多讲了我们来看看它作为CGI所特殊地方


  前面已经提到标准输出内容就是要被显示在浏览器中内容输出内容是必须也是个CGI所特有:prf("%s%c%c","Content-Type:text/html",13,10)这个输出是作为HTML文件头CGI不仅可以像浏览器输出HTML文本而且可以输出图像声音的类东西行告诉浏览器如何处理接受到内容在Content-Type定义后面跟有两行空行这也是不可缺少所有CGI头部输出都是相近因而可以为其定义来节省编程时间这是CGI编程常用个窍门技巧


  在后面了用了库getevn来得到QUERY_STRING内容然后使用sscanf把每个参数值取出来要注意是sscanf使用方法其他就没有什么了C没有区别


  把编译后改名为mult.cgi放在/cgi-bin/目录下面就可以被表单这样个处理GET方式表单CGI就大功告成了




  POST表单处理


  下面我们来考虑另外种表单传送思路方法:POST假设我们要实现任务是这样:把表单中客户输入段文本内容添加到服务器上个文本文件后面这可以看作是个留言版雏形显然这个工作是无法用javascript这种客户端脚本来实现也算得上真正意义上CGI


  看起来这个问题和上面讲内容很相近仅仅是用区别表单和区别脚本()而已但实际上这中间是有些区别在上面例子中GET处理思路方法可以看作是“纯查询(purequery)”类型也就是说它和状态无关同样数据可以被提交任意次数而不会引起任何问题(除了服务器些小小开销)但是现在任务就区别了至少它要改变个文件内容因而可以说它是和状态有关这也算是POST和GET区别的而且GET对于表单长度是有限制而POST则不然这也是在这个任务中选用POST思路方法主要原因但相对对GET处理速度就要比POST快


  在CGI定义中对于POST类型表单其内容被送到CGI标准输入(在C语言中是stdin)而被传送长度被放在环境变量CONTENT_LENGTH中因而我们要做就是在标准输入中读入CONTENT_LENGTH长度从标准输出读入数据听起来似乎要比从环境变量中读数据来要容易其实则不然,有些细节地方要注意这在下面中可以看到特别要注意点就是:CGI有所区别在读完了个文件流内容的后会得到个EOF标志但在CGI表单处理过程中EOF是永远不会出现所以千万不要读多于CONTENT_LENGTH长度否这会有什么后果谁也不知道(CGI规范标准中没有定义般根据服务器区别而有区别得处理思路方法)


  我们来看看到底如何从POST表单收集数据到CGI下面給出了個比较简单C源代碼:

#<stdio.h>

#<stdlib.h>

#MAXLEN80

#EXTRA5

/*4个字节留给字段名字"data",1个字节留给"="*/

#MAXINPUTMAXLEN+EXTRA+2

/*1个字节留给换行符还有个留给后面NULL*/

#DATAFILE"../data/data.txt"

/*要被添加数据文件*/


voidunencode(char*src,char*last,char*dest)

{

for(;src!=last;src,dest)

(*src"+")

*dest="";

(*src"%"){

code;

(sscanf(src+1,"%2x",&code)!=1)code="?";

*dest=code;

src2;}



*dest=*src;

*dest="";

*dest="";

}

(void)

{

char*lenstr;

charinput[MAXINPUT],data[MAXINPUT];

longlen;

prf("%s%c%c",

"Content-Type:text/html;char=gb2312",13,10);

prf("<TITLE>Response</TITLE>");

lenstr=getenv("CONTENT_LENGTH");

(lenstrNULL||sscanf(lenstr,"%ld",&len)!=1||len>MAXLEN)

prf("<P>表单提交");

{

FILE*f;

fgets(input,len+1,stdin);

unencode(input+EXTRA,input+len,data);

f=fopen(DATAFILE,"a");

(fNULL)

prf("<P>对不起意外不能够保存你数据");



fputs(data,f);

fclose(f);

prf("<P>非常感谢数据已经被保存<BR>%s",data);

}

0;

}




  从本质上来看先从CONTENT_LENGTH环境变量中得到数据字长然后读取相应长度数据内容在传输过程中是经过了编码所以必须进行相应解码编码规则很简单主要有这几条:


  1.表单中每个每个字段用字段名后跟等号再接上上这个字段值来表示每个字段的间内容用&连结;


  2.所有空格符号用加号代替所以在编码码段中出现空格是非法


  3.特殊比如标点符号些有特定意义如“+”用百分号后跟其对应ACSII码值来表示


  例如:如果用户输入是:


  Hellothere!


  那么数据传送到服务器时候经过编码就变成了data=Hello+there%21上面unencode()就是用来把编码后数据进行解码在解码完成后数据被添加到data.txt文件尾部并在浏览其中回显出来


  把文件编译完成后把它改名为collect.cgi后放在CGI目录中就可以被表单下面给出了其相应表单:




<formACTION="/cgi-bin/collect.cgi"METHOD="POST">

<P>请输入您留言(最多80个):<BR><INPUTNAME="data"SIZE="60"MAXLENGTH="80"><BR>

<INPUTTYPE="SUBMIT"values="确定">

</form>


  事实上这个只能作为例子是不能够正式使用它漏掉了很关键个问题:当有多个用户同时像文件写入数据是肯定会有发生而对于个这样而言文件被同时写入几率是很大因此在比较正式留言版都需要做些更多考虑比如加入个信号量或者是借助于个钥匙文件等那只是编程窍门技巧问题在这儿就不多说了


  最后我们来写个浏览data.txt文件CGI这只需要把内容输出到stdout就可以了:

  #<stdio.h>

  #<stdlib.h>

  #DATAFILE"../data/data.txt"

  (void)

  {

  FILE*f=fopen(DATAFILE,"r");

  ch;

  (fNULL){

  prf("%s%c%c",

  "Content-Type:text/html;char=gb2312",13,10);

  prf("<TITLE></TITLE>");

  prf("<P><EM>意外无法打开文件</EM>");}

  {

  prf("%s%c%c",

  "Content-Type:text/plain",13,10);

  while((ch=getc(f))!=EOF)

  putchar(ch);

  fclose(f);}

  0;

  }


  这个要注意是:它并没有把data.txt包装成HTML格式后再输出而是直接作为简单文本(plaext)输出这只要在输出头部用text/plain类型代替text/html就可以了浏览器会根据Content-Type类型自动选择相应处理思路方法


  要触发这个也很简单没有数据要输入所以只需个按钮就可以搞定了:


  <formACTION="/cgi-bin/viewdata.cgi">

  <P><INPUTTYPE="SUBMIT"values="察看">

  </form>


  到这儿些基本用C编写CGI原理就将完了当然就凭讲这些内容还很难编写出个好CGI这需要进学习CGI规范标准定义以及些其他CGI编程特有窍门技巧


  这篇文章也就是要你了解下CGI编程概念事实上现在些主流服务器端脚本编程语言如ASPPHPJSP等都基本上具备了CGI编程大部分功能但他们在使用上确实是比无论用什么语言进行CGI编程都要容易所以在进行服务器端编程时候般都会首先考虑使用这些脚本编程语言只有当他们也解决不了比如要进行些更为底层编程时候才会用到CGI
Tags:  c语言教程 c语言 流行语言100篇 cgi语言

延伸阅读

最新评论

发表评论