1.用c语言写cgi程序
代码用这个:
http://wenda.sogou.com/question/28759329.html
再贴一下:
- #include < stdio.h >
- #include < stdlib.h >
- int main(void)
- {
- char *data;
- long m,n;
- printf("%s%c%c ","Content-Type:text/html;charset=gb2312",13,10);
- printf("< TITLE >乘法结果< /TITLE > ");
- printf("< H3 >乘法结果< /H3 > ");
- data = getenv("QUERY_STRING");
- if(data == NULL)
- printf("< P >错误!数据没有被输入或者数据传输有问题");
- else if(sscanf(data,"m=%ld&n=%ld",&m,&n)!=2)
- printf("< P >错误!输入数据非法。表单中输入的必须是数字。");
- else
- printf("< P >%ld和%ld的成绩是:%ld。",m,n,m*n);
- return 0;
- }
- 编译运行出.exe的文件 。是否要把后缀名改为.cgi?
- 此程序的表单如下:
- < FORM ACTION="/cgi-bin/mult.cgi" >
- < P >请在下面填入乘数和被乘数,按下确定后可以看到结果。
- < INPUT NAME="m" SIZE="5" >
- < INPUT NAME="n" SIZE="5" >< BR >
- < INPUT TYPE="SUBMIT" VALUE="确定" >
- < /FORM >
上面的有点问题,printf第一行最后要有回车/n;
表单中提交方式要为get,看这个解析:
- GET 和 POST
- 表单从浏览器发给服务器有两种方法. GET 和 POST.
- 我们上面谈论的方法,实际是GET,它将数据打包放置在环境变量QUERY_STRING中作为URL整体的一部分传递给服务器。
- POST做很多类似GET同样的事情, 不同的地方就是它是分离地传递数据给脚本. 你的脚本通过标准输入获取这些数据. (有些Web服务器是存储在临时文件中.) 这个QUERY_STRING环境变量将不再设置.
- 那你用那个方法呢? POST是个安全的方法, 尤其如果你的表单中有很多数据的话. 当你用GET, 这个服务器就分配变量QUERY_STRING给所有的表单数据, 但是这个变量可存储量是有限的. 换句话说,如果你有很多数据但是你又用GET,你会丢失很多数据.
- 如果你用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-Type,Location,Status。Contet-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代码,供大家测试使用 。
- #include<stdio.h>
- #include<string.h>
- #include<unistd.h>
- #include<fcntl.h>
- #include<sys/stat.h>
- #include"cgic.h"
- #define BufferLen 1024
- int cgiMain(void){
- cgiFilePtr file;
- int targetFile;
- mode_t mode;
- char name[128];
- char fileNameOnServer[64];
- char contentType[1024];
- char buffer[BufferLen];
- char *tmpStr=NULL;
- int size;
- int got,t;
- cgiHeaderContentType("text/html");
- //取得html页面中file元素的值,应该是文件在客户机上的路径名
- if (cgiFormFileName("file", name, sizeof(name)) !=cgiFormSuccess) {
- fprintf(stderr,"could not retrieve filename/n");
- goto FAIL;
- }
- cgiFormFileSize("file", &size);
- //取得文件类型,不过本例中并未使用
- cgiFormFileContentType("file", contentType, sizeof(contentType));
- //目前文件存在于系统临时文件夹中,通常为/tmp,通过该命令打开临时文件。临时文件的名字与用户文件的名字不同,所以不能通过路径/tmp/userfilename的方式获得文件
- if (cgiFormFileOpen("file", &file) != cgiFormSuccess) {
- fprintf(stderr,"could not open the file/n");
- goto FAIL;
- }
- t=-1;
- //从路径名解析出用户文件名
- while(1){
- tmpStr=strstr(name+t+1,"//");
- if(NULL==tmpStr)
- tmpStr=strstr(name+t+1,"/");//if "//" is not path separator, try "/"
- if(NULL!=tmpStr)
- t=(int)(tmpStr-name);
- else
- break;
- }
- strcpy(fileNameOnServer,name+t+1);
- mode=S_IRWXU|S_IRGRP|S_IROTH;
- //在当前目录下建立新的文件,第一个参数实际上是路径名,此处的含义是在cgi程序所在的目录(当前目录))建立新文件
- targetFile=open(fileNameOnServer,O_RDWR|O_CREAT|O_TRUNC|O_APPEND,mode);
- if(targetFile<0){
- fprintf(stderr,"could not create the new file,%s/n",fileNameOnServer);
- goto FAIL;
- }
- //从系统临时文件中读出文件内容,并放到刚创建的目标文件中
- while (cgiFormFileRead(file, buffer, BufferLen, &got) ==cgiFormSuccess){
- if(got>0)
- write(targetFile,buffer,got);
- }
- cgiFormFileClose(file);
- close(targetFile);
- goto END;
- FAIL:
- fprintf(stderr,"Failed to upload");
- return 1;
- END:
- printf("File /"%s/" has been uploaded",fileNameOnServer);
- return 0;
- }
假设该文件存储为upload.c,则使用如下命令编辑:
编译完成后把upload.cgi复制到你部署cgi程序的目录(通常命名为cgi-bin)。
正式部署时,请务必修改用open创建新文件那一行代码。把open的第一个参数设置为目标文件在服务器上存储的绝对路径,或者相对于cgi程序的相对路径。本例中,出于简单考虑,在cgi程序所在目录下创建新文件。
测试用HTML代码:
"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的源代码即可):
- else if (cgiStrEqNc(cgiContentType, "multipart/form-data")) {
- #ifdef CGICDEBUG
- CGICDEBUGSTART
- fprintf(dout, "Calling PostMultipartInput/n");
- CGICDEBUGEND
- #endif /* CGICDEBUG */
- //我的代码
- //UpSize:文件长度上限值,以byte为单位,UpSize是一个int变量,因为cgiContentLength的类型为int
- if(cgiContentLength>UpSize){
- cgiHeaderContentType("text/html");
- printf("File too large!/n");
- cgiFreeResources();
- return -1;
- }
- //我的代码结束
- if (cgiParsePostMultipartInput() != cgiParseSuccess) {
- #ifdef CGICDEBUG
- CGICDEBUGSTART
- fprintf(dout, "PostMultipartInput failed/n");
- CGICDEBUGEND
- #endif /* CGICDEBUG */
- cgiFreeResources();
- return -1;
- }
- #ifdef CGICDEBUG
- CGICDEBUGSTART
- fprintf(dout, "PostMultipartInput succeeded/n");
- CGICDEBUGEND
- #endif /* CGICDEBUG */
- }
- }
4.处理post.,get请求
http://topic.youkuaiyun.com/t/20030213/10/1423382.html
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- char InputBuffer[4096];
- int main(int argc, char *argv[]) {
- int ContentLength; /*数据长度*/
- int x;
- int i;
- char *p;
- char *pRequestMethod; /* METHOD属性值 */
- setvbuf(stdin,NULL,_IONBF,0); /*关闭stdin的缓冲*/
- printf("Content-type: text/html/n"); /*从stdout中输出,告诉Web服务器返回的信息类型*/
- printf("/n"); /*插入一个空行,结束头部信息*/
- /* 从环境变量REQUEST_METHOD中得到METHOD属性值 */
- pRequestMethod = getenv("REQUEST_METHOD");
- if (pRequestMethod==NULL) {
- return 0;
- }
- if (_stricmp(pRequestMethod,"POST")==0) {
- p = getenv("CONTENT_LENGTH"); /*从环境变量CONTENT_LENGTH中得到数据长度*/
- if (p!=NULL) {
- ContentLength = atoi(p);
- } else {
- ContentLength = 0;
- }
- if (ContentLength>sizeof(InputBuffer)-1) {
- ContentLength = sizeof(InputBuffer)-1;
- }
- i = 0;
- while (i<ContentLength) { /*从stdin中得到Form数据*/
- x = fgetc(stdin);
- if (x==EOF) break;
- InputBuffer[i++] = x;
- }
- InputBuffer[i] = '/0';
- ContentLength = i;
- DecodeAndProcessData(); /*具体译码和处理数据,该函数代码略*/
- } else
- if (_stricmp(pRequestMethod,"GET")==0) {
- p = getenv("QUERY_STRING"); /*从环境变量QUERY_STRING中得到Form数据*/
- if (p!=NULL) {
- strncpy(InputBuffer,p,sizeof(InputBuffer));
- DecodeAndProcessData(); /*具体译码和处理数据,该函数代码略*/
- }
- }
- printf("<HEAD><TITLE>Submitted OK</TITLE></HEAD>/n"); /*从stdout中输出返回信息*/
- printf("<BODY>The information you supplied has been accepted.</BODY>/n");
- return 0;
- }