天天看點

Perl CGI程式設計

什麼是CGI

CGI 目前由NCSA維護,NCSA定義CGI如下:

CGI(Common Gateway Interface),通用網關接口,它是一段程式,運作在伺服器上如:HTTP伺服器,提供同用戶端HTML頁面的接口。

網頁浏覽

為了更好的了解CGI是如何工作的,我們可以從在網頁上點選一個連結或URL的流程:

  • 1、使用你的浏覽器通路URL并連接配接到HTTP web 伺服器。
  • 2、Web伺服器接收到請求資訊後會解析URL,并查找通路的檔案在伺服器上是否存在,如果存在傳回檔案的内容,否則傳回錯誤資訊。
  • 3、浏覽器從伺服器上接收資訊,并顯示接收的檔案或者錯誤資訊。

CGI程式可以是Python腳本,PERL腳本,SHELL腳本,C或者C++程式等。

CGI架構圖

Perl CGI程式設計

Web伺服器支援及配置

在你進行CGI程式設計前,確定您的Web伺服器支援CGI及已經配置了CGI的處理程式。

Apache 支援CGI 配置:

設定好CGI目錄:

ScriptAlias /cgi-bin/ /var/www/cgi-bin/
      

所有的HTTP伺服器執行CGI程式都儲存在一個預先配置的目錄。這個目錄被稱為CGI目錄,并按照慣例,它被命名為/var/www/cgi-bin目錄。

CGI檔案的擴充名為.cgi,Perl 也可以使用.pl擴充名。

預設情況下,Linux伺服器配置運作的cgi-bin目錄中為/var/www。

如果你想指定其他運作CGI腳本的目錄,可以修改httpd.conf配置檔案,如下所示:

<Directory "/var/www/cgi-bin">
   AllowOverride None
   Options +ExecCGI
   Order allow,deny
   Allow from all
</Directory>
      

在 AddHandler 中添加 .pl 字尾,這樣我們就可以通路 .pl 結尾的 Perl 腳本檔案:

AddHandler cgi-script .cgi .pl .py      

第一個 CGI 程式

以下我們建立一個 test.cgi 檔案,代碼如下所示:

test.cgi 代碼

#!/usr/bin/perl

print "Content-type:text/html\r\n\r\n";

print '<html>';

print '<head>';

print '<meta charset="utf-8">';

print '<title>菜鳥教程(runoob.com)</title>';

print '</head>';

print '<body>';

print '<h2>Hello Word! </h2>';

print '<p>來自菜鳥教程第一個 CGI 程式。</p>';

print '</body>';

print '</html>';

1;

然後通過浏覽器打開 http://localhost/cgi-bin/test.cgi,輸出結果如下:

Perl CGI程式設計

腳本第一行的輸出内容"Content-type:text/html\r\n\r\n"發送到浏覽器并告知浏覽器顯示的内容類型為"text/html"。

HTTP頭部

test.cgi檔案内容中的" Content-type:text/html"即為HTTP頭部的一部分,它會發送給浏覽器告訴浏覽器檔案的内容類型。

HTTP頭部的格式如下:

HTTP 字段名: 字段内容
      

例如:

Content-type:text/html\r\n\r\n      

以下表格介紹了CGI程式中HTTP頭部經常使用的資訊:

描述
Content-type: 請求的與實體對應的MIME資訊。例如: Content-type:text/html
Expires: Date 響應過期的日期和時間
Location: URL 用來重定向接收方到非請求URL的位置來完成請求或辨別新的資源
Last-modified: Date 請求資源的最後修改時間
Content-length: N 請求的内容長度
Set-Cookie: String 設定Http Cookie

CGI環境變量

所有的CGI程式都接收以下的環境變量,這些變量在CGI程式中發揮了重要的作用:

變量名
CONTENT_TYPE 這個環境變量的值訓示所傳遞來的資訊的MIME類型。目前,環境變量CONTENT_TYPE一般都是:application/x-www-form-urlencoded,他表示資料來自于HTML表單。
CONTENT_LENGTH 如果伺服器與CGI程式資訊的傳遞方式是POST,這個環境變量即使從标準輸入STDIN中可以讀到的有效資料的位元組數。這個環境變量在讀取所輸入的資料時必須使用。
HTTP_COOKIE 客戶機内的 COOKIE 内容。
HTTP_USER_AGENT 提供包含了版本數或其他專有資料的客戶浏覽器資訊。
PATH_INFO 這個環境變量的值表示緊接在CGI程式名之後的其他路徑資訊。它常常作為CGI程式的參數出現。
QUERY_STRING 如果伺服器與CGI程式資訊的傳遞方式是GET,這個環境變量的值即使所傳遞的資訊。這個資訊經跟在CGI程式名的後面,兩者中間用一個問号'?'分隔。
REMOTE_ADDR 這個環境變量的值是發送請求的客戶機的IP位址,例如上面的192.168.1.67。這個值總是存在的。而且它是Web客戶機需要提供給Web伺服器的唯一辨別,可以在CGI程式中用它來區分不同的Web客戶機。
REMOTE_HOST 這個環境變量的值包含發送CGI請求的客戶機的主機名。如果不支援你想查詢,則無需定義此環境變量。
REQUEST_METHOD 提供腳本被調用的方法。對于使用 HTTP/1.0 協定的腳本,僅 GET 和 POST 有意義。
SCRIPT_FILENAME CGI腳本的完整路徑
SCRIPT_NAME CGI腳本的的名稱
SERVER_NAME 這是你的 WEB 伺服器的主機名、别名或IP位址。
SERVER_SOFTWARE 這個環境變量的值包含了調用CGI程式的HTTP伺服器的名稱和版本号。例如,上面的值為Apache/2.2.14(Unix)

以下是一個簡單的CGI腳本輸出CGI的環境變量:

執行個體

print "Content-type: text/html\n\n";

print "<font size=+1>環境變量:</font>\n";

foreach (sort keys %ENV)

{

print "<b>$_</b>: $ENV{$_}<br>\n";

}

檔案下載下傳

如果我們想通過 Perl CGI 實作檔案下載下傳,需要設定不同的頭部資訊,如下所示:

# HTTP Header

print "Content-Type:application/octet-stream; name=\"FileName\"\r\n";

print "Content-Disposition: attachment; filename=\"FileName\"\r\n\n";

# Actual File Content will go hear.

open( FILE, "<FileName" );

while(read(FILE, $buffer, 100) )

print("$buffer");

使用GET方法傳輸資料

GET方法發送編碼後的使用者資訊到服務端,資料資訊包含在請求頁面的URL上,以"?"号分割, 如下所示:

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

有關 GET 請求的其他一些注釋:

  • GET 請求可被緩存
  • GET 請求保留在浏覽器曆史記錄中
  • GET 請求可被收藏為書簽
  • GET 請求不應在處理敏感資料時使用
  • GET 請求有長度限制
  • GET 請求隻應當用于取回資料

簡單的url執行個體:GET方法

以下是一個簡單的URL,使用GET方法向test.cgi程式發送兩個參數:

/cgi-bin/test.cgi?name=菜鳥教程&url=http://www.runoob.com
      

以下為test.cgi檔案的代碼:

local ($buffer, @pairs, $pair, $name, $value, %FORM);

# 讀取文本資訊

$ENV{'REQUEST_METHOD'} =~ tr/a-z/A-Z/;

if ($ENV{'REQUEST_METHOD'} eq "GET")

$buffer = $ENV{'QUERY_STRING'};

# 讀取 name/value 對資訊

@pairs = split(/&/, $buffer);

foreach $pair (@pairs)

($name, $value) = split(/=/, $pair);

$value =~ tr/+/ /;

$value =~ s/%(..)/pack("C", hex($1))/eg;

$FORM{$name} = $value;

$name = $FORM{name};

$url = $FORM{url};

print "<html>";

print "<head>";

print "</head>";

print "<body>";

print "<h2>$name網址:$url</h2>";

print "</body>";

print "</html>";

檢視浏覽器,輸出結果如下:

Perl CGI程式設計

簡單的表單執行個體:GET方法

以下是一個通過HTML的表單使用GET方法向伺服器發送兩個資料,送出的伺服器腳本同樣是test.cgi檔案,test.html 代碼如下:

test.html 檔案代碼

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

<title>菜鳥教程(runoob.com)</title>

</head>

<body>

<form action="/cgi-bin/test.cgi" method="get">

站點名稱: <input type="text" name="name"> <br />

站點 URL: <input type="text" name="url" />

<input type="submit" value="送出" />

</form>

</body>

</html>

浏覽器中,執行效果如下所示:

Perl CGI程式設計

使用POST方法傳遞資料

使用POST方法向伺服器傳遞資料是更安全可靠的,像一些敏感資訊如使用者密碼等需要使用POST傳輸資料。

以下同樣是 test.cgi ,它也可以處理浏覽器送出的POST表單資料:

if ($ENV{'REQUEST_METHOD'} eq "POST")

read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});

}else {

test.html 代碼

<form action="/cgi-bin/test.cgi" method="post">

Perl CGI程式設計

通過CGI程式傳遞checkbox資料

checkbox用于送出一個或者多個選項資料,test.html 代碼如下:

<form action="/cgi-bin/test.cgi" method="POST" target="_blank">

<input type="checkbox" name="runoob" value="on" /> 菜鳥教程

<input type="checkbox" name="google" value="on" /> Google

<input type="submit" value="選擇站點" />

以下為 test.cgi 檔案的代碼:

# 讀取資訊

if( $FORM{runoob} ){

$runoob_flag ="ON";

}else{

$runoob_flag ="OFF";

if( $FORM{google} ){

$google_flag ="ON";

$google_flag ="OFF";

print "<h2> 菜鳥教程選中狀态 : $runoob_flag</h2>";

print "<h2> Google 選擇狀态 : $google_flag</h2>";

Perl CGI程式設計

通過CGI程式傳遞Radio資料

Radio 隻向伺服器傳遞一個資料,test.html 代碼如下:

<form action="/cgi-bin/test.cgi" method="post" target="_blank">

<input type="radio" name="site" value="runoob" /> 菜鳥教程

<input type="radio" name="site" value="google" /> Google

test.cgi 腳本代碼如下:

$site = $FORM{site};

print "<h2> 選擇的網站 $site</h2>";

Perl CGI程式設計

通過CGI程式傳遞 Textarea 資料

Textarea 向伺服器傳遞多行資料,test.html 代碼如下:

<textarea name="textcontent" cols="40" rows="4">

在這裡輸入内容...

</textarea>

$text_content = $FORM{textcontent};

print "<h2>輸入的文本内容為:$text_content</h2>";

Perl CGI程式設計

通過 CGI 程式傳遞下拉資料

HTML 下拉框代碼如下:

<select name="dropdown">

<option value="runoob" selected>菜鳥教程</option>

<option value="google">Google</option>

</select>

<input type="submit" value="送出"/>

test.cgi 腳本代碼如下所示:

$site = $FORM{dropdown};

print "<h2>選擇的網站是:$site</h2>";

Perl CGI程式設計

CGI中使用Cookie

在 http 協定一個很大的缺點就是不對使用者身份的進行判斷,這樣給程式設計人員帶來很大的不便,

而 cookie 功能的出現彌補了這個不足。

cookie 就是在客戶通路腳本的同時,通過客戶的浏覽器,在客戶硬碟上寫入紀錄資料

,當下次客戶通路腳本時取回資料資訊,進而達到身份判别的功能,cookie 常用在身份校驗中。

 

cookie的文法

http cookie的發送是通過http頭部來實作的,他早于檔案的傳遞,頭部set-cookie的文法如下:

Set-cookie:name=name;expires=date;path=path;domain=domain;secure 
      
  • name=name: 需要設定cookie的值(name不能使用";"和","号),有多個name值時用 ";" 分隔,例如:name1=name1;name2=name2;name3=name3。
  • expires=date: cookie的有效期限,格式: expires="Wdy,DD-Mon-YYYY HH:MM:SS"
  • path=path: 設定cookie支援的路徑,如果path是一個路徑,則cookie對這個目錄下的所有檔案及子目錄生效,例如: path="/cgi-bin/",如果path是一個檔案,則cookie指對這個檔案生效,例如:path="/cgi-bin/cookie.cgi"。
  • domain=domain: 對cookie生效的域名,例如:domain="www.runoob.com"
  • secure: 如果給出此标志,表示cookie隻能通過SSL協定的https伺服器來傳遞。
  • cookie的接收是通過設定環境變量HTTP_COOKIE來實作的,CGI程式可以通過檢索該變量擷取cookie資訊。

Cookie設定

Cookie的設定非常簡單,cookie會在http頭部單獨發送。以下執行個體在cookie中設定了UserID、Password 和 expires:

print "Set-Cookie:UserID=XYZ;\n";

print "Set-Cookie:Password=XYZ123;\n";

print "Set-Cookie:Expires=Tuesday, 31-Dec-2017 23:12:40 GMT";\n";

print "Set-Cookie:Domain=www.runoob.com;\n";

print "Set-Cookie:Path=/perl;\n";

...........其他 HTML 内容

查找 Cookie

Cookie資訊檢索頁非常簡單,Cookie資訊存儲在CGI的環境變量HTTP_COOKIE中,存儲格式如下:

$rcvd_cookies = $ENV{'HTTP_COOKIE'};

@cookies = split /;/, $rcvd_cookies;

foreach $cookie ( @cookies ){

($key, $val) = split(/=/, $cookie); # splits on the first =.

$key =~ s/^\s+//;

$val =~ s/^\s+//;

$key =~ s/\s+$//;

$val =~ s/\s+$//;

if( $key eq "UserID" ){

$user_id = $val;

}elsif($key eq "Password"){

$password = $val;

}

print "User ID = $user_id\n";

print "Password = $password\n";

以上執行個體輸出結果為:

User ID = XYZ
Password = XYZ123
      

CGI 子產品

Perl 提供了很多内置的 CGI 子產品,常用以下兩個:

  • Berkeley cgi-lib.pl