1. 程式人生 > >C語言CGI程式--POST表單/GET表單處理

C語言CGI程式--POST表單/GET表單處理

#include <stdio.h>
#include <stdlib.h>
#define MAXLEN 80
#define EXTRA 5
/*   4個位元組給欄位"data",   1個位元組留給"="   */
#define MAXINPUT MAXLEN+EXTRA+2
/*   1個位元組留給換行符,還有一個留給後面的NULL   */
#define DATAFILE "../data/data.txt"
/*   要被新增資料的檔案   */
void unencode(char *src, char *last, char *dest)
{
 for(; src != last; src++, dest++)
   if(*src == '+')
     *dest = ' ';
   else if(*src == '%') {
     int code;
     if(sscanf(src+1, "%2x", &code) != 1) code = '?';
     *dest = code;
     src +=2; }     
   else
     *dest = *src;
 *dest = '\n';
 *++dest = '\0';
}
int main(void)
{
char *lenstr;
char input[MAXINPUT], data[MAXINPUT];
long len;
printf("%s%c%c\n",
"Content-Type:text/html;charset=GB2312",13,10);
printf("<TITLE>Response</TITLE>\n");
lenstr = getenv("CONTENT_LENGTH");
if(lenstr == NULL || sscanf(lenstr,"%ld",&len)!=1 || len > MAXLEN)
  printf("<P>表單提交錯誤.");
else {
  FILE *f;
  fgets(input, len+1, stdin);
  unencode(input+EXTRA, input+len, data);
  f = fopen(DATAFILE, "a");
  if(f == NULL)
    printf("<P>對不起,意外錯誤,不能夠儲存你的資料.");
  else
    fputs(data, f);
  fclose(f);
  printf("<P>非常感謝,您的資料已經被儲存!<BR>%s",data);
  }
return 0;
}
      從本質上來看,程式先從CONTENT_LENGTH環境變數中得到資料的字長,然後讀取相應長度的字串。因為資料內容在傳輸的過程中是經過了編碼的,所以必須進行相應的解碼。編碼的規則很簡單,主要的有這幾條:     

1.   表單中每個每個欄位用欄位名後跟等號,再接上上這個欄位的值來表示,每個欄位之間的內容用&連結;

2.   所有的空格符號用加號代替,所以在編碼碼段中出現空格是非法的;     
       3.   特殊的字元比如標點符號,和一些有特定意義的字元如“+”,用百分號後跟其對應的ACSII碼值來表示。     

例如:如果使用者輸入的是:     
                 Hello   there!     
那麼資料傳送到伺服器的時候經過編碼,就變成了data=Hello+there%21   上面的unencode()函式就是用來把編碼後的資料進行解碼的。在解碼完成後,資料被新增到data.txt檔案的尾部,並在瀏覽其中回顯出來。     
把檔案編譯完成後,把它改名為mult.cgi後放在CGI目錄中就可以被表單呼叫了。

gcc -o mult.cgi mult.c

下面給出了其相應的html表單:     

<form action="/cgi-bin/mult.cgi" method="post">
<div>
請輸入您的留言(最多80個字元
):<br>
<input name="data" size="60" maxlength="80"><br>
<input type="submit" value="Send"></div>
</form>

注意:  ../data/data.txt的檔案應該提前建立,而且檔案屬性應該為666.

chmod 666 ../data/data.txt    
    
       事實上,這個程式只能作為例子,是不能夠正式的使用的。它漏掉了很關鍵的一個問題:當有多個使用者同時像檔案寫入資料是,肯定會有錯誤發生。而對於一個這樣的程式而言,檔案被同時寫入的機率是很大的。因此,在比較正式的留言版程式中,都需要做一些更多的考慮,比如加入一個訊號量,或者是藉助於一個鑰匙檔案等。因為那只是程式設計的技巧問題,在這兒就不多說了。

下面是僅檢視檔案../data/data.txt的C原始碼:

#include <stdio.h>
#include <stdlib.h>
#define DATAFILE "../data/data.txt"
int main(void)
{
FILE *f = fopen(DATAFILE,"r");
int ch;
if(f == NULL) {
  printf("%s%c%c\n",
  "Content-Type:text/html;charset=iso-8859-1",13,10);
  printf("<TITLE>Failure</TITLE>\n");
  printf("<P><EM>Unable to open data file, sorry!</EM>"); }
else {
  printf("%s%c%c\n",
  "Content-Type:text/plain;charset=iso-8859-1",13,10);
  while((ch=getc(f)) != EOF)
    putchar(ch);
  fclose(f); }
return 0;
}
相應的html表單:
<form action="/cgi-bin/viewdata.cgi">
<div><input type="submit" value="View"></div>
</form>
-----------------------------------------------
附:get方式分離表單m和表單n的資料。
#include <stdio.h>
#include <stdlib.h>
main()
{
char *qa;
int m1,n1;
printf("%s%c%c\n","Content-Type:text/html;charset=GB2312",13,10);
printf("<TITLE>表單內容返回</TITLE>\n");
qa = getenv ("QUERY_STRING");
sscanf(qa,"m=%d&n=%d",&m1,&n1);
printf("%d,%d",m1,n1);
return 0;
}
附2:post方式獲取表單m和表單n的資料。
#include <stdio.h>
#include <stdlib.h>
#define MAXLEN 80
#define EXTRA 5
/*   4個位元組給欄位"data",   1個位元組留給"="   */
#define MAXINPUT MAXLEN+EXTRA+2
/*   1個位元組留給換行符,還有一個留給後面的NULL   */
//#define DATAFILE "./haha.sh"
/*   要被新增資料的檔案   */
int main(void)
{
long len;
char *lenstr,poststr[20];
char m[10],n[10];
printf("%s%c%c\n","Content-Type:text/html;charset=GB2312",13,10);
printf("<TITLE>我的cgi返回結果</TITLE>\n");
lenstr = getenv("CONTENT_LENGTH");
//if(lenstr == NULL || len > MAXLEN)
if(lenstr == NULL)
  printf("<P>表單提交錯誤.");
else{
len = atoi(lenstr);
fgets(poststr,len+1,stdin);
if (sscanf(poststr,"m=%[^&]&n=%s",m,n)!=1)
{printf("m=%s,n=%s\n",m,n);}
printf("<input type=\"button\" value=\"Back CGI\" onclick=\"javascript:window
.location='../../ip.html'\">");}
return 0;
}