FrontPage | changes | index | create | search | preferences |

WiKicker

Last-Modified: Sun Dec 20 01:43 2009; by KM
edit | copy | diff | rlog | raw
  1. Tips
    1. robots.txt for Query String
    2. .htaccess
    3. スパム対策
    4. Perl 5.6.2→5.8.7移行メモ
    5. データベースから直接、Google Sitemapを生成
      1. PageRanking
    6. 参照しているページ自体へのAutomaticリンクを取り除く
  2. その他、備忘用

このWikiForumを提供しているWikiEngine。 Perlで実装されていて、ページの部分編集、RCSによる複数世代のバージョン管理等、いたって高機能。

FreeBSDportsにも、japanese/wikickerとして加えられています。

Tips

robots.txt for Query String

サイトを外部からも閲覧できるようにしていると、検索エンジンのロボット(クローラー)が根こそぎコンテンツを持っていこうとします。 あまり、持っていっても意味がないと思われるページ*1は、robots.txtに書いておいて持っていかないよう、お願いしておいた方が無難*2。 ちょうど、WiKickerの場合、Wikiの編集画面など、閲覧者には二次的な内容のコンテンツは、URIにクエリ文字列が付く形を とっています。従って、robots.txtに、

 User-agent: *
 Disallow: /wiki?

としておけば、メジャーなクローラー*3なら、それを汲み取って、クエリ文字列が続くURIにはアクセスしてきません。

あるいは、編集画面へのアクセスだけを拒否するには、

 User-agent: *
 Disallow: /wiki?edit=

としておけばOK。

*1WiKickerはRCSで複数世代のコンテンツのバージョンを管理しているので、どうしても一見、類似した内容のページが大量に出来てしまう。重複した内容が多いと検索エンジンの検索結果でURL表示のみになったり、あるいは検索結果のインデックスから外されるらしい。

*2もちろん、robots.txtを設定できる権限があることが前提。

*3Googlebot/2,1、Yahoo! Slurp、msnbot/1.0、Ask Jeeves/Teoma等で確認済み。

.htaccess

 ※セキュリティ上の都合で、内容の一部を改変している場合があります。

 <Files wiki>
     SetHandler speedycgi-script
     # SetHandler cgi-script
 </Files>
 
 ####
 
 RewriteEngine on
 
 RewriteCond %{QUERY_STRING} (?:diff|edit|name|rlog|search)=
 RewriteCond %{HTTP_COOKIE}  !WiKicker=
 RewriteRule ^wiki$ - [F,L]

 RewriteCond %{REQUEST_METHOD} POST
 RewriteCond %{HTTP_REFERER}   !^(?:http://www\.xdelta\.net/wiki(?:[/|\?].+))?$
 RewriteCond %{HTTP_COOKIE}    !WiKicker=
 RewriteRule ^wiki$ - [F,L]

 RewriteRule ^wiki/(.+)/$ /wiki/$1.html [R,L]
 
 RewriteRule ^wiki/(?:.+?/)?favicon\.ico$ /favicon.ico [L]
 RewriteRule ^wiki/.+\.(?i:gif|ico|jpe?g|png)$ - [F,L]

一番下は、変なリクエストをしてくる一部Webブラウザ用。ディレクトリごとにfavicon.icoを取得しようとしたり、ディレクトリの解釈にバグがあると思われる。

ついでに、管理人がスパムと認識しているクローラーを拒否する設定例のいくつか

 RewriteCond %{HTTP_USER_AGENT} ^User-Agent:
 RewriteRule ^.*$ - [F,L]
 
 # 全信協スパム
 RewriteCond %{HTTP_USER_AGENT} "^Mozilla/4.0 \(compatible; MSIE 6\.0; Windows 98\)$"
 RewriteCond %{SERVER_PROTOCOL} ^HTTP/1\.0$
 RewriteCond %{HTTP_REFERER}    ^$
 RewriteRule ^.*$ - [F,L]
 
 # 不正なリファラ
 RewriteCond %{HTTP_REFERER} ^http://www\.xdelta\.net/wiki/(?:.*/)?$
 RewriteRule ^wiki(?:[/?].*)?$ - [F,L]
 
 # some referer spam
 RewriteRule ^wiki/\+(?:.*?-\+-.*)-\+\.html$ - [F,L]

 RewriteCond %{HTTP_REFERER} "black-?jack|casino|gambling|poker|roulette|texas-hold-?em" [OR]
 RewriteCond %{HTTP_REFERER} "loans" [OR]
 RewriteCond %{HTTP_REFERER} "diet-pill||phentermine|via[gq]rr?a"
 RewriteRule ^.*$ - [F,L]

中段は、いわゆる全信協スパムクローラー*4と呼ばれるものを意図して弾く設定。アクセス元には触れてないので、このままの設定だと、もしかすると無関係な方も拒否されるかも知れないので、十分注意する必要あり。

最近は、たどって来たページに対して自動的にリンクを張るページを対象に、宣伝目的のHTTP-REFERERを送信してくるリファラスパムと呼ばれるものも増えている*5ので、これも、.htaccess等で弾いておいた方が無難。

*4メールアドレスの取得を目的やってくる招かざるクローラー。一応、国内の法人らしい。アドレスが見付かったら、その後、文章・内容とも、怪しげなメールが送られて来る…。

*5現在のWiKickerには直接関係ないと思われるが、スパム対象のリストに加えられても迷惑なので。

スパム対策

可能なかぎり.htaccess等を駆使してなるべくCGIが起動される前に、スパム目的と思しきクライアントは弾きたいものであるが、すり抜けてスパム投稿してきた場合、厄介である*6

しかし、WiKickerには、あらかじめ書き込み禁止ワードを設定する機能が付いており、これによってある程度、不本意な書き込みを制限することができる。

書き込み禁止パターンファイルの行頭にqrで始まる行があれば、Perl正規表現qr//*7であると見なされ、例えば、

 qr/black[-\s]?jack|casino|gambling|poker|roulette|texas[-\s]hold[-\s]?em/i
 qr/loans/i
 qr/diet[-\s]pill|phentermine|via[gq]rr?a/i

のように、書き込み禁止パターンファイル内で、正規表現を使用することもできる。

*6一度、ポツリと来だしたら、その後、怒涛のように押し寄せて来るのがスパムの常である。そのうち収まるだろうと言うのは甘い考えで、万全を期して、芽は早いうちに摘み取るのが得策。

*7qr/STRING/は、コンパイル済みの正規表現を得るPerl関数。なお、現在、禁止パターンファイル中にはスラッシュ/以外のデリミタは使用できない模様。

Perl 5.6.2→5.8.7移行メモ

FreeBSDportsインストールされるPerlのデフォルトのバージョンも、v5.8.7になったので、 そろそろ、Webサーバーの方のPerlもv5.6からアップグレードしなくてはならないかなと思い、試みてみました。

ところがそのまま移行しただけでは、WiKickerの方が、

 Byte order is not compatible at blib/lib/Storable.pm

と言われて起動できない。

いろいろ調べたところ、FreeBSDPerlは、v5.8から64bit Intengerでビルドされるよう*8*9なので、Storableモジュールのデータの互換性がとれないのが原因らしい。

(wikicker.database.directory)/info/basic 以下のファイルを削除すれば、解決するようだけど、そうすると、各ページのサマリや、更新履歴が空白になってしまう…。

で、解決策として、古いPerl上で、Data::Dumperを使って該当データをPerlのソースコードにダンプし、それを新しい方のPerlで読み込んで、そのStorableで書き戻すというやり方*10を試みてみました。

まず、

 #!/usr/local/bin/perl5.6.2 -w
 
 use strict;
 use Storable qw(thaw);
 
 use Data::Dumper;
 $Data::Dumper::Indent = 0;   # 出力に改行をはさまない
 $Data::Dumper::Useqq  = 1; # エスケープして出力
 
 my $db_dir = '/SOURCE_DATABASE_DIR/info/basic';   ### 適宜修正
 
 opendir(DIR, $db_dir) || die "can't open dir $db_dir.\n";
 
 while (my $key = readdir(DIR)) {
   next if ($key =~ m/^(?:\.){1,2}$/);
   my $value;
 
   if (open(FILE, "$db_dir/$key")) {
     binmode(FILE);
     local $/;
     $value = <FILE>;
     close(FILE);
   } else {
     die "can't read file $key.\n";
   }
   my  $record = \%{thaw($value)};
   print Data::Dumper->Dump( [ $key, $record ],
                             [ qw(key record) ] ) . "\n";
 }
 
 close(DIR);

をdb-dump.plという名前で保存して、古いPerl上で、

 % perl5.6 db-dump.pl > dump.txt

と実行し、dump.txtを作成する。

そして、新しい方のPerlで、

 #!/usr/local/bin/perl5.8.7 -w
 
 use strict;
 use Storable qw(freeze);
 
 my $output_dir = '/NEW_DATABASE_DIR/info/basic';   ### 適宜修正
 
 while (defined(my $line = <STDIN>)) {
   my($key, $record);
   eval $line;
   die "dame\n" if $@;
 
   my $frozen = freeze($record);
   if (open(FILE, "> $output_dir/$key")) {
     binmode(FILE);
     local $/;
     print FILE $frozen;
     close(FILE);
   } else {
     die "can't write file.\n";
   }
 }

をdb-restore.plという名前で保存し、

 % cat dump.txt | perl5.8.7 db-restore.pl

と実行すればOK。指定したディレクトリに復元されます。これで、サマリ等も見れるようになりました。

あと、IPC::ShareLiteを使用して、RecentLogの機能を有効にしたい場合は、通常のままだとPerlがコアダンプしてしまう不具合があるので、lang/perl5.8-DWITHOUT_PERL_MALLOC付きでビルドするか、もしくは、

でのパッチをdevel/p5-IPC-ShareLiteに適用する必要があります*11

*8そういえば、Perl 5.8では「$M = 0x100000000」はOKなのに、5.6上では「Integer overflow in hexadecimal number at 」とか怒られた。「$M = 0xFFFFFFFF + 0x00000001」と小分けにすると大丈夫なようだが?

*9DON's Diaryに書いてあったけど、lang/perl5.8を「WITHOUT_PERL_64BITINT」付きでビルドすると、従来のデータとの互換性が保てるかも知れない。実際のところ、このオプションを付けてビルドしたら、上記Perl 5.6と5.8との間のStorableを使用したキャッシュファイルの互換性の問題は解決した(データの変換を要せずに、ちゃんとサマリ等も表示できる。もっとも、出来ると言うだけであって、根本的な解決とは思えないが…。それに特定のアプリケーションのために、ビルド方法を変更すると、他のアプリケーションで問題が発生してくる可能性もあるし。やっぱり、標準ビルドの5.8対応を考えた方が無難)。

*10「$Storable::interwork_56_64bit = 1」とすると、Perl 5.6形式のデータも読めるそうだが、そうすると、「Out of memory during "large" request for 2147487744 bytes, total sbrk() is 901120 bytes at ../../lib/Storable.pm」とか怒られたので。

*11現時点でのp5-IPC-ShareLite-0.09のバージョンの場合。

データベースから直接、Google Sitemapを生成

WiKickerのデータベースファイルから、直接、Google Sitemapファイルを生成するスクリプトを書いてみました*12。現在は、当該CGIスクリプトにアクセスがあるとgzip圧縮されたXMLファイルを生成する仕様で、定時にcronでcurlを起動してSitemapファイルを生成することを想定しています。

PageRanking

上記サイトマップを元に各コンテンツのPageRankを調べたい時には、

 curl -s http://www.somedomain.com/wiki-sitemap.xml.gz | gzip -dc | \
 perl -nle 'm"<loc>(.+?)</loc>" && print $1' | gprank.pl | sort

とする。興味本位に、検索エンジンのインデックス状況を知りたい時には、結構便利。

*12クローラーの巡回に頼らずに、新規ページや更新部分を伝えることができるという試みには賛同するので。

参照しているページ自体へのAutomaticリンクを取り除く

 以下のJavaScriptをフッタファイルに書いておけば、新しめのWebブラウザなら、取り除けると思います。

 var ShortNameAttribute = "[[value:ShortNameAttribute]]";

 function removeSameLinksAsThePage(element) {
   if (! element.hasChildNodes)
     return;
 
   for (var i = 0; i < element.childNodes.length; i ++) {
     var e = element.childNodes[i];
     if (e.nodeType == 1 && e.tagName.match(/^A$/i) 
         && e.getAttribute('class') == 'auto') {
       if (e.hasChildNodes && e.firstChild.nodeType == 3 
         && e.firstChild.nodeValue == ShortNameAttribute) {
         element.replaceChild(document.createTextNode(ShortNameAttribute), e);
       }
     } else {
       removeSameLinksAsThePage(e);
     }
   }
 }
 
 if (document.getElementById && document.createElement) {
   var elements = document.getElementsByTagName('div');
   for (var i = 0; elements.length > i; i ++) {
     if (elements[i].getAttribute('class') == 'main') {
       removeSameLinksAsThePage(elements[i]);
     }
   }
 }

その他、備忘用

  • WiKickerでのInterWikiを定義するページ名は、InterWikiDefinitionでなければならない模様。それ以外のページ内で定義しても、(wikicker.database.directory)/cache/interwiki/以下が更新されない。
  • [[anchor:ANCHOR]]などとしてアンカー文字を指定せず、空の<a name="ANCHOR"></a>をたくさん生成すると、SpeedyCGI使用下において、サーバが応答を返さなくなり、プロセスだけが残ってしまう場合がある。SpeedyCGIを使わずに、PerlCGIを起動する場合に置いては、このような問題は発生しないので、おそらく変数の初期化が関係しているのだと思われる。
  • 入り組んだリストや見出しは、3段階まで使える。それより多いと、3段階以降の部分は単なる文字と認識される。
  • memcachedを使っていると、raw viewの挙動が変な時がある。memcachedを再起動すれば直る。
  • SpeedyCGIを使っていると、RssPage等のviewがエラーになる。サイトのporopertiesファイルに、view.rss: WiKicker::CGI::View::XML::Rss等と明示しておく必要がある。

文頭に「:」(コロン)で始まる行では、定義リストを作成する。すなわち、

 :定義語:定義の説明

は、

 <dl>
   <dt>定義語</dt>
   <dd>定義の説明</dd>
 </dl>

のように展開される。しかし、定義語の部分に、「:」(コロン)を使用することはできない。 例えば、定義語の箇所に、[[anchor:アンカー]]を挿入しようとしても、ブラケット内に含まれる「:」に邪魔されて、意図した通りに機能しないので、便宜上、dd部分に挿入する必要がある。