大多數網站託管(Web hosting)公司都支援客戶對Web網站統計資料的訪問,但是你往往會覺得伺服器所產生的狀態資訊不夠全面。例如,配置不正確的Web伺服器不能識別某些檔案類型,這些類型的檔案就不會出現在狀態資訊之中。幸好,你可以用PHP來定製狀態資訊收集程式,這樣你就可以擷取你所需要的資訊了。
公用記錄檔格式(Common Logfile Format,CLF)的結構
CLF最初是NCSA為HTTPd(全球網伺服器軟體)而設計的。CERN HTTPd是一個由全球資訊網聯盟(World Wide Web Consortium,W3C)維護的公用域Web伺服器。W3C網站列出了該記錄檔規範。基於微軟和UNIX的Web伺服器都可以產生CLF格式的記錄檔。CLF格式如下:
Host IdentAuthuserTime_Stamp "request" Status_codeFile_size
例如:
21.53.48.83 - - [22/Apr/2002:22:19:12 -0500] "GET /cnet.gif HTTP/1.0" 200 8237
下面是日誌條目的細目分類:
Host是網站訪問者的IP地址或者DNS名;在上面的例子中,它是21.53.48.83。
Ident是該訪客的遠端身份(RFC 931)。破折號表明“未指定”。
Authuser是使用者ID(如果Web伺服器已經驗證了驗證網站訪問者的身份的話)。
Time_Stam是伺服器以“日/月/年”這種格式返回的時間。
Request是網站訪問者的HTTP請求,例如GET或者POST。
Status_Code是伺服器所返回的狀態碼,例如:200代表“正確——瀏覽器請求成功”。
File_Size是使用者所請求檔案的大小。在本例中,它為 8237位元組。
伺服器狀態碼
你可以在HTTP標準中找到W3C所開發的伺服器狀態碼規範。這些由伺服器所產生的狀態碼表示了瀏覽器和伺服器之間的資料轉送成功與否。這些代碼一般傳遞給瀏覽器(例如非常有名的404錯誤“頁面沒有找到“)或者添加到伺服器日誌中去。
收集資料
建立我們的自訂應用程式的第一步就是擷取使用者資料。每當使用者選擇網站的某個資源時,我們就希望建立一個對應的日誌條目。幸好,伺服器變數的存在使得我們能夠查詢使用者瀏覽器並擷取資料。
前序中的伺服器變數攜帶了從瀏覽器傳遞到伺服器的資訊。REMOTE_ADDR就是一個伺服器變數的例子。這個變數返回了使用者的IP地址:
例子輸出:27.234.125.222
下面的PHP代碼將顯示出目前使用者的IP地址:
<?php echo $_SERVER['REMOTE_ADDR']; ?>
讓我們看看我們的PHP應用程式的代碼。首先,我們需要定義我們想跟蹤的網站資源並指定檔案大小:
//擷取我們想記錄的檔案名稱
$fileName="cnet-banner.gif";
$fileSize="92292";
你無需把這些值儲存到靜態變數中去。如果你要跟蹤許多條目,那麼你可以把它們儲存到數組或者資料庫中去。在這種情況下,你可能會希望通過一個外部連結來找到每個條目,如下所示:
<a href="weblogger.php?bannerid=123"><imgsrc="cnet-banner.gif" border="0"></a>
其中“123”表示“cnet-banner.gif”所對應的記錄。然後,我們通過伺服器變數來查詢使用者瀏覽器。這樣我們就得到在我們的記錄檔中添加新條目所需的資料:
//得到網站瀏覽者的CLF資訊
$host=$_SERVER['REMOTE_ADDR'];
$ident=$_SERVER['REMOTE_IDENT'];
$auth=$_SERVER['REMOTE_USER'];
$timeStamp=date("d/M/Y:H:i:s O");
$reqType=$_SERVER['REQUEST_METHOD'];
$servProtocol=$_SERVER['SERVER_PROTOCOL'];
$statusCode="200";
然後,我們檢查伺服器是否返回了空值(null)。根據CLF規範,空值應該用破折號來代替。這樣,下一個代碼塊的任務就是尋找空值並用破折號來取代它:
//給空值添加破折號(根據規範)
if ($host==""){ $host="-"; }
if ($ident==""){ $ident="-"; }
if ($auth==""){ $auth="-"; }
if ($reqType==""){ $reqType="-"; }
if ($servProtocol==""){ $servProtocol="-"; }
一旦我們擷取了必要的資訊,這些值將被組織成一種符合CLF規範的格式:
//建立CLF格式的字串
$clfString=$host." ".$ident." ".$auth." [".$timeStamp."] \"".$reqType." /".$fileName." ".$servProtocol."\" ".$statusCode." ".$fileSize."\r\n";
建立自訂記錄檔
現在,格式化之後的資料可以存放到我們的自訂記錄檔中去。首先,我們將建立一種檔案命名協定,並編寫每日產生一個新記錄檔的方法(函數)。在本文所舉的例子中,每個檔案都以“weblog-”開頭,然後是按月/日/年表示的日期,副檔名為.log。.log副檔名一般表示伺服器記錄檔。(實際上,絕大多數日誌分析器都搜尋.log檔案。)
// 用當前日期來命名記錄檔
$logPath="./log/";
$logFile=$logPath."weblog-".date("mdy").".log";
現在,我們需要判斷當前記錄檔是否存在。如果存在,我們就向它添加條目;否則,應用程式就建立新的記錄檔。(新記錄檔的建立一般發生在日期更改時,因為這時檔案名稱發生變化了。)
//檢查記錄檔是否已經存在
if (file_exists($logFile)){
//如果存在,則開啟已存在的記錄檔
$fileWrite = fopen($logFile,"a");}
else {
//否則,建立新的記錄檔
$fileWrite = fopen($logFile,"w"); }
如果你在寫或者追加檔案時,收到“許可權不足(Permission Denied)”錯誤資訊,請更改目標記錄檔夾的許可權來允許寫操作。絕大多數Web伺服器的預設許可權為“可讀可執行”。你可以用CHMOD命令或者使用FTP用戶端來改變檔案夾的許可權。
然後,我們建立檔案鎖定機制,這樣當兩個或者更多使用者同時訪問記錄檔時,只有其中的一個使用者可以對該檔案進行寫操作:
//建立檔案寫操作的鎖定機制
flock($fileWrite, LOCK_SH);
最後,我們寫入條目的內容:
//寫CLF條目
fwrite($fileWrite,$clfString);
//解除檔案鎖定狀態
flock($fileWrite, LOCK_UN);
//關閉記錄檔
fclose($fileWrite);
處理日誌資料
在該系統產品化之後,客戶希望得到對所收集到的訪問者資料的詳細統計分析。由於所有的定製記錄檔都是按照一個標準的格式組織的,因此任何一個日誌分析器都可以處理它們。日誌分析器是一個工具,它分析大的記錄檔併產生餅圖、長條圖以及其它統計圖形。日誌分析器也用來收集資料,並綜合出提供哪些使用者訪問你的網站、點擊數等方面的資訊。
下面列出了幾個比較流行的日誌分析器:
WebTrends是一個非常不錯的日誌分析器,它適用於大規模網站以及企業級的網路。
Analog是一個頗受歡迎的免費日誌分析器。
Webalizer是一個免費的剖析器。它可以產生HTML報告,這樣大多數網路瀏覽器都可以查看它的報告。
遵守標準
我們可以輕鬆的擴充該應用程式來讓它支援其它類型的日誌記錄。這樣你就可以捕獲到更多的資料,如瀏覽器類型以及referrer(referrer指得是連結到當前網頁的前一個網頁)。這裡的經驗就是:在你編程的時候遵循標準或者慣例終究會簡化工作。