cgi的表单处理

 1.用c语言写cgi程序

代码用这个:

http://wenda.sogou.com/question/28759329.html

再贴一下:

[xhtml]  view plain copy
  1. #include < stdio.h >  
  2. #include < stdlib.h >  
  3. int main(void)  
  4. {  
  5. char *data;  
  6. long m,n;  
  7. printf("%s%c%c ","Content-Type:text/html;charset=gb2312",13,10);  
  8. printf("< TITLE >乘法结果< /TITLE > ");  
  9. printf("< H3 >乘法结果< /H3 > ");  
  10. data = getenv("QUERY_STRING");  
  11. if(data == NULL)  
  12. printf("< P >错误!数据没有被输入或者数据传输有问题");  
  13. else if(sscanf(data,"m=%ld&n=%ld",&m,&n)!=2)  
  14. printf("< P >错误!输入数据非法。表单中输入的必须是数字。");  
  15. else  
  16. printf("< P >%ld和%ld的成绩是:%ld。",m,n,m*n);  
  17. return 0;  
  18. }  
  19. 编译运行出.exe的文件 。是否要把后缀名改为.cgi?  
  20. 此程序的表单如下:  
  21. < FORM ACTION="/cgi-bin/mult.cgi" >  
  22. < P >请在下面填入乘数和被乘数,按下确定后可以看到结果。  
  23. < INPUT NAME="m" SIZE="5" >  
  24. < INPUT NAME="n" SIZE="5" >< BR >  
  25. < INPUT TYPE="SUBMIT" VALUE="确定" >  
  26. < /FORM >   

 

上面的有点问题,printf第一行最后要有回车/n;

表单中提交方式要为get,看这个解析:

 

[xhtml]  view plain copy
  1. GET 和 POST  
  2. 表单从浏览器发给服务器有两种方法.  GET 和 POST.  
  3.   
  4. 我们上面谈论的方法,实际是GET,它将数据打包放置在环境变量QUERY_STRING中作为URL整体的一部分传递给服务器。  
  5.   
  6. POST做很多类似GET同样的事情, 不同的地方就是它是分离地传递数据给脚本. 你的脚本通过标准输入获取这些数据. (有些Web服务器是存储在临时文件中.) 这个QUERY_STRING环境变量将不再设置.  
  7.   
  8. 那你用那个方法呢? POST是个安全的方法, 尤其如果你的表单中有很多数据的话. 当你用GET, 这个服务器就分配变量QUERY_STRING给所有的表单数据, 但是这个变量可存储量是有限的. 换句话说,如果你有很多数据但是你又用GET,你会丢失很多数据.  
  9.   
  10. 如果你用POST, 你可以尽可能多地使用数据, 因为这些数据从来也不分配到一个变量里. 

2.用c语言写cgi程序

第一个CGI程序:Hello World


Hello World!


任何程序语言的学习都是从打印Hello World!开始的,这样不但可以熟悉程序的流程和大体结构,而且最大限度的避免了一些细小的错误,给初学者信心。


hello.c

#include <stdio.h>


int main(){


        printf("Content-Type:text/plain;charset=us-ascii\n\n");


        printf("Hello World\n\n");


        return 0;


}


#gcc –o hello.cgi hello.c


#cp hello.cgi /var/www/cgi-bin/


用GCC将源文件编译成CGI程序,并拷贝到服务器所制定的cgi程序运行目录中。在浏览器中输入:192.168.44.128/cgi-bin/hello.cgi可以看到页面打印出“Hello World”。


       让我们再来一个更简单的CGI脚本:(Linux下)


#vim /var/www/cgi-bin/hellow.cgi


echo Conten-Type: text/plain


echo


echo


/bin/date


在浏览器中输入:192.168.44.128/cgi-bin/hellow.cgi,我们看到在浏览器页面中输出了当前时间。呵呵,这时应该对CGI是什么有比较深的印象里吧?CGI就是在服务器端执行的一段程序,这段程序执行完毕得到结果后会反馈显示给客户。编写CGI程序的可以是任何形式的语言。


在所有CGI程序中,第一句必须输出HTML头来告诉浏览器这是一个什么样的内容,这个头是服务器与浏览器之间的信息协议并不属于文本的一部分其实Contet-Type指定的就是MIME信息。有三个类型的头部:Contet-TypeLocationStatusContet-Type最为常用




Format


Content-Type


HTML


text/html


Text


text/plain


GIF


image/gif


JPEG


image/jpeg


MPEG


video/mpeg


AVI


Video/avi


Content-Type行后必须接两个空行,不然浏览器不能正确的认出内容类型来。


转自:http://bbs.ednchina.com/BLOG_ARTICLE_256824.HTM

3.实现文件上传


敬告:其实当前的cgic版本已经有上传的功能了,可以看看自带的test文件

用C语言编写cgi程序的话,多半会用到CGIC。 这是个非常流行的库,遇到文件上传之类的应用更是离不开它。官方页面及下载地址为:www.boutell.com/cgic/#obtain

不少网站都有文件上传的功能,本文展示如何用CGIC库编写文件上传的服务端程序,最后给出一段简单的HTML代码,供大家测试使用 。

下载:  upload.c
[cpp]  view plain copy
  1. #include<stdio.h>   
  2. #include<string.h>   
  3. #include<unistd.h>   
  4. #include<fcntl.h>   
  5. #include<sys/stat.h>   
  6. #include"cgic.h"   
  7. #define BufferLen 1024   
  8. int cgiMain(void){   
  9. cgiFilePtr file;   
  10. int targetFile;   
  11. mode_t mode;   
  12. char name[128];   
  13. char fileNameOnServer[64];   
  14. char contentType[1024];   
  15. char buffer[BufferLen];   
  16. char *tmpStr=NULL;   
  17. int size;   
  18. int got,t;   
  19. cgiHeaderContentType("text/html");   
  20. //取得html页面中file元素的值,应该是文件在客户机上的路径名   
  21. if (cgiFormFileName("file", name, sizeof(name)) !=cgiFormSuccess) {   
  22. fprintf(stderr,"could not retrieve filename/n");   
  23. goto FAIL;   
  24. }   
  25. cgiFormFileSize("file", &size);   
  26. //取得文件类型,不过本例中并未使用   
  27. cgiFormFileContentType("file", contentType, sizeof(contentType));   
  28. //目前文件存在于系统临时文件夹中,通常为/tmp,通过该命令打开临时文件。临时文件的名字与用户文件的名字不同,所以不能通过路径/tmp/userfilename的方式获得文件   
  29. if (cgiFormFileOpen("file", &file) != cgiFormSuccess) {   
  30. fprintf(stderr,"could not open the file/n");   
  31. goto FAIL;   
  32. }   
  33. t=-1;   
  34. //从路径名解析出用户文件名   
  35. while(1){   
  36. tmpStr=strstr(name+t+1,"//");   
  37. if(NULL==tmpStr)   
  38. tmpStr=strstr(name+t+1,"/");//if "//" is not path separator, try "/"   
  39. if(NULL!=tmpStr)   
  40. t=(int)(tmpStr-name);   
  41. else   
  42. break;   
  43. }   
  44. strcpy(fileNameOnServer,name+t+1);   
  45. mode=S_IRWXU|S_IRGRP|S_IROTH;   
  46. //在当前目录下建立新的文件,第一个参数实际上是路径名,此处的含义是在cgi程序所在的目录(当前目录))建立新文件   
  47. targetFile=open(fileNameOnServer,O_RDWR|O_CREAT|O_TRUNC|O_APPEND,mode);   
  48. if(targetFile<0){   
  49. fprintf(stderr,"could not create the new file,%s/n",fileNameOnServer);   
  50. goto FAIL;   
  51. }   
  52. //从系统临时文件中读出文件内容,并放到刚创建的目标文件中   
  53. while (cgiFormFileRead(file, buffer, BufferLen, &got) ==cgiFormSuccess){   
  54. if(got>0)   
  55. write(targetFile,buffer,got);   
  56. }   
  57. cgiFormFileClose(file);   
  58. close(targetFile);   
  59. goto END;   
  60. FAIL:   
  61. fprintf(stderr,"Failed to upload");   
  62. return 1;   
  63. END:   
  64. printf("File /"%s/" has been uploaded",fileNameOnServer);   
  65. return 0;   
  66. }   

假设该文件存储为upload.c,则使用如下命令编辑:

gcc -Wall upload.c cgic.c -o upload.cgi

编译完成后把upload.cgi复制到你部署cgi程序的目录(通常命名为cgi-bin)。
正式部署时,请务必修改用open创建新文件那一行代码。把open的第一个参数设置为目标文件在服务器上存储的绝对路径,或者相对于cgi程序的相对路径。本例中,出于简单考虑,在cgi程序所在目录下创建新文件。

测试用HTML代码:

下载:  upload.html
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
   "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Test Upload</title>
    <meta name="author" content="Jack">
    <!-- Date: 2007-08-30 -->
</head>
<body>
<form action="cgi-bin/upload.cgi" method="post" enctype="multipart/form-data" target="_blank">
    <input type="file" name="file" value="" />
    <input type="submit" name="submit" value="OK">
</form>
</body>
</html>

最后的文件目录结构为
/MyWebRoot
|—/upload.html
|—/cgi-bin
|——/upload.cgi
当然,你必须配置能够cgi-bin,并且程序要有权限在cgi-bin目录下创建文件(因为此例把文件上传到cgi-bin目录下)。

那么如何控制上传文件的大小呢?因为你有时会不允许用户上传太大的文件。
通过分析cgic.c的源代码,我们发现它定义了一个变量cgiContentLength,表示请求的长度。但我们需要首先判断这是一个上传文件的请求,然后才能根据cgiContentLength来检查用户是否要上传一个太大的文件。
cgic.c的main函数中进行了一系列if-else判断来检查请求的类型,首先确定这是一个post请求,然后确定数据的编码方式为 “multipart/form-data”,这个判断通过之后,就要开始准备接收数据了。所以我们要在接收数据开始之前使用 cgiContentLength判断大小,如果超过标准,就立即返回,不允许继续操作。
下面贴出修改后代码片段(直接修改cgic.c的源代码即可):

 

[cpp]  view plain copy
  1. else if (cgiStrEqNc(cgiContentType, "multipart/form-data")) {   
  2. #ifdef CGICDEBUG   
  3. CGICDEBUGSTART   
  4. fprintf(dout, "Calling PostMultipartInput/n");   
  5. CGICDEBUGEND   
  6. #endif /* CGICDEBUG */   
  7. //我的代码   
  8. //UpSize:文件长度上限值,以byte为单位,UpSize是一个int变量,因为cgiContentLength的类型为int   
  9. if(cgiContentLength>UpSize){   
  10. cgiHeaderContentType("text/html");   
  11. printf("File too large!/n");   
  12. cgiFreeResources();   
  13. return -1;   
  14. }   
  15. //我的代码结束   
  16. if (cgiParsePostMultipartInput() != cgiParseSuccess) {   
  17. #ifdef CGICDEBUG   
  18. CGICDEBUGSTART   
  19. fprintf(dout, "PostMultipartInput failed/n");   
  20. CGICDEBUGEND   
  21. #endif /* CGICDEBUG */   
  22. cgiFreeResources();   
  23. return -1;   
  24. }   
  25. #ifdef CGICDEBUG   
  26. CGICDEBUGSTART   
  27. fprintf(dout, "PostMultipartInput succeeded/n");   
  28. CGICDEBUGEND   
  29. #endif /* CGICDEBUG */   
  30. }   
  31. }   

4.处理post.,get请求

http://topic.youkuaiyun.com/t/20030213/10/1423382.html

<FORM   METHOD=POST   ACTION="/cgi-bin/sample.exe">   
  <P>Your   name   :   <INPUT   NAME="name"   size=30>   
  <P>Sex   :   
  <INPUT   NAME="sex"   TYPE=RADIO   VALUE="mail"   CHECKED>Male   
  <INPUT   NAME="sex"   TYPE=RADIO   VALUE="female">Female   
  <P>What   are   you   like:   
  <INPUT   NAME="flavor"   TYPE=CHECKBOX   VALUE="apple">Apple   
  <INPUT   NAME="flavor"   TYPE=CHECKBOX   VALUE="orange">Orange   
  <INPUT   NAME="flavor"   TYPE=CHECKBOX   VALUE="strawberry">Strawberry   
  <INPUT   NAME="flavor"   TYPE=CHECKBOX   VALUE="peach">Peach   
  <P>How   much   do   you   eat   them   per   week:   
  <SELECT   NAME="weight">   
  <OPTION   VALUE="little">less   than   1kg   
  <OPTION   VALUE="middle"   SELECTED>1kg   to   3kg   
  <OPTION   VALUE="more">more   than   3kg   
  </SELECT>   
  <P>What's   your   opinion   of   eating   fruit:<BR>   
  <TEXTAREA   NAME="opinion"   COLS=40   ROWS=3>I   think   </TEXTAREA><P>   
  <INPUT   TYPE=SUBMIT   VALUE="Send">   <INPUT   TYPE=RESET   VALUE="Clear">   
  </FORM>   
   

 

数据传送格式 当用户填完表格并按了SUBMIT按钮后,Web浏览器并非将用户所填的数据直接送给Web服务器, 而先要经过一定的编码处理。 Web浏览器总是将数据按照“变量名=变量值”这样的数据对格式进行编码,并且每对数据之间 用一个&符号相连接。其中“变量名”就是Form元素中的NAME属性值;“变量值”则是用户在 输入框中所输入的数据,或者是用户所选择的数据(即RADIO,CHECKBOX,OPTION中 的VALUE值)。 并且Web浏览器将用户数据中的所有空格都替换成"+"号。另外一些特殊字符的表示使用转义 符"%"后面加上该特殊字符的十六进制ASCII码。特殊字符主要包括"="、"+"、"&"、"%"以及多 行文本中的回车,换行符,所有不能直接显示的高位ASCII符等。 一个Form的简单例子 例如在上例中用户填入了下述信息(其中/n表示回车换行): name "J&K" sex "male" flavor "apple" flavor "orange" weight "middle" opinion "I think it is necessary that/nman eat fruit everyday." 则Web浏览器发送数据时的字符序列为: name=J%26K&sex=male&flavor=apple&flavor=orange&weight=middle& opinion=I+think+it+is+necessary+that%0D%0Aman+eat+fruit+everyday. 用CGI程序处理得到的数据 当Web浏览器将Form数据经过编码后,就传送给了Web服务器,而Web服务器并非自己处理这些 数据,而是先依靠CGI程序来帮忙处理这些数据,然后Web服务器再把CGI程序产生的处理结果 返回给Web浏览器。CGI(Common Gateway Interface,通用网关接口)是信息服务器(如Web服 务器)与外部应用程序之间的一个接口标准。通常被Web服务器所取到的HTML文件总是事先编 辑好的,固定不变的信息,但若通过实时运行着的CGI程序Web服务器就有可能向Web浏览器 输出动态的信息。 CGI标准用最简单的话来说就是:CGI程序是通过标准输入(stdin)或环境变量来得到服务器的输 入信息,并通过标准输出(stdout)向服务器输出信息。 当Web服务器收到了由Web浏览器传来的Form数据时,就启动

标记中ACTION属性所指 明的CGI程序。如果METHOD属性值是GET,CGI程序就从环境变量QUERY_STRING中获取Form数 据;若METHOD属性值是POST,CGI程序就从标准输入(stdin)中获取Form数据。 CGI程序获取Form数据并经过处理后,还要向Web服务器返回一定的信息(如数据的处理结果等 )。为让Web服务器能正确理解所返回的是何种信息,CGI规定在输出的信息体前加上一个头部 信息,该头部信息由若干行ASCII文本构成,并用一个空行将头部信息与信息体隔开。例如要返 回HTML文档则头部信息为"Content-type: text/html"。 下面给出一个用C语言编写的CGI程序的基本框架:

 

[cpp]  view plain copy
  1. #include   <stdio.h>    
  2.   #include   <stdlib.h>    
  3.   #include   <string.h>    
  4.   char   InputBuffer[4096];    
  5.   int   main(int   argc,   char   *argv[])   {    
  6.   int   ContentLength;   /*数据长度*/    
  7.   int   x;    
  8.   int   i;    
  9.   char   *p;    
  10.   char   *pRequestMethod;     /*   METHOD属性值   */    
  11.           setvbuf(stdin,NULL,_IONBF,0);     /*关闭stdin的缓冲*/    
  12.           printf("Content-type:   text/html/n");     /*从stdout中输出,告诉Web服务器返回的信息类型*/    
  13.   printf("/n");                                           /*插入一个空行,结束头部信息*/    
  14.           /*   从环境变量REQUEST_METHOD中得到METHOD属性值   */    
  15.           pRequestMethod   =   getenv("REQUEST_METHOD");    
  16.           if   (pRequestMethod==NULL)   {    
  17.                   return   0;    
  18.           }    
  19.           if   (_stricmp(pRequestMethod,"POST")==0)   {    
  20.                   p   =   getenv("CONTENT_LENGTH");     /*从环境变量CONTENT_LENGTH中得到数据长度*/    
  21.                   if   (p!=NULL)   {    
  22.                           ContentLength   =   atoi(p);    
  23.                   }   else   {    
  24.                           ContentLength   =   0;    
  25.         }    
  26.                   if   (ContentLength>sizeof(InputBuffer)-1)   {    
  27.                           ContentLength   =   sizeof(InputBuffer)-1;    
  28.         }    
  29.                   i   =   0;    
  30.                   while   (i<ContentLength)   {                         /*从stdin中得到Form数据*/    
  31.                           x   =   fgetc(stdin);    
  32.                           if   (x==EOF)   break;    
  33.                           InputBuffer[i++]   =   x;    
  34.         }    
  35.                   InputBuffer[i]   =   '/0';    
  36.                   ContentLength   =   i;    
  37.                   DecodeAndProcessData();                 /*具体译码和处理数据,该函数代码略*/    
  38.           }   else      
  39.           if   (_stricmp(pRequestMethod,"GET")==0)   {    
  40.                   p   =   getenv("QUERY_STRING");     /*从环境变量QUERY_STRING中得到Form数据*/    
  41.                   if   (p!=NULL)   {    
  42.                           strncpy(InputBuffer,p,sizeof(InputBuffer));    
  43.                           DecodeAndProcessData();                               /*具体译码和处理数据,该函数代码略*/    
  44.         }    
  45.         }    
  46.         printf("<HEAD><TITLE>Submitted   OK</TITLE></HEAD>/n");       /*从stdout中输出返回信息*/    
  47.         printf("<BODY>The   information   you   supplied   has   been   accepted.</BODY>/n");    
  48.         return   0;    
  49.   }     
以上转自:http://blog.youkuaiyun.com/lanmanck/article/details/5359403

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值