C++ web程式設計:寫出你的CGI程式

工程師WWW發表於2014-02-17

一 什麼是CGI

      CGI(The Common Gateway Interface):通用閘道器介面,定義web伺服器和客戶指令碼進行資訊互動的一系列標準

 二 web瀏覽器

         為了瞭解CGI的概念,讓我們來看看當我們單擊一個超連結來瀏覽一個特定的web頁或URL的時候,背後會發生什麼事?

      (1)瀏覽器首先會連結HTTP web 伺服器並且請求一個URL 頁面;

      (2) WEB伺服器將會解析這個URL並且查詢請求的檔名,如果找到了請求檔案伺服器就會將這個檔案傳送回瀏覽器,否則傳送回一個包含錯誤資訊提示的頁面指示你請求的是一個伺服器並不包含的檔案。

      (3)WEB瀏覽器將接受來自伺服器端的響應,並且向發出請求的使用者顯示接收到的檔案。

        然而,HTTP伺服器也可能會以如何這種方式進行配置,那就是無論什麼時候接受到對特定目錄下的檔案的請求,伺服器不會將這個檔案傳送回客戶端,而是它作為一個程式被伺服器執行,併產生出輸出傳送回客戶端瀏覽器進行顯示。

        CGI(The Common Gateway Interface)是一個標準化的協議,能夠使應用程式(通常稱為CGI程式或CGI指令碼)同web伺服器和客戶端進行互動。CGI程式能夠用Python, PERL, Shell, C or C++等語言來實現。

三 CGI程式結構圖

       下圖簡單的展示了CGI程式架構

四 web伺服器配置

        在你著手寫CGI程式之前,確保你的web伺服器支援CGI程式並且配置成處理CGI程式。所有的能夠被HTTP伺服器執行的CGI程式都被存放在預先配置好的目錄下面,這個目錄叫做CGI目錄,並且按照約定命名為 /var/www/cgi-bin,並且約定CGI檔案的字尾名為.cgi ,儘管它們是c++可執行檔案。

      一般的,Apache 伺服器在/var/www/cgi-bin目錄下配置檔案來執行CGI程式,如果你想要宣告另外的目錄來執行CGI指令碼,你需要修改httpd.conf 檔案中的部分內容:

<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指令碼

以下是一段簡短的CGI腳步程式碼

#include <iostream>
using namespace std;
 
int main ()
{
    
   cout << "Content-type:text/html\r\n\r\n";
   cout << "<html>\n";
   cout << "<head>\n";
   cout << "<title>Hello World - First CGI Program</title>\n";
   cout << "</head>\n";
   cout << "<body>\n";
   cout << "<h2>Hello World! This is my first CGI program</h2>\n";
   cout << "</body>\n";
   cout << "</html>\n";
   
   return 0;
}

        編譯上述程式碼並且將二進位制可執行檔案命名為cplusplus.cgi,儲存路徑為/var/www/cgi-bin目錄下,執行chmod 755 cplusplus.cgi 命令使得該檔案為可執行的。現在,如果你點選cplusplus.cgi然後就會產生如下輸出:

Hello World! This is my first CGI program

        上面的C++程式是一個將輸出寫入標準輸出檔案(stdout)的簡單程式。這段程式碼中有一個很重要的一點那就是第一行程式碼:Content-type:text/html\r\n\r\n,這行被髮送回瀏覽器,指明瀏覽器顯示的文字型別。現在你應該瞭解了CGI的基本概念了,你也可以使用python寫出更多複雜的CGI程式,C++ CGI程式能與其他任何外部系統進行資訊互動,例如像RDBMS。

六 HTTP報文頭部

       這行字串” Content-type:text/html\r\n\r\n”是傳送回瀏覽器的HTTP報文頭部的一部分,所有的HTTP報文頭部都有如下格式:

HTTP Field Name: Field Content
 
For Example
Content-type: text/html\r\n\r\n


下表中包含其他一些重要的HTTP報文資訊,這些資訊在CGI程式設計中經常會用到。

Header Description
Content-type: A MIME string defining the format of the file being returned. Example is Content-type:text/html
Expires: Date The date the information becomes invalid. This should be used by the browser to decide when a page needs to be refreshed. A valid date string should be in the format 01 Jan 1998 12:00:00 GMT.
Location: URL The URL that should be returned instead of the URL requested. You can use this filed to redirect a request to any file.
Last-modified: Date The date of last modification of the resource.
Content-length: N The length, in bytes, of the data being returned. The browser uses this value to report the estimated download time for a file.
Set-Cookie: String Set the cookie passed through the string

七 CGI環境變數

所有的CGI程式將會使用到下列的CGI環境變數,這些變數在CGI程式中起著重要的作用。

Variable Name Description
CONTENT_TYPE The data type of the content. Used when the client is sending attached content to the server. For example file upload etc.
CONTENT_LENGTH The length of the query information. It's available only for POST requests
HTTP_COOKIE Return the set cookies in the form of key & value pair.
HTTP_USER_AGENT The User-Agent request-header field contains information about the user agent originating the request. Its name of the web browser.
PATH_INFO The path for the CGI script.
QUERY_STRING The URL-encoded information that is sent with GET method request.
REMOTE_ADDR The IP address of the remote host making the request. This can be useful for logging or for authentication purpose.
REMOTE_HOST The fully qualified name of the host making the request. If this information is not available then REMOTE_ADDR can be used to get IR address.
REQUEST_METHOD The method used to make the request. The most common methods are GET and POST.
SCRIPT_FILENAME The full path to the CGI script.
SCRIPT_NAME The name of the CGI script.
SERVER_NAME The server's hostname or IP Address
SERVER_SOFTWARE The name and version of the software the server is running.

下面這段程式碼列出了所有的CGI變數,點選Get Environment可看結果。

#include <iostream>
using namespace std;

const string ENV[ 24 ] = {                 
        "COMSPEC", "DOCUMENT_ROOT", "GATEWAY_INTERFACE",   
        "HTTP_ACCEPT", "HTTP_ACCEPT_ENCODING",             
        "HTTP_ACCEPT_LANGUAGE", "HTTP_CONNECTION",         
        "HTTP_HOST", "HTTP_USER_AGENT", "PATH",            
        "QUERY_STRING", "REMOTE_ADDR", "REMOTE_PORT",      
        "REQUEST_METHOD", "REQUEST_URI", "SCRIPT_FILENAME",
        "SCRIPT_NAME", "SERVER_ADDR", "SERVER_ADMIN",      
        "SERVER_NAME","SERVER_PORT","SERVER_PROTOCOL",     
        "SERVER_SIGNATURE","SERVER_SOFTWARE" };   

int main ()
{
    
   cout << "Content-type:text/html\r\n\r\n";
   cout << "<html>\n";
   cout << "<head>\n";
   cout << "<title>CGI Envrionment Variables</title>\n";
   cout << "</head>\n";
   cout << "<body>\n";
   cout << "<table border = \"0\" cellspacing = \"2\">";

   for ( int i = 0; i < 24; i++ )
   {
       cout << "<tr><td>" << ENV[ i ] << "</td><td>";
       // attempt to retrieve value of environment variable
       char *value = getenv( ENV[ i ].c_str() );  
       if ( value != 0 ){
         cout << value;                                 
       }else{
         cout << "Environment variable does not exist.";
       }
       cout << "</td></tr>\n";
   }
   cout << "</table><\n";
   cout << "</body>\n";
   cout << "</html>\n";
   
   return 0;
}
 

八 C++CGI庫

在該FTP伺服器上ftp://ftp.gnu.org/gnu/cgicc/ 提供了C++ CGI庫以供下載,我們從上面下載CGI 庫並一下步驟進行安裝:

      $tar xzf cgicc-X.X.X.tar.gz 

$cd cgicc-X.X.X/

$./configure --prefix=/usr

$make

$make install

並且你可以閱讀相關文件。C++ CGI Lib Documentation 。

九 GET 與POST方法

        當你需要從瀏覽器客戶端傳遞資訊至web伺服器端並最終送至CGI程式的時候,你將必然會遇到很多的問題。大部分的瀏覽器使用兩種方法傳送資訊至瀏覽器:GET方法和POST方法,進行過WEB開發的人應該對其很熟悉。

        1. 使用GET方法傳送資訊

       GET方法將編碼過的使用者資訊附加在頁面請求上傳送,頁面請求和這些編碼資訊使用?進行分割,如下所示:

       http://www.test.com/cgi-bin/cpp.cgi?key1=value1&key2=value2

        GET方法是瀏覽器傳送資訊之伺服器端所採用的預設的方法,採用這種方法傳送時,在你的瀏覽器位址列上在URL後面會附加上一串字串,如果你傳輸密碼或其他敏感資訊至伺服器端的時候不要使用GET方法,GET方法有長度限制,在一個請求字串中,最多隻能傳送1024的字元。

當使用GET方法的時候,HTTP報文頭採用QUERY_STRING傳送資訊,並且將通過QUERY_STRING環境變數進入你的CGI程式。

您能夠使用簡單的鍵-值組合附加在URL後傳遞資訊,或者你也可使用HTML中的<FORM>標籤通過使用GET方法來傳遞資訊。

         2. 使用POST方法傳送資訊

        CGI程式中較為通用的且更為可靠地傳遞資訊的方法是POST方法,POST傳遞的報文資訊和GET方法沒什麼兩樣,但是跟GET方法的將字串資訊附加於URL之後並且用?分隔有所區別的是,POST方法使用分離的報文段分別傳送URL和要傳輸的資訊。這些資訊會被CGI指令碼以標準輸入的形式接收。

(注:在原文中作者給出了HTML各種控制元件傳遞資訊給CGI指令碼的例子,有興趣的朋友可以去看看)

十 在CGI中使用Cookies

        伺服器可能會以Cookies的形式傳送資料給客戶端瀏覽器上,瀏覽器也許會接收這些Cookies,並且會以簡單文字的形式儲存在使用者的硬碟上,當使用者訪問該web站點的另外頁面的時候,這些Cookies就會有用處了,伺服器就會據此知道使用者記錄了那些資訊。

        Cookies資訊格式包含如下5個變數:

     (1) Expires:包含Cookies的過期資訊。如果變數值為空,當客戶端關閉瀏覽器時,Cookies就會過期。

    (2)  Domain:web站點的域名資訊。

    (3)  Path:設定Cookies的web頁或目錄的路徑。如果想要從任何頁面或目錄獲取Cookies資訊,此變數設為空值。

    (4)  Secure:如果該欄位設定為"secure",那麼Cookies將只能被安全伺服器獲取,如果該欄位為空,則沒有該限制。

    (5)  Name=Value:Cookies以鍵-值對的形式設定或獲取。

      1. 設定Cookies

       傳送Cookies資訊至瀏覽器是非常容易的,這些Cookies將會附加在在HTTP報文頭的Content-type域前。假設你想要以Cookies的方式設定UserID和Password,那麼簡單的CGI設定指令碼如下:

      

#include <iostream>
using namespace std;

int main ()
{
 
   cout << "Set-Cookie:UserID=XYZ;\r\n";
   cout << "Set-Cookie:Password=XYZ123;\r\n";
   cout << "Set-Cookie:Domain=www.tutorialspoint.com;\r\n";
   cout << "Set-Cookie:Path=/perl;\n";
   cout << "Content-type:text/html\r\n\r\n";

   cout << "<html>\n";
   cout << "<head>\n";
   cout << "<title>Cookies in CGI</title>\n";
   cout << "</head>\n";
   cout << "<body>\n";

   cout << "Setting cookies" << endl;  
  
   cout << "<br/>\n";
   cout << "</body>\n";
   cout << "</html>\n";
   
   return 0;
}


        從這個例子中你將瞭解怎麼設定Cookies,那就是使用Set-Cookie來設定Cookies。

        設定Cookies屬性的時候,Expires, Domain, and Path是可選的,值得注意的一點是Cookies的設定是在傳送"Content-type:text/html\r\n\r\n”之前。執行/cgi-bin/setcookies.cgi將會在你的電腦上設定Cookies。

2.獲取Cookies

      獲取Cookies也非常簡單,Cookies都儲存在CGI的環境變數HTTP_COOKIE中,並且具有如下的格式:

      key1=value1;key2=value2;key3=value3....

     以下就是一段獲取Cookies的簡短的CGI程式碼:

#include <iostream>
#include <vector>  
#include <string>  
#include <stdio.h>  
#include <stdlib.h> 
	
#include <cgicc/CgiDefs.h> 
#include <cgicc/Cgicc.h> 
#include <cgicc/HTTPHTMLHeader.h> 
#include <cgicc/HTMLClasses.h>

using namespace std;
using namespace cgicc;

int main ()
{
   Cgicc cgi;
   const_cookie_iterator cci;

   cout << "Content-type:text/html\r\n\r\n";
   cout << "<html>\n";
   cout << "<head>\n";
   cout << "<title>Cookies in CGI</title>\n";
   cout << "</head>\n";
   cout << "<body>\n";
   cout << "<table border = \"0\" cellspacing = \"2\">";
   
   // get environment variables
   const CgiEnvironment& env = cgi.getEnvironment();

   for( cci = env.getCookieList().begin();
        cci != env.getCookieList().end(); 
        ++cci )
   {
      cout << "<tr><td>" << cci->getName() << "</td><td>";
      cout << cci->getValue();                                 
      cout << "</td></tr>\n";
   }
   cout << "</table><\n";
  
   cout << "<br/>\n";
   cout << "</body>\n";
   cout << "</html>\n";
   
   return 0;
}

點選/cgi-bin/getcookies.cgi看看效果,將會顯示出之前設定過的Cookies。

 譯自:http://www.tutorialspoint.com/cplusplus/cpp_web_programming.htm (部分略去未譯)。

相關文章