分享

[作为备案]用c语言写cgi程序实现文件上传

 SamBookshelf 2016-02-19
    背景:现在很少有用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
  1. <HTML>  
  2. <HEAD>  
  3. <TITLE>上传数据文件</TITLE>  
  4. <META HTTP-EQUIV="CONTENT-TYPE" CONTENT="TEXT/HTML;CHARSER=UTF-8">  
  5. <link rel="stylesheet" type="text/css" href="css/main.css">  
  6. <script type="text/javascript">  
  7. function upload_file(){  
  8. if( document.getElementById('FILE1').value == '' ){  
  9. alert("请选择文件!");  
  10. return false;  
  11. }  
  12.   
  13. document.getElementById('uploadInfo').innerHTML = '' ;  
  14. document.getElementById('uploadInfo').innerHTML = '<img src="images/wait.gif"><br>数据上传中,请稍候……' ;  
  15.   
  16. document.getElementById('form1').submit();  
  17. }  
  18. </script>   
  19. </HEAD>  
  20. <BODY BGCOLOR="#FFFFFF">  
  21. <FORM METHOD="POST" id="form1" name="form1" ENCTYPE="multipart/form-data" ACTION="cgi-bin/uploadcgi.cgi">  
  22. 选择文件:<INPUT TYPE="FILE" NAME="FILE1" id="FILE1" class="btn"><INPUT TYPE="button" onclick="upload_file()" VALUE="上传" class="btn"><br>  
  23. <center>  
  24. <div id="uploadInfo"></div>  
  25. </center>  
  26. </FORM>  
  27. </BODY>  
  28. </HTML>  


#############################
uploadcgi.c

  1. /************************************************************************** 
  2. 2007-1-5 11:42 establish by lzh.A cgi program. 
  3. get a file from user's explorer. 
  4. ***************************************************************************/  
  5. #include <stdio.h>  
  6. #include <stdlib.h>  
  7. #include <string.h>  
  8.   
  9. #define DEAL_BUF_LEN 1024  
  10. #define SIGN_CODE_LEN 100  
  11. #define FILE_NAME_LEN 64  
  12. #define FILE_SAVE_DIR "/var/landog/db_upload/"  
  13.   
  14. enum  
  15. {  
  16. STATE_START,  
  17. STATE_GET_SIGN_CODE,  
  18. STATE_GET_FILE_NAME,  
  19. STATE_GET_FILE_START,  
  20. STATE_GET_FILE_CONTENT,  
  21. STATE_CHECK_END,  
  22. STATE_END  
  23. };  
  24. /*************************************************************************** 
  25. ShowErrorInfo 
  26. ****************************************************************************/  
  27. static void ShowErrorInfo(char * error)  
  28. {  
  29.   
  30. printf("Content-Type:text/html;charset=UTF-8\n\n");  
  31. printf("<center><font color='red'>%s</font></center>" , error );  
  32. }  
  33.   
  34. /* 主体从这里开始 */  
  35.   
  36. int main(void)  
  37. {  
  38. FILE *fp; /* 文件指针,保存我们要获得的文件 */  
  39. int getState = STATE_START;  
  40. int contentLength;/*标准输入内容长度*/  
  41. int nowReadLen;  
  42. int signCodeLen;  
  43. int tmpLen;  
  44. char *nowReadP;  
  45. char *nowWriteP;  
  46. char dealBuf[DEAL_BUF_LEN];  
  47. char signCode[SIGN_CODE_LEN]; /*存储本次的特征码*/  
  48. char tmpSignCode[SIGN_CODE_LEN];  
  49. char fileName[FILE_NAME_LEN];  
  50. memset(dealBuf,0,DEAL_BUF_LEN);  
  51. memset(signCode,0,SIGN_CODE_LEN);  
  52. memset(fileName,0,FILE_NAME_LEN);  
  53. nowReadLen = 0;  
  54. if((char *)getenv("CONTENT_LENGTH")!=NULL)  
  55. {  
  56. contentLength = atoi((char *)getenv("CONTENT_LENGTH"));  
  57. }  
  58. else  
  59. {  
  60. ShowErrorInfo("没有恢复数据!");  
  61. exit(1);  
  62. }  
  63.   
  64. while(contentLength > 0)  
  65. {  
  66. if(contentLength >= DEAL_BUF_LEN)  
  67. {  
  68. nowReadLen = DEAL_BUF_LEN;  
  69. }  
  70. else  
  71. {  
  72. nowReadLen = contentLength;  
  73. }  
  74. contentLength -= nowReadLen;  
  75. if(fread(dealBuf,sizeof(char),nowReadLen,stdin) != nowReadLen)  
  76. {  
  77. ShowErrorInfo("读取恢复数据失败,请重试!");  
  78. exit(1);  
  79. }  
  80. nowReadP = dealBuf;  
  81. while(nowReadLen > 0)  
  82. {  
  83. switch (getState)  
  84. {  
  85. case STATE_START:  
  86. nowWriteP = signCode;  
  87. getState = STATE_GET_SIGN_CODE;  
  88. case STATE_GET_SIGN_CODE:  
  89. if(strncmp(nowReadP,"\r\n",2) == 0)  
  90. {  
  91. signCodeLen = nowWriteP - signCode;  
  92. nowReadP++;  
  93. nowReadLen--;  
  94. *nowWriteP = 0;  
  95. getState = STATE_GET_FILE_NAME;  
  96. //ShowErrorInfo(signCode);  
  97. }  
  98. else  
  99. {  
  100. *nowWriteP = *nowReadP;  
  101. nowWriteP++;  
  102. }  
  103. break;  
  104. case STATE_GET_FILE_NAME:  
  105. if(strncmp(nowReadP,"filename=",strlen("filename=")) == 0)  
  106. {  
  107. nowReadP += strlen("filename=");  
  108. nowReadLen -= strlen("filename=");  
  109. nowWriteP = fileName + strlen(FILE_SAVE_DIR);  
  110. while(*nowReadP != '\r') 
  111. if(*nowReadP == '\\' || *nowReadP == '/') 
  112. nowWriteP = fileName + strlen(FILE_SAVE_DIR); 
  113. else if(*nowReadP != '\"') 
  114. *nowWriteP = *nowReadP; 
  115. nowWriteP++; 
  116. nowReadP++; 
  117. nowReadLen--; 
  118. *nowWriteP = 0; 
  119. nowReadP++; 
  120. nowReadLen--; 
  121. getState = STATE_GET_FILE_START; 
  122. memcpy(fileName,FILE_SAVE_DIR,strlen(FILE_SAVE_DIR)); 
  123. if((fp=fopen(fileName,"w"))==NULL) 
  124. fprintf(stderr,"open file error\n"); 
  125. exit(1); 
  126. //ShowErrorInfo(fileName); 
  127. break; 
  128. case STATE_GET_FILE_START: 
  129. if(strncmp(nowReadP,"\r\n\r\n",4) == 0) 
  130. nowReadP += 3; 
  131. nowReadLen -= 3; 
  132. getState = STATE_GET_FILE_CONTENT; 
  133. //ShowErrorInfo("get"); 
  134. break; 
  135. case STATE_GET_FILE_CONTENT: 
  136. if(*nowReadP != '\r') 
  137. fputc(*nowReadP,fp); 
  138. else 
  139. if(nowReadLen >= (signCodeLen + 2)) 
  140. if(strncmp(nowReadP + 2,signCode,signCodeLen) == 0) 
  141. getState = STATE_END; 
  142. nowReadLen = 1; 
  143. ShowErrorInfo("数据上传成功"); 
  144. /* if( system( "/var/landog/app/sniff/db_recover.sh" ) == 0 ){ 
  145. ShowErrorInfo( "数据库恢复完成,请重新启动landog" );  
  146. }else{ 
  147. ShowErrorInfo( "数据库恢复过程中出现错误,错误原因:恢复的文件已经损坏" ); 
  148. */ 
  149. else 
  150. fputc(*nowReadP,fp); 
  151. else 
  152. getState = STATE_CHECK_END; 
  153. nowWriteP = tmpSignCode; 
  154. *nowWriteP = *nowReadP; 
  155. nowWriteP++; 
  156. tmpLen = 1; 
  157. break; 
  158. case STATE_CHECK_END: 
  159. if(*nowReadP != '\r') 
  160. if(tmpLen < signCodeLen + 2) 
  161. *nowWriteP = *nowReadP; 
  162. nowWriteP++; 
  163. tmpLen++; 
  164. if(tmpLen == signCodeLen + 2) 
  165. *nowWriteP = 0; 
  166. if((tmpSignCode[1] == '\n')&&(strncmp(tmpSignCode + 2,signCode,signCodeLen) == 0)) 
  167. getState = STATE_END; 
  168. nowReadLen = 1; 
  169. ShowErrorInfo("数据上传成功"); 
  170. /* if( system( "/var/landog/app/sniff/db_recover.sh" ) == 0 ){ 
  171. ShowErrorInfo( "数据库恢复完成,请重新启动landog" );  
  172. }else{ 
  173. ShowErrorInfo( "数据库恢复过程中出现错误,错误原因:恢复的文件已经损坏" );  
  174. }  
  175. */  
  176. }  
  177. else  
  178. {  
  179. //fprintf(fp,tmpSignCode);  
  180. fwrite(tmpSignCode,sizeof(char),tmpLen,fp);  
  181. getState = STATE_GET_FILE_CONTENT;  
  182. }  
  183. }  
  184. }  
  185. }  
  186. else  
  187. {  
  188. *nowWriteP = 0;  
  189. //fprintf(fp,tmpSignCode);  
  190. fwrite(tmpSignCode,sizeof(char),tmpLen,fp);  
  191. nowWriteP = tmpSignCode;  
  192. *nowWriteP = *nowReadP;  
  193. nowWriteP++;  
  194. tmpLen = 1;  
  195. }  
  196. break;  
  197. case STATE_END:  
  198. nowReadLen = 1;  
  199. break;  
  200. default:break;  
  201. }  
  202. nowReadLen--;  
  203. nowReadP++;  
  204. }  
  205. }  
  206. if(fp != NULL)  
  207. {  
  208. fclose(fp);  
  209. }  
  210. return 0;  
  211. }  


=========================================================================
另一个写在一个文件里的CGI文件上传方式,[备注:]C语言-cgi文件上传代码,它通过 getenv("CONTENT_LENGTH") 之后可以直接对stdin使用fread() 但是在实际应用时发现,有时候文件读不全 ,注意要使用二进制模式来读取,而不是文本模式:
  1. #include   <stdio.h>   
  2. #include   <stdlib.h>   
  3. #include   <string.h>   
  4. #include   <ctype.h>   
  5. #include   <fcntl.h>   
  6. #define   ACHEAD "ooooooooooooo"  
  7. #define AC483PATH "../htdocs/ac483/ac483_bak"  
  8. void fit(char *,unsigned size);  
  9.   
  10. int   main(int   argc,   char   *argv[])   
  11. {   
  12.     printf("Content-Type:text/html\n\n");       
  13.     char   *pMethod   =   getenv("REQUEST_METHOD");  
  14.     //printf("pMethod=%s\n",pMethod);   
  15.     if(pMethod   ==   NULL   ||   *pMethod   ==   0)   
  16.     {   
  17.       printf("No   Any   Method!\n");   
  18.       return   0;   
  19.     }   
  20.     
  21.     if(strcmp(pMethod,   "GET")   ==   0)   
  22.       return   1;   
  23.     
  24.     if(strcmp(pMethod,   "POST")   ==   0)   
  25.     {   
  26.       char   *pCntLen   =   getenv("CONTENT_LENGTH");   
  27.       //printf("pCntLen=%s\n",pCntLen);  
  28.       if(!pCntLen)   
  29.       {   
  30.         printf("Can't   get   Content_Length!\n");   
  31.         return   0;   
  32.       }   
  33.       if(*pCntLen   ==   0)   
  34.       {   
  35.         printf("Can't   get   Content_Length!\n");   
  36.         return   0;   
  37.       }   
  38.       int   StrLen   =   atoi(pCntLen);  
  39.       // printf("StrLen=%d\n",StrLen);   
  40.       if(StrLen   <=   0)   
  41.       {   
  42.         printf("String   Length   <=   0\n");   
  43.         return   0;   
  44.       }   
  45.       //char *ph = getenv("CONTENT_TYPE");  
  46.       //printf("ph=%s\n",ph);  
  47.         
  48.       char *readstr=(char   *)malloc(StrLen+1);  
  49.       fread(readstr,StrLen,1,stdin);  
  50.       // printf("readstr=%s\n",readstr);  
  51.       int n=0;  
  52.       int firstLineMark=0;  
  53.       int firstLineCount=0;  
  54.       int headCount=0;  
  55.       while(n<4)  
  56.       {  
  57.       if(*(readstr++)=='\n')  
  58.         {  
  59.         firstLineMark++;  
  60.         n++;  
  61.         }  
  62.       if(firstLineMark==0)  
  63.         {  
  64.         firstLineCount++;  
  65.         }  
  66.         headCount++;  
  67.         
  68.       }  
  69.         
  70.       StrLen = StrLen-headCount;  
  71.       fit(readstr,13);  
  72.       if(strcmp(readstr,ACHEAD)!=0)  
  73.   {  
  74.   printf("<SCRIPT language=JavaScript>alert('文件不正确!');javascript:history.go(-1)</SCRIPT>");  
  75.     
  76.   return 0;  
  77.   }  
  78.       FILE *fp;  
  79.       if((fp=fopen(AC483PATH,"wb"))==NULL)  
  80.       {  
  81.         printf("error open file\n");  
  82.         return 0;  
  83.       }  
  84.       fwrite(readstr+13,StrLen-13-firstLineCount-5,1,fp);  
  85.       fclose(fp);  
  86.       printf("<SCRIPT language=JavaScript>alert('恭喜升级成功!');javascript:history.go(-1)</SCRIPT>");  
  87.       // printf("恭喜升级成功!");  
  88.       
  89.       
  90.     }   
  91.     return   0;   
  92. }     
  93. void fit(char *string,unsigned size)  
  94. {  
  95. if(strlen(string)>size)  
  96. *(string+size)='\0';  
  97. }  

打开一个文件,上传到服务器指定的文件中.适用于一些软件在线更新.文字!
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

作者:justwinit@向东博客 专注WEB应用 构架之美 --- 构架之美,在于尽态极妍 | 应用之美,在于药到病除
地址:http:///post/6314/
版权所有。转载时必须以链接形式注明作者和原始出处及本声明!

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多