以下為引用的內(nèi)容: #!/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); 代碼首先引入了一些常用庫(kù)并聲明了一些變量,然后將加載 404 報(bào)告文本和通過(guò) buildMetaphoneList.pl 程序創(chuàng)建的變音。這時(shí),我們可以開始編寫主要的程序邏輯了,如下所示。清單 5. 主要程序邏輯
以下為引用的內(nèi)容: 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 } 首先,對(duì)匹配測(cè)試各部分的輸出進(jìn)行排序,然后將其添加到總建議鏈接列表。對(duì)鏈接列表進(jìn)行排序和惟一化(unique-ifying)之后,將建議鏈接直接打印輸出。三個(gè)排序命令將結(jié)果保存在同一個(gè)數(shù)組中,目的是創(chuàng)建一個(gè)有序的建議列表。發(fā)生 404 錯(cuò)誤時(shí),目錄樹中(至少第一級(jí)目錄)極有可能會(huì)出現(xiàn)目錄分隔符(用于表示 Web 頁(yè)面)。比如說(shuō),以 bloggs/nathenherringtoon.html 頁(yè)面請(qǐng)求為例。上述代碼中所調(diào)用的 directorySplitTest 方法將創(chuàng)建一個(gè)排序的頁(yè)面列表,BLKS 和子目錄 N0NHRNKTN 的變音匹配都將包含在該列表中。這一策略可用于區(qū)分根目錄中的文件(如 blogs.html 和 nathanharrington.html)和完整路徑名匹配的頁(yè)面(如 blogs/nathanharrington.html)。下面的清單顯示了 directorySplitTest 子例程的內(nèi)容。清單 6. directorySplitTest subroutine
以下為引用的內(nèi)容: 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 組合測(cè)試位于 directorySplitTest 之后,用于檢查變音混和在一起時(shí)的匹配情況 忽略任何目錄結(jié)構(gòu)。該測(cè)試用于糾正 404 類錯(cuò)誤,即文件名中含有空格、斜杠、反斜杠、冒號(hào)和其他一些無(wú)發(fā)音的字符。比如說(shuō),如果針對(duì) blogs_nathanherrington.html 發(fā)出一個(gè) 404 請(qǐng)求,那么 directorySplitTest 將返回零結(jié)果,但是 combinedTest 將發(fā)現(xiàn)該 404 產(chǎn)生的變音組合在一起是 blogs/NathanHarrington.html 頁(yè)面的準(zhǔn)確匹配。同樣,這些建議的優(yōu)先級(jí)低于目錄匹配,因此這些分類結(jié)果將在 directorySplitTest 之后存入 suggestLinks 數(shù)組。以下清單顯示了 combinedTest 子例程。清單 7. combinedTest 子例程
以下為引用的內(nèi)容: 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 之后是最后一個(gè)匹配測(cè)試,該測(cè)試基于一個(gè)廣度包含搜索。如果當(dāng)前的 404 鏈接的變音是 metaphoneScores.txt 文件中可用變音的一部分,我們將把它添加到建議列表。包含搜索的設(shè)計(jì)目的是尋找內(nèi)容極度不完整的 URL。nathan.html 頁(yè)面在任何位置都無(wú)法找到,但是一個(gè)良好的建議應(yīng)該是 /NathanHarrington.html 和 /blogs/NathanHarrington.html,并且它們根據(jù)作用域值排序并添加到 suggestLinks 數(shù)組中。注意,此方法還將為單字母變音 404(如 whoo.html)生成 NathanHarrington.html 建議。由于 NathanHarrington.html 變音中含有一個(gè) H ,故將其添加到建議列表。考慮創(chuàng)建一個(gè)最小長(zhǎng)度的匹配變音,或提供一個(gè)包含總數(shù)受限的匹配,以修改這一行為。清單 8 顯示了 containsTest 和 sortResults 子例程。清單 8. sortResults 和 containsTest 子例程
以下為引用的內(nèi)容: 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 文件上面所設(shè)計(jì)的 MetaphoneSuggest 腳本是一個(gè)將從 Apache 中直接調(diào)用的 cgi-bin 腳本。要運(yùn)行 MetaphoneSuggestscript 腳本,我們需要對(duì) httpd.conf 文件進(jìn)行適當(dāng)修改,否則將顯示 404 錯(cuò)誤頁(yè)面。比如說(shuō),如果默認(rèn)的 httpd.conf 文件含有以下部分:清單 9. 默認(rèn) httpd.conf 部分
以下為引用的內(nèi)容: # 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 服務(wù)器的 document_root /cgi-bin/ 目錄下。以根用戶身份發(fā)起服務(wù)器重啟命令:例如 /usr/local/apache2/bin/apachectl restart,至此靈活的建議機(jī)制將徹底結(jié)束笨拙的 404 錯(cuò)誤。結(jié)束語(yǔ)