以下為引用的內容: #!/usr/bin/perl -w # MetaphoneSuggest - suggest links for typographical and other errors from 404s use strict; use CGI::Pretty ':standard'; #standard cgi stuff use Text::Metaphone;
my @suggestLinks = (); # suggested link list my %mt = (); # filename, score, metaphone code hash my $origLink = substr($ENV{REDIRECT_URL},1); # remove leading / $origLink =~ s//.html//g; # remove trailing .html open(MPH,'metaphonesScore.txt') or die can't open metaphones while(my @slPart = split '###', MPH ) { $slPart[0] =~ s/ //g; #remove trailing space $mt{$slPart[0]}{ score } = $slPart[1]; $mt{$slPart[0]}{ metaphones } = $slPart[2]; } close(MPH); 代碼首先引入了一些常用庫并聲明了一些變量,然后將加載 404 報告文本和通過 buildMetaphoneList.pl 程序創建的變音。這時,我們可以開始編寫主要的程序邏輯了,如下所示。清單 5. 主要程序邏輯
以下為引用的內容: push @suggestLinks, sortResults( directorySplitTest( $origLink ) ); push @suggestLinks, sortResults( combinedTest( $origLink ) ); push @suggestLinks, sortResults( containsTest( $origLink ) ); # from the book - unique-ify the array my %seen = (); @suggestLinks = grep{ ! $seen{$_}++ } @suggestLinks ; print header; print qq{Error 404: The file requested [$ENV{REDIRECT_URL}] is unavailable. BR next if( @suggestLinks == 0 ); print qq{Please try one of the following pages: BR for my $link( @suggestLinks ){ $link = substr($link,index($link,'./')+1); print qq{ a href= $link $link /a BR } 首先,對匹配測試各部分的輸出進行排序,然后將其添加到總建議鏈接列表。對鏈接列表進行排序和惟一化(unique-ifying)之后,將建議鏈接直接打印輸出。三個排序命令將結果保存在同一個數組中,目的是創建一個有序的建議列表。發生 404 錯誤時,目錄樹中(至少第一級目錄)極有可能會出現目錄分隔符(用于表示 Web 頁面)。比如說,以 bloggs/nathenherringtoon.html 頁面請求為例。上述代碼中所調用的 directorySplitTest 方法將創建一個排序的頁面列表,BLKS 和子目錄 N0NHRNKTN 的變音匹配都將包含在該列表中。這一策略可用于區分根目錄中的文件(如 blogs.html 和 nathanharrington.html)和完整路徑名匹配的頁面(如 blogs/nathanharrington.html)。下面的清單顯示了 directorySplitTest 子例程的內容。清單 6. directorySplitTest subroutine
以下為引用的內容: sub directorySplitTest { my @matchRes = (); my $inLink = $_[0]; for my $fileName ( keys %mt ) { my @inLinkMetas = (); # process each metaphone chunk as a directory for my $inP ( split '//', $inLink ){ push @inLinkMetas, Metaphone($inP) } my @metaList = split ' ', $mt{$fileName}{metaphones}; next if( @metaList != @inLinkMetas ); my $pos = 0; my $totalMatch = 0; for( @metaList ) { $totalMatch++ if( $metaList[$pos] =~ /(/b$inLinkMetas[$pos]/b)/i ); $pos++; }#for meatlist # make sure there is a match in each metaphone chunk next if( $totalMatch != @metaList ); push @matchRes, $mt{$fileName}{score} ## $fileName }#for keys in metaphone hash return( @matchRes ); }#directorySplitTest 組合測試位于 directorySplitTest 之后,用于檢查變音混和在一起時的匹配情況 忽略任何目錄結構。該測試用于糾正 404 類錯誤,即文件名中含有空格、斜杠、反斜杠、冒號和其他一些無發音的字符。比如說,如果針對 blogs_nathanherrington.html 發出一個 404 請求,那么 directorySplitTest 將返回零結果,但是 combinedTest 將發現該 404 產生的變音組合在一起是 blogs/NathanHarrington.html 頁面的準確匹配。同樣,這些建議的優先級低于目錄匹配,因此這些分類結果將在 directorySplitTest 之后存入 suggestLinks 數組。以下清單顯示了 combinedTest 子例程。清單 7. combinedTest 子例程
以下為引用的內容: sub combinedTest { my @matchRes = (); my $inLink = $_[0]; for my $fileName ( keys %mt ) { my $inLinkMeta = Metaphone($inLink); # smoosh all of the keys together, removing spaces and trailing newline my $metaList = $mt{$fileName}{metaphones}; $metaList =~ s/( |/n)//g; next if( $metaList !~ /(/b$inLinkMeta/b)/i ); push @matchRes, $mt{$fileName}{score} ## $fileName }#for filename keys in metaphone hash return(@matchRes); }#combinedTest 在 combinedTest 之后是最后一個匹配測試,該測試基于一個廣度包含搜索。如果當前的 404 鏈接的變音是 metaphoneScores.txt 文件中可用變音的一部分,我們將把它添加到建議列表。包含搜索的設計目的是尋找內容極度不完整的 URL。nathan.html 頁面在任何位置都無法找到,但是一個良好的建議應該是 /NathanHarrington.html 和 /blogs/NathanHarrington.html,并且它們根據作用域值排序并添加到 suggestLinks 數組中。注意,此方法還將為單字母變音 404(如 whoo.html)生成 NathanHarrington.html 建議。由于 NathanHarrington.html 變音中含有一個 H ,故將其添加到建議列表。考慮創建一個最小長度的匹配變音,或提供一個包含總數受限的匹配,以修改這一行為。清單 8 顯示了 containsTest 和 sortResults 子例程。清單 8. sortResults 和 containsTest 子例程
以下為引用的內容: sub sortResults { # simply procedue to sort an array of 'score ## filename' entries my @scored = @_; my @idx = (); #temporary index for sorting for my $entry( @scored ){ # create an index of scores my $item = substr($entry,0,index($entry,'##')); push @idx, $item; }
# sort the index of scores my @sorted = @scored[ sort { $idx[$b] = $idx[$a] } 0 .. $#idx ];
return( @sorted );
}#sortResults sub containsTest { my @matchRes = (); my $inLink = $_[0]; for my $fileName ( keys %mt ) { my $inLinkMeta = Metaphone($inLink); my $metaList = $mt{$fileName}{metaphones}; next if( $metaList !~ /$inLinkMeta/i ); push @matchRes, $mt{$fileName}{score} ## $fileName }#for filename keys in metaphone hash return(@matchRes); }#containsTest 修改 Apache httpd.conf 文件上面所設計的 MetaphoneSuggest 腳本是一個將從 Apache 中直接調用的 cgi-bin 腳本。要運行 MetaphoneSuggestscript 腳本,我們需要對 httpd.conf 文件進行適當修改,否則將顯示 404 錯誤頁面。比如說,如果默認的 httpd.conf 文件含有以下部分:清單 9. 默認 httpd.conf 部分
以下為引用的內容: # Customizable error responses come in three flavors: # 1) plain text 2) local redirects 3) external redirects # # Some examples: #ErrorDocument 500 The server made a boo boo. #ErrorDocument 404 /missing.html #ErrorDocument 404 /cgi-bin/missing_handler.pl #ErrorDocument 402 http://www.example.com/subscription_info.html 在注釋掉的 ErrorDocument 代碼行之后插入如下代碼:ErrorDocument 404 /cgi-bin/MetaphoneSuggest 。確保 MetaphoneSuggest 和 metaphonesScore.txt 文件位于 Web 服務器的 document_root /cgi-bin/ 目錄下。以根用戶身份發起服務器重啟命令:例如 /usr/local/apache2/bin/apachectl restart,至此靈活的建議機制將徹底結束笨拙的 404 錯誤。結束語