首页 > php > 用c语言写cgi程序实现文件上传

用c语言写cgi程序实现文件上传

现在很少有用C实现文件上传了,有Nginx的上传模块,用CGI实现文件上传在这里作下备案。
后加参考:http://hi.baidu.com/davidgabriel/item/58fec40b4c2f49803c42e290
用C语言库(CGIC)编写CGI,实现文件上传:
http://hi.baidu.com/rszlatkfoxbalqd/item/62bb3a4e04e89c0fc0161326
使用C语言的CGI库“CGIC”完成Web开发的各种要求 :
http://blog.sina.com.cn/s/blog_75a8cfac0100p9es.html
add Time:2014-01-14

upload.html

<HTML>
<HEAD>
<TITLE>上传数据文件</TITLE>
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="TEXT/HTML;CHARSER=UTF-8">
<link rel="stylesheet" type="text/css" href="css/main.css">
<script type="text/javascript">
function upload_file(){
if( document.getElementById('FILE1').value == '' ){
alert("请选择文件!");
return false;
}

document.getElementById('uploadInfo').innerHTML = '' ;
document.getElementById('uploadInfo').innerHTML = '<img src="images/wait.gif"><br>数据上传中,请稍候……' ;

document.getElementById('form1').submit();
}
</script> 
</HEAD>
<BODY BGCOLOR="#FFFFFF">
<FORM METHOD="POST" id="form1" name="form1" ENCTYPE="multipart/form-data" ACTION="cgi-bin/uploadcgi.cgi">
选择文件:<INPUT TYPE="FILE" NAME="FILE1" id="FILE1" class="btn"><INPUT TYPE="button" onclick="upload_file()" VALUE="上传" class="btn"><br>
<center>
<div id="uploadInfo"></div>
</center>
</FORM>
</BODY>
</HTML>
#

uploadcgi.c

/**************************************************************************
2007-1-5 11:42 establish by lzh.A cgi program.
get a file from user's explorer.
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define DEAL_BUF_LEN 1024
#define SIGN_CODE_LEN 100
#define FILE_NAME_LEN 64
#define FILE_SAVE_DIR "/var/landog/db_upload/"

enum
{
STATE_START,
STATE_GET_SIGN_CODE,
STATE_GET_FILE_NAME,
STATE_GET_FILE_START,
STATE_GET_FILE_CONTENT,
STATE_CHECK_END,
STATE_END
};
/***************************************************************************
ShowErrorInfo
****************************************************************************/
static void ShowErrorInfo(char * error)
{

printf("Content-Type:text/html;charset=UTF-8\n\n");
printf("<center><font color='red'>%s</font></center>" , error );
}

/* 主体从这里开始 */

int main(void)
{
FILE *fp; /* 文件指针,保存我们要获得的文件 */
int getState = STATE_START;
int contentLength;/*标准输入内容长度*/
int nowReadLen;
int signCodeLen;
int tmpLen;
char *nowReadP;
char *nowWriteP;
char dealBuf[DEAL_BUF_LEN];
char signCode[SIGN_CODE_LEN]; /*存储本次的特征码*/
char tmpSignCode[SIGN_CODE_LEN];
char fileName[FILE_NAME_LEN];
memset(dealBuf,0,DEAL_BUF_LEN);
memset(signCode,0,SIGN_CODE_LEN);
memset(fileName,0,FILE_NAME_LEN);
nowReadLen = 0;
if((char *)getenv("CONTENT_LENGTH")!=NULL)
{
contentLength = atoi((char *)getenv("CONTENT_LENGTH"));
}
else
{
ShowErrorInfo("没有恢复数据!");
exit(1);
}

while(contentLength > 0)
{
if(contentLength >= DEAL_BUF_LEN)
{
nowReadLen = DEAL_BUF_LEN;
}
else
{
nowReadLen = contentLength;
}
contentLength -= nowReadLen;
if(fread(dealBuf,sizeof(char),nowReadLen,stdin) != nowReadLen)
{
ShowErrorInfo("读取恢复数据失败,请重试!");
exit(1);
}
nowReadP = dealBuf;
while(nowReadLen > 0)
{
switch (getState)
{
case STATE_START:
nowWriteP = signCode;
getState = STATE_GET_SIGN_CODE;
case STATE_GET_SIGN_CODE:
if(strncmp(nowReadP,"\r\n",2) == 0)
{
signCodeLen = nowWriteP - signCode;
nowReadP++;
nowReadLen--;
*nowWriteP = 0;
getState = STATE_GET_FILE_NAME;
//ShowErrorInfo(signCode);
}
else
{
*nowWriteP = *nowReadP;
nowWriteP++;
}
break;
case STATE_GET_FILE_NAME:
if(strncmp(nowReadP,"filename=",strlen("filename=")) == 0)
{
nowReadP += strlen("filename=");
nowReadLen -= strlen("filename=");
nowWriteP = fileName + strlen(FILE_SAVE_DIR);
while(*nowReadP != '\r')
{
if(*nowReadP == '\\' || *nowReadP == '/')
{
nowWriteP = fileName + strlen(FILE_SAVE_DIR);
}
else if(*nowReadP != '\"')
{
*nowWriteP = *nowReadP;
nowWriteP++;
}
nowReadP++;
nowReadLen--;
}
*nowWriteP = 0;
nowReadP++;
nowReadLen--;
getState = STATE_GET_FILE_START;
memcpy(fileName,FILE_SAVE_DIR,strlen(FILE_SAVE_DIR));
if((fp=fopen(fileName,"w"))==NULL)
{
fprintf(stderr,"open file error\n");
exit(1);
}
//ShowErrorInfo(fileName);
}
break;
case STATE_GET_FILE_START:
if(strncmp(nowReadP,"\r\n\r\n",4) == 0)
{
nowReadP += 3;
nowReadLen -= 3;
getState = STATE_GET_FILE_CONTENT;
//ShowErrorInfo("get");
}
break;
case STATE_GET_FILE_CONTENT:
if(*nowReadP != '\r')
{
fputc(*nowReadP,fp);
}
else
{
if(nowReadLen >= (signCodeLen + 2))
{
if(strncmp(nowReadP + 2,signCode,signCodeLen) == 0)
{
getState = STATE_END;
nowReadLen = 1;
ShowErrorInfo("数据上传成功");
/* if( system( "/var/landog/app/sniff/db_recover.sh" ) == 0 ){
ShowErrorInfo( "数据库恢复完成,请重新启动landog" ); 
}else{
ShowErrorInfo( "数据库恢复过程中出现错误,错误原因:恢复的文件已经损坏" );
}
*/
}
else
{
fputc(*nowReadP,fp);
}
}
else
{
getState = STATE_CHECK_END;
nowWriteP = tmpSignCode;
*nowWriteP = *nowReadP;
nowWriteP++;
tmpLen = 1;
}
}
break;
case STATE_CHECK_END:
if(*nowReadP != '\r')
{
if(tmpLen < signCodeLen + 2)
{
*nowWriteP = *nowReadP;
nowWriteP++;
tmpLen++;
if(tmpLen == signCodeLen + 2)
{
*nowWriteP = 0;
if((tmpSignCode[1] == '\n')&&(strncmp(tmpSignCode + 2,signCode,signCodeLen) == 0))
{
getState = STATE_END;
nowReadLen = 1;
ShowErrorInfo("数据上传成功");
/* if( system( "/var/landog/app/sniff/db_recover.sh" ) == 0 ){
ShowErrorInfo( "数据库恢复完成,请重新启动landog" ); 
}else{
ShowErrorInfo( "数据库恢复过程中出现错误,错误原因:恢复的文件已经损坏" );
}
*/
}
else
{
//fprintf(fp,tmpSignCode);
fwrite(tmpSignCode,sizeof(char),tmpLen,fp);
getState = STATE_GET_FILE_CONTENT;
}
}
}
}
else
{
*nowWriteP = 0;
//fprintf(fp,tmpSignCode);
fwrite(tmpSignCode,sizeof(char),tmpLen,fp);
nowWriteP = tmpSignCode;
*nowWriteP = *nowReadP;
nowWriteP++;
tmpLen = 1;
}
break;
case STATE_END:
nowReadLen = 1;
break;
default:break;
}
nowReadLen--;
nowReadP++;
}
}
if(fp != NULL)
{
fclose(fp);
}
return 0;
}

=========================================================================
另一个写在一个文件里的CGI文件上传方式,[备注:]C语言-cgi文件上传代码,它通过 getenv("CONTENT_LENGTH") 之后可以直接对stdin使用fread() 但是在实际应用时发现,有时候文件读不全 ,注意要使用二进制模式来读取,而不是文本模式:

#include   <stdio.h> 
#include   <stdlib.h> 
#include   <string.h> 
#include   <ctype.h> 
#include   <fcntl.h> 
#define   ACHEAD "ooooooooooooo"
#define AC483PATH "../htdocs/ac483/ac483_bak"
void fit(char *,unsigned size);

int   main(int   argc,   char   *argv[]) 
{ 
    printf("Content-Type:text/html\n\n");     
    char   *pMethod   =   getenv("REQUEST_METHOD");
    //printf("pMethod=%s\n",pMethod); 
    if(pMethod   ==   NULL   ||   *pMethod   ==   0) 
    { 
      printf("No   Any   Method!\n"); 
      return   0; 
    } 
  
    if(strcmp(pMethod,   "GET")   ==   0) 
      return   1; 
  
    if(strcmp(pMethod,   "POST")   ==   0) 
    { 
      char   *pCntLen   =   getenv("CONTENT_LENGTH"); 
      //printf("pCntLen=%s\n",pCntLen);
      if(!pCntLen) 
      { 
        printf("Can't   get   Content_Length!\n"); 
        return   0; 
      } 
      if(*pCntLen   ==   0) 
      { 
        printf("Can't   get   Content_Length!\n"); 
        return   0; 
      } 
      int   StrLen   =   atoi(pCntLen);
      // printf("StrLen=%d\n",StrLen); 
      if(StrLen   <=   0) 
      { 
        printf("String   Length   <=   0\n"); 
        return   0; 
      } 
      //char *ph = getenv("CONTENT_TYPE");
      //printf("ph=%s\n",ph);
      
      char *readstr=(char   *)malloc(StrLen+1);
      fread(readstr,StrLen,1,stdin);
      // printf("readstr=%s\n",readstr);
      int n=0;
      int firstLineMark=0;
      int firstLineCount=0;
      int headCount=0;
      while(n<4)
      {
      if(*(readstr++)=='\n')
        {
        firstLineMark++;
        n++;
        }
      if(firstLineMark==0)
        {
        firstLineCount++;
        }
        headCount++;
      
      }
      
      StrLen = StrLen-headCount;
      fit(readstr,13);
      if(strcmp(readstr,ACHEAD)!=0)
  {
  printf("<SCRIPT language=JavaScript>alert('文件不正确!');javascript:history.go(-1)</SCRIPT>");
  
  return 0;
  }
      FILE *fp;
      if((fp=fopen(AC483PATH,"wb"))==NULL)
      {
        printf("error open file\n");
        return 0;
      }
      fwrite(readstr+13,StrLen-13-firstLineCount-5,1,fp);
      fclose(fp);
      printf("<SCRIPT language=JavaScript>alert('恭喜升级成功!');javascript:history.go(-1)</SCRIPT>");
      // printf("恭喜升级成功!");
    
    
    } 
    return   0; 
}   
void fit(char *string,unsigned size)
{
if(strlen(string)>size)
*(string+size)='\0';
}

打开一个文件,上传到服务器指定的文件中.适用于一些软件在线更新.文字!
CGI中文件无法上传
在调试cgictest.cgi过程中,发现文件无法上传,提示“No file was uploaded.”。
原因有两点:
1、boa的用户权限不够,无法建立临时文件。改为root用户启动
2、cgi是以GET形式发送表格的。改为POST形式。

更多参考:
http://hi.baidu.com/andforce/item/787a822953d87bc9dcf69ac3
http://wenku.baidu.com/view/35fc800b52ea551810a687ed.html
http://blog.csdn.net/xyj0663/article/details/4666146

上一篇: 利用php调用C语言 扩展PHP的功能

下一篇: C语言CGI编程入门