天天看點

CGI接口原理及實作

CGI接口原理及實作(2012-12-7 Over)

1.CGI定義:

CGI(CommonGateway Interface)是HTTP伺服器與你的或其它機器上的程式進行“交談”的一種工具,其程式須運作在網絡伺服器上。

2.CGI功能:

絕大多數的CGI程式被用來解釋處理來自表單的輸入資訊,并在伺服器産生相應的處理,或将相應的資訊回報給浏覽器。CGI程式使**網頁具有互動功能。

3.CGI運作環境:

CGI程式在UNIX作業系統上CERN或NCSA格式的伺服器上運作。 在其它作業系統(如:windows NT及windows95等)的伺服器上 也廣泛地使用CGI程式,同時它也适用于各種類型機器。

4.CGI處理步驟:

⑴通過Internet把使用者請求送到伺服器。

⑵伺服器接收使用者請求并交給CGI程式處理。

⑶CGI程式把處理結果傳送給伺服器。

⑷伺服器把結果送回到使用者。

5.CGI伺服器配置:

在許多伺服器cgi-bin是僅能夠放置CGI腳本的目錄。

在Windows平台上将C或C++寫好的程式的Debug或Release版本的.exe程式拷貝到cgi-bin的目錄下(如上圖所示),将.exe改為.cgi也可同樣運作,如下2個圖。

CGI接口原理及實作

cgi-bin目錄是存放CGI腳本的地方。這些腳本使WWW伺服器和浏覽器能運作外部程式,而無需啟動另一個程式。它是運作在Web伺服器上的一個程式,并由來自于浏覽者的輸入觸發。

CGI程式不是放在伺服器上就能順利運作,如果要想使其在伺服器上順利的運作并準确的處理使用者的請求,則須對所使用的伺服器進行必要的設定。

配置:根據所使用的伺服器類型以及它的設定把CGI程式放在某一特定的目錄中或使其帶有特定的擴充名。

Apache網絡伺服器配置在/var/www/cgi-bin裡(如下圖所示筆者電腦的目錄位置)。C++編譯的可執行檔案可以轉換成擴充名為.cgi的檔案。

更改初始配置的的方法:

<Directory"/var/www/cgi-bin">

   AllowOverride None

   Options ExecCGI

   Order allow,deny

   Allow from all

</Directory>

<Directory"/var/www/cgi-bin">

           Options All

</Directory>           
CGI接口原理及實作

6.CGI接口标準包括标準輸入、環境變量、标準輸出三部分。

介紹
1.标準輸入 CGI程式像其他可執行程式一樣,可通過标準輸入(stdin)從Web伺服器得到輸入資訊,如Form中的資料,這就是所謂的向CGI程式傳遞資料的POST方法。這意味着在作業系統指令行狀态可執行CGI程式,對CGI程式進行調試。POST方法是常用的方法。
2.環境變量 作系統提供了許多環境變量,它們定義了程式的執行環境,應用程式可以存取它們。Web伺服器和CGI接口又另外設定了自己的一些環境變量,用來向CGI程式傳遞一些重要的參數。CGI的GET方法還通過環境變量QUERY-STRING向CGI程式傳遞Form中的資料。
3.标準輸出 CGI程式通過标準輸出(stdout)将輸出資訊傳送給Web伺服器。傳送給Web伺服器的資訊可以用各種格式,通常是以純文字或者HTML文本的形式,這樣我們就可以在指令行狀态調試CGI程式,并且得到它們的輸出。

7.環境變量

環境變量是文本串(名字/值對),可以被OSShell或其他程式設定 ,也可以被其他程式通路。它們是Web伺服器傳遞資料給CGI程式的簡單手段,之是以稱為環境變量是因為它們是全局變量,任何程式都可以存取它們。

下面是CGI程式設計中常常要用到的一些環境變量。

環境變量 意義
SERVER_NAME CGI腳本運作時的主機名和IP位址.
SERVER_SOFTWARE 你的伺服器的類型如: CERN/3.0 或 NCSA/1.3.
GATEWAY_INTERFACE 運作的CGI版本. 對于UNIX伺服器, 這是CGI/1.1.
SERVER_PROTOCOL 伺服器運作的HTTP協定. 這裡當是HTTP/1.0.
SERVER_PORT 伺服器運作的TCP口,通常Web伺服器是80.
REQUEST_METHOD POST 或 GET, 取決于你的表單是怎樣遞交的.
HTTP_ACCEPT 浏覽器能直接接收的Content-types, 可以有HTTP Accept header定義.
HTTP_USER_AGENT 遞交表單的浏覽器的名稱、版本 和其他平台性的附加資訊。
HTTP_REFERER 遞交表單的文本的 URL,不是所有的浏覽器都發出這個資訊,不要依賴它
PATH_INFO 附加的路徑資訊, 由浏覽器通過GET方法發出.
PATH_TRANSLATED 在PATH_INFO中系統規定的路徑資訊.
SCRIPT_NAME 指向這個CGI腳本的路徑, 是在URL中顯示的(如, /cgi-bin/thescript).
QUERY_STRING 腳本參數或者表單輸入項(如果是用GET遞交). QUERY_STRING包含URL中問号後面的參數.
REMOTE_HOST 遞交腳本的主機名,這個值不能被設定.
REMOTE_ADDR 遞交腳本的主機IP位址.
REMOTE_USER 遞交腳本的使用者名. 如果伺服器的authentication被激活,這個值可以設定。
REMOTE_IDENT 如果Web伺服器是在ident (一種确認使用者連接配接你的協定)運作, 遞交表單的系統也在運作ident, 這個變量就含有ident傳回值.
CONTENT_TYPE 如果表單是用POST遞交, 這個值将application/x-www-form-urlencoded. 在上載檔案的表單中, content-type 是個 multipart/form-data.
CONTENT_LENGTH 對于用POST遞交的表單,标準輸入口的位元組數.

REQUEST-METHOD:指的是當Web伺服器傳遞資料給CGI程式時所采用的方法,分為GET和POST兩種方法。

【GET和POST方法的差別】:GET方法僅通過環境變量(如QUERY-STRING)傳遞資料給CGI程式,而POST方法通過環境變量和标準輸入傳遞資料給CGI程式,是以POST方法可較友善地傳遞較多的資料給CGI程式。

問題
GET方法 通過在URL中嵌入的形式傳遞參數。對CGI程式而言,在GET method中傳遞的參數要通過化境變量“QUERY-STRING”來接收。 1) 參數的内容作為URL資訊,使用者可以看到;2) 有大小的限制
POST方法 CGI程式從标準輸入接收參數。與GET方法不同的是,參數的内容從URL資訊中不能獲得,對于大小也沒有限制。 與GET方法問題1),2)完全相反。

CONTENT-LENGTH:傳遞給CGI程式的資料字元數(位元組數)。

在C語言程式中,要訪向環境變量,可使用getenv()庫函數。例如:

if (getenv (″CONTENT-LENGTH″))n=atoi(getenv(″CONTENT-LENGTH″));           

請注意程式中最好調用兩次getenv():第一次檢查是否存在該環境變量,第二次再使用該環境變量。這是因為函數getenv()在給定的環境變量名不存在時,傳回一個NULL(空)指針,如果你不首先檢查而直接引用它,當該環境變量不存在時會引起CGI程式崩潰。

8. CGI的工作原理

CGI是一個WEB伺服器提供資訊服務的标準接口,通過這樣一個接口,WEB伺服器能夠執行程式,并将程式輸出的資訊傳回給浏覽器。因為在WEB網上的資料都是靜态的,通過CGI程式能夠動态的處理浏覽者的請求,如儲存使用者輸入的資訊,根據使用者資訊傳回相關的資料等等。當用戶端發送一個CGI請求給WEB伺服器後,WEB伺服器将根據CGI程式的類型決定資料向CGI程式的傳送方式,一般來講是通過标準輸入/輸出流和環境變量來與CGI程式間傳遞資料。

CGI接口原理及實作

CGI輸入輸出原理

CGI的輸入/輸出方法:CGI程式通過标準輸入(STDIN)和标準輸出(STDOUT)來進行輸入輸出,STDIN和STDOUT是兩個預先定義好的檔案指針。你可以利用檔案讀寫函數來對其進行操縱。

此外CGI程式還通過環境變量來得到輸入,隻不過環境變量中提供的是一些常用的資訊,并且通常不包括使用者在WEB頁面中輸入的資訊(除使用下面講的GET方法時,通過檢查環境變量QUERY_STRING來得到輸入資料),而STDIN通常用來傳遞使用者輸入的資訊。

在輸入時所使用的POST/GET方法:在WEB頁面向CGI發送資料時通常采用兩種方法:GET/POST,GET方法将資料附加在URL後發送,如:/cgi/a_cgi_test.exe?your_data,CGI程式通過檢查環境變量QUERY_STRING來得到輸入資料。

示例一、下圖即是GET方法!

CGI接口原理及實作

上圖的對應程式為:

//2012-12-5 GET c程式示例..

void main(void)
{// 本程式将使用者輸入的資料列印出來
       fprintf(stdout,"content-type:text/plain\n\n");
       // 輸出一個CGI标題,這行代碼的意義後面會講解
      
       char *pszMethod;
       pszMethod =getenv("REQUEST_METHOD");
       if(strcmp(pszMethod,"GET") == 0)
       {     //GET method
              //讀取環境變量來擷取資料
              printf("This is GETMETHOD!\n");
              printf("SERVER_NAME:%s\n",getenv("SERVER_NAME"));
              printf("REMOTE_ADDR:%s\n",getenv("REMOTE_ADDR"));
              fprintf(stdout,"input data is:%s\n",getenv("QUERY_STRING"));
       }
       else
       {  // POST method
              //讀取STDIN來擷取資料
              intiLength=atoi(getenv("CONTENT_LENGTH"));
                     printf("This is POSTMETHOD!\n");
 
              fprintf(stdout,"input data is:\n");
              for(int i=0;i<iLength;i++)
              {
                     char cGet=fgetc(stdin);
                     fputc(cGet,stdout);
              }
       }
}           

示例二、下圖即是POST程式示例:

CGI接口原理及實作
CGI接口原理及實作
CGI接口原理及實作
void unencode(char *src, char *last, char *dest)
{
  // str = hello+there%21 此處跳過data=... 
  // last = ; 已到末尾.
  // dest= ; 空串.
 
   //解碼原則
   //原則1: '+'變' ';
   //原則2: '%xx'變成對應的16進制ASCII碼值;
   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';
}
 
intmain(void)
{
       char *lenstr;
       char input[MAXINPUT], data[MAXINPUT];
       long len;
       printf("%s%c%c\n","Content-Type:text/html;charset=iso-8859-1",13,10);
       printf("<TITLE>Response</TITLE>\n");
      
       lenstr =getenv("CONTENT_LENGTH");
       printf("CONTENT_LENGTH =%s\n",lenstr);
      
       if(lenstr == NULL ||sscanf(lenstr,"%ld",&len)!=1 || len > MAXLEN)
       {
              printf("<P>Error ininvocation - wrong FORM probably.");
       }
       else
       {
              FILE *f;
              fgets(input, len+1, stdin);           //add by ycy從輸入流中擷取字元串.
              unencode(input+EXTRA, input+len,data);
             
              f = fopen(DATAFILE,"a");
              if(f == NULL)
              {
                     printf("<P>Sorry,cannot store your data.");
              }
              else
              {
                     fputs(data, f); //add byycy 将資料存儲在對對應的檔案中.
              }
              fclose(f);
              printf("<P>Thank you!Your contribution has been stored.");
       }
      
       return 0;
}           

請求過程即是:

(1)send發送按鈕--->(2)調用post.cgi--->(3)将資料存儲在datadata.txt裡面。

示例三、下圖即是GET/POST程式示例。

綜合執行個體:在上面兩個程式上的擴充(應用Get方法及QUERY_STRING),

CGI接口原理及實作
CGI接口原理及實作

如上兩圖所示,在表單(cgi接口的表單隻是在html語言的基礎上用C或C++實作的擴充操作而已)的基礎上,送出按鈕對應的另一個CGI接口(6.exe或6.cgi),這樣通過Get方法及QUERY_STRING參量就可以完成輸出操作。

而POST方法則會将資料送入CGI程式的STDIN輸入流。在表單(FORM)中的各個變量都會成為name=value的形式向WEB伺服器發送,多個資料間用&分隔,如:name=value&name2=value2。其中名字(name,name2)是Form中定義的INPUT、SELECT或TEXTAREA等标置(Tag)名字,值是使用者輸入或選擇的标置值。

如上面說講,在CGI程式輸出時必須先輸出一個CGI标題,标題共有以下三類:

  • Location: 标題,指明輸出另一個文檔的URL,例如 fprintf(stdout,"Location: http://www.vchelp.net/ nn");
  • Content-Type: 标題,指明發送的資料的MIME類型,例如 fprintf(stdout,"Content-Type:text/htmlnn");
  • Status: 标題,指明HTTP狀态碼,例如 fprintf(stdout,"Status:200nn");

注意每種标題後都必須跟一個換行和一個空行。

MIME類型以類型/子類型的形式來表示,下面是一些常用的類型/子類型的組合:

·  Text/plain 普通文本類型

·  Text/html HTML格式的文本類型

·  Audio/basic 八位聲音檔案格式,字尾為.au

·  Video/mpeg MPEG檔案格式

·  Video/quicktime QuickTime檔案格式

·  Image/gif GIF圖形檔案

·  Image/jpeg JPEG圖形檔案

·  Image/x-xbitmap X bitmap圖形檔案,字尾為.xbm

有了上面的知識我們就可以寫出一些CGI程式,首先需要對輸入資料進行分析,方法為:每當找到字元=,标志着一個Form變量名字的結束;每當找到字元& ,标志着一個Form變量值的結束。請注意輸入資料的最後一個變量的值不以&結束。這樣我們可以将輸入資料分解為一組一組的值。

但随後會發現CGI的輸入并不規則,例如有時會出現類似下面格式的輸入字元号串:

filename=hello&cmd=world+I%27

,這是因為浏覽器對一些上傳的特殊字元進行了編碼,是以在将資料分解開後需要進行解碼,

解碼規則為:

1)+: 将+轉換成空格符;

2) %xx: 用其十六進制ASCII碼值表示的特殊字元(%作為為轉意符)。根據值xx将其轉換成相應的ASCII字元。對Form變量名和變量值都要進行這種轉換。

作者:銘毅天下

來源:CSDN

原文:

https://blog.csdn.net/laoyang360/article/details/8288619

版權聲明:本文為部落客原創文章,轉載請附上博文連結!

繼續閱讀