当前位置: 首页 > 图文教程 > 网络编程 > PHP > PHP匹配变音使404页面更加智能化

PHP
php 多线程上下文中安全写文件实现代码
PHP类的使用 实例代码讲解
用php实现让页面只能被百度gogole蜘蛛访问的方法
php 学习笔记
PHP编程过程中需要了解的this,self,parent的区别
php 操作excel文件的方法小结
使用PHP获取网络文件的实现代码
PHP 巧用数组降低程序的时间复杂度
php下将XML转换为数组
php 文件上传代码(限制jpg文件)
php 无极分类(递归)实现代码
PHP 采集获取指定网址的内容
PHP 将图片按创建时间进行分类存储的实现代码
PHP 存储文本换行实现方法
PHP 批量更新网页内容实现代码
用PHP查询搜索引擎排名位置的代码
用php实现的获取网页中的图片并保存到本地的代码
php实现首页链接查询 友情链接检查的代码
处理php自动反斜杠的函数代码
php实现的遍历文件夹下所有文件,编辑删除

PHP匹配变音使404页面更加智能化


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-09-28   浏览: 33 ::
收藏到网摘: n/a

创建您自己的 404 错识消息处理程序,为站点内容提供有用的链接和重定向。使用变音匹配(metaphone matching)和一个简单的加权记分文件为输入错误、拼写错误和无效链接生成重定向建议。根据 Web 站点的内容和首选重定向位置定制建议。捕获传入 URL 请求中的各种错误,并通过处理纠正其中的目录、脚本和 HTML 页面名称错误。

关于如何为 404 页面创建有效格式的教程比比皆是。这类教程大多建议在 404 页面中包含静态的建议链接,并将这些链接指向站点的公共区域,比如说首页、下载页面和站点的搜索引擎,前提是要有这些页面。404 页面普遍存在的问题是它们无法反映用户访问该站点的目的。本文将介绍如何构建一个建议生成器和一个方法,用于根据 Web 站点的内容提供更加有用的重定向链接。

现行的 404 处理程序允许我们为各种错误提供一些建议链接,比如说将用户指向站点目录。一些拼写校正程序(比如说 mod_speling ——— 没错,它只有一个 “l”)可用于纠正词典单词中的错误,从而将用户定向到正确的页面。本文中的代码将帮助您构建一个建议生成引擎,它可以根据 Web 站点的内容来处理在词典中无法找到的单词和目录链接。

我们考虑这样一个场景:您在电话会议中听到了一个 Web 页面名称,因此便尝试打开 blegs/DavSmath.html 链接。现行的拼写校正模块无法为此情况提供一个有用的链接。使用本文中的代码,您将能够生成一个 404 页面,并在其中显示建议的有效页面 /blogs/DaveSmith.html。

需求

本世纪生产的任何现代 PC 应该都足以编写和运行本文中的代码。如果您的 Web 页面含有超过 10,000 个不同的页面,那么可能需要大容量的内存、高性能的硬件或足够的耐心。

所提供的 Perl 和 CGI 脚本可以在多种 UNIX® 和 Windows® 平台上运行(请参阅 下载部分。虽然本文将使用 Apache 和一个 CGI 脚本作为建议引擎,但是所构建的工具应该能够在大多数 Web 服务器上正常运行。对于变音匹配,本文将引用 Michael Schwern 编写的 Text::Metaphone 模块。在开始之前,先通过喜好的 CPAN 镜像安装 Text::Metaphone 模块。请参阅 参考资料 获得下载信息。

Web 服务器页面和变音代码

针对输入和拼写错误提供替代建议的主要方法为变音匹配。与 Soundex 语音算法和一些其他算法类似,Metaphone 使用字母数字代码表示单词的发音。但是,与 Soundex 语音算法有所不同,构建语音代码的目的是匹配英文发音的语言可变性。因此,变音代码通常能够更加准确地表示特定的单词,并且为建议库的构建提供了理论基础。

考虑示例 Web 服务器目录中的下列文件。


清单 1. Web 服务器文件
               

以下为引用的内容:
./index.html
./survey.html
./search_tips.html
./about.html
./how.html
./why.html
./who.html
./NathanHarrington.html
./blogs/NathanHarrington.html
./blogs/DaveSmith.html
./blogs/MarkCappel.html

针对这些静态 HTML 文件,我们将使用 buildMetaphoneList.pl 程序为所有扩展名为 .html 的文件创建变音。


清单 2. buildMetaphoneList.pl
               

以下为引用的内容:
#!/usr/bin/perl -w
# buildMetaphoneList.pl - / split filename, 0 score, metaphones

use strict;
use File::Find;
use Text::Metaphone;

find(\&htmlOnly,".");

sub htmlOnly
{
  if( $File::Find::name =~ /\.html/ )
  {
    my $clipFname = $File::Find::name;
    $clipFname =~ s/\.html//g;

    my @slParts = split '/', $clipFname;
    shift(@slParts);

    print "$File::Find::name ### 0 ### ";
    for( @slParts ){ print Metaphone($_) . " " }
    print "\n";

  }#if a matching .html file

}#htmlOnly sub

buildMetaphoneList.pl 程序只能处理扩展名为 .html 的文件,它将移除文件名中的 .html,然后为完整路径名称的各个部分生成变音。将 buildMetaPhoneList.pl 程序复制到 Web 服务器的根目录下,然后运行命令 perl buildMetaphoneList.pl > metaphonesScore.txt。对于清单 1 中的文件,相应的 metaphonesScore.txt 文件内容如清单 3 所示。

清单 3. metaphonesScore.txt
               

以下为引用的内容:
./index.html ### 0 ### INTKS
./survey.html ### 0 ### SRF
./search_tips.html ### 0 ### SRXTPS
./about.html ### 0 ### ABT
./how.html ### 0 ### H
./why.html ### 0 ### H
./who.html ### 0 ### H
./NathanHarrington.html ### 0 ### N0NHRNKTN
./blogs/NathanHarrington.html ### 0 ### BLKS N0NHRNKTN
./blogs/DaveSmith.html ### 0 ### BLKS TFSM0
./blogs/MarkCappel.html ### 0 ### BLKS MRKKPL

清单 3 中的每一行文字都显示了 Web 服务器根目录下的实际链接、默认作用域和变音代码。注意,how.html、 why.html 和 who.html 都解析为了相同的变音代码。要解决这个不明确的地方,需要修改作用域字段,让链接建议程序以指定的顺序向页面提供链接。比如说,将 “H” 变音条目修改为:

以下为引用的内容:
./how.html ### 100 ### H
./why.html ### 50 ### H
./who.html ### 0 ### H

这样将创建一个直观的链接重排序,并留下空间用于作用域的进一步修改。作用域的数字越大,插入同一变音文件(不过是不同的作用域)的顺序就越靠后。比如说添加一个作用域为 25 的 hoo.html 文件列表,那么它将位于 who.html 条目之上和 why.html 条目之下。

您还可以使用作用域字段区分目录不同而名称相同的文件。比如说,将 ./NathanHarrington.html 一行的的作用域修改为 100,那么类似 nathenHorrington.html 这样的请求会将 ./NathanHarrington.html 链接列在 ./blogs/NathanHarrington.html 页面之前。

选择文件的作用域时,务必要考虑 Web 站点的统计和逻辑访问组件。从日志文件可以看出,用户对 why.html 页面的请求比较频繁,但是如果您认为 how.html 对于用户更为重要,那么只需修改相应的作用域值对排序做出纠正。

构建 CGI 404 处理程序

我们已经生成了适当的变音并为它们指定了相关的作用域值,下一步将构建实际的建议生成器。通常,404 错误消息的原因为链接输入错误或链接本身的问题。以下代码生成的建议将通过以下三个主要测试创建:根据目录结构匹配、使用变音组合匹配,以及当其他方法失败时使用 “包含” 匹配。这三种测试的设计目的是处理大多数 404 错误。MetaphoneSuggest CGI Perl 脚本的开始部分如下所示。

清单 4. MetaphoneSuggest CGI 第 1 部分
               

以下为引用的内容:
#!/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 错误。

结束语
 
记住,使用 MetaphoneSuggest 程序中所描述的工具时,错误条件必须为 404 页面。试着提供少量建议的选择并保持设计的简单性。请教 Web 设计方面的知名人士,了解他们为什么没有提供自动链接建议,或者开展各种可用性研究,了解何种情况下最适合在站点中实现链接建议工具。

本文提供了各种工具和代码,用于在 404 页面中创建实用的链接建议。但是,这些示例都已经实现,您可以通过它们提供一些复杂的功能,而不仅仅是简单的目录链接或拼写建议。通过对特定站点和内容进行调整,笨拙的 404 错误将不复存在。