Published on Blog Developer's Cookbook.
Printer friendly version of http://blog.bulknews.net/cookbook/blosxom/trackback/tb_send.html.
Trackback Ping を送信する
by miyagawa at Fri, 05 Dec 2003 03:54
なにかのイベントや、事件などについての Blog 記事を書くとき、同じ内容について書かれている Blog エントリ同士がリンクでつながっていると、ブラウズやディスカッションの際に非常に便利です。Trackback は、こうしたエントリ間のつながりを、簡単な URL 呼び出しで実現するための Blog API です。今回は、この Trackback Ping の API について簡単に解説し、Trackback Ping を実際に送信するコードを記述してみます。
Trackback は MovableType の Ben & Mena 夫妻によって考案され(*1)、Movable Type ではじめて実装された、Blog 間の言及通知のフレームワークです。
Trackback は、送信側が受信側に対して、HTTP によるメッセージを送信することによって行われます。
まず送信側は、通知したい Blog エントリやカテゴリ毎に固有の Trackback URL に対して、HTTP POST で
url | URL |
blog_name | Blog 名 |
title | タイトル |
excerpt | 概要 |
の情報を送信します。受信側は、これらのパラメータをローカルのDB などに保存し、レスポンスを以下のような XML で返します。
Content-Type: text/xml
<?xml encoding="utf-8"?>
<response>
<error>0</error>
<message>Ping saved successfully.</message>
</response>
もしエラーが起こった場合には、
Content-Type: text/xml
<?xml encoding="utf-8"?>
<response>
<error>1</error>
<message>Something Bad happened.</message>
</response>
のように error
に 1 をセットします。
Trackback の API はたったこれだけです。MovableType では、各記事やカテゴリごとに Trackback の固有ID が用意されており、http://example.com/mt/mt-tb.cgi/1234
のような URL が Trackback URL (送信先)となります(*2)。その記事やカテゴリにリンク、言及した Blog がこの Trackback URL に対し、上述のような HTTP POST リクエストを送信します。
ここで紹介したように、Trackback の主な利用目的は、「リンクしたよ」とか、「同じイベントにいった感想を書いたよ」という通知といえますが、他にも
- 複数の Blog サイトの特定カテゴリのエントリを集約する
- PhotoFriday や FridayFive のような、アンケートなどの結果集積所
といったような利用方法が考えられます。実際、Movable Type では、「特定のカテゴリにエントリを記述した際に、関連づいた Trackback URL に Ping を送信する」という設定を行うことができるようになっています。
サンプルコード
Trackback を送信するための簡易フォームつき CGI スクリプトを記述すると、List 1 のようになります。
use CGI;
use HTTP::Request::Common;
use LWP::UserAgent;
使用するモジュールを use します。CGI スクリプトとして起動するため、CGI.pm を使用しています。
my $query = CGI->new();
$query->charset('utf-8');
CGI オブジェクトを new し、charset
メソッドで文字コードを UTF-8 としています。Trackback の文字コードについては、実際の Trackback規格仕様書では対応方法が記述されておらず、日本語のように複数の文字エンコーディングを持つ言語での対応が若干混乱しています。執筆時点では、
- 送る文字コードは UTF-8 推奨
- 送信する際に
charset
パラメータでエンコーディングを指定
- 受け取り側は
charset
からデコード。ない場合は自動判定を試みる
というのが国内の各種 Blog ツールのラフコンセンサスとなっていますので、ここでは UTF-8 で送信することにします。TypePad のようなホスティングサービスでも、UTF-8 で Ping を送れば文字化けすることはないようです。
my $mode = $query->param('mode');
if ($mode && $mode eq 'form') {
show_ping_form($query);
CGI の mode パラメータを受けとり、form であれば、送信するためのフォームを表示する show_ping_form
を呼び出します。
} else {
my $v = $query->Vars();
if ($v->{ping_url} && $v->{title} && $v->{url}) {
my $message = send_ping($v);
show_ping_form($query, $message);
} else {
show_ping_form($query, "invalid parameters");
}
}
mode がない場合には、Ping 送信モードになります。パラメータ ping_url
, title
, url
が指定されているかチェックし、問題なければ send_ping
により Trackback Ping を送信します。送信した結果は $message
に格納されるので、フォームと同時に画面に出力します。
パラメータに不備がある場合も、その旨メッセージがフォームとともに表示されます。
sub show_ping_form {
my($query, $message) = @_;
$message ||= '';
print $query->header, <<HTML;
<html>
<body>
$message
<form>
Ping URL: <input type="text" name="ping_url" size="30" /><br />
Title: <input type="text" name="title" size="30" /><br />
Blogname: <input type="text" name="blog_name" size="30" /><br />
Blog URL: <input type="text" name="url" size="30" /><br />
Excerpt: <input type="text" name="excerpt" size="50" /><br />
<input type="submit" value="Send" />
</form>
</body></html>
HTML
;
}
Trackback を送信するための簡易フォームを表示します。
sub send_ping {
my $v = shift;
my $ua = LWP::UserAgent->new();
$ua->agent("tb_send/1.0");
my $req = POST $v->{ping_url}, [
title => $v->{title},
url => $v->{url},
blog_name => $v->{blog_name},
excerpt => $v->{excerpt},
charset => 'utf-8',
];
my $response = $ua->request($req);
unless ($response->is_success) {
return "HTTP error: " . $response->status_line;
}
$response->content =~ m!<error>(\d+).*<message>(.+?)</message>!s;
return $1 ? "Error: $2" : "Ping to $v->{ping_url} successful";
}
send_ping
では、LWP::UserAgent オブジェクトを生成、CGI パラメータから POST リクエストを作成して、request
メソッドによりリクエストを送信します。先述したように、charset
パラメータに utf-8 をセットしていることに注意してください。
HTTP レスポンスがエラーであった場合には、ステータス行とともに return します。HTTP レスポンス自体が成功した場合は、返り値の XML 内の error
属性の値を調べ、1 であった場合にはエラー、0 であった場合には Ping 成功として表示します(*3)
実行例
このスクリプトを、CGI 実行可能なパスに設置し、ブラウザから .../tb_send.cgi?mode=form
として呼び出してみましょう。
このようなフォームが表示されます。一番上の Ping URL に、Trackback Ping 先の URL (mt-tb.cgi/1234
など)、以下の4つには、Ping 元となるエントリ(通常は自分の Blog エントリでの記述内容) を入力し、Send のボタンを押します。
Ping が成功すれば、
Ping to http://example.com/tb.cgi successful.
失敗した場合には、
HTTP error: 500 Internal Server Error.
といったメッセージが表示されます。
Hack the Hacks
Trackback のリファレンス実装である tb-standalone が MovableType サイト内でオープンソースで公開されています。このツールの中にも、Trackback を送信するモードが用意されていますそのままでは日本語に対応していません。筆者の Blog で日本語対応版を公開しています。
CPAN モジュール Net::TrackBack は、リファレンス実装をモジュール化して使いやすくしたものです。
No Host Trackback のように、Trackback に対応していない Blog ツール向けのホスティングサービスも用意されています。
今回用意したスクリプトを、誰でもアクセスできる場所に置くと、Trackback SPAM の踏み台にされる可能性もありますので、注意しましょう。
Listings
#!/usr/local/bin/perl -w
# tb_send - Send Trackback Ping
use strict;
use CGI;
use HTTP::Request::Common;
use LWP::UserAgent;
my $query = CGI->new();
$query->charset('utf-8');
my $mode = $query->param('mode');
if ($mode && $mode eq 'form') {
show_ping_form($query);
} else {
my $v = $query->Vars();
if ($v->{ping_url} && $v->{title} && $v->{url}) {
my $message = send_ping($v);
show_ping_form($query, $message);
} else {
show_ping_form($query, "invalid parameters");
}
}
sub show_ping_form {
my($query, $message) = @_;
$message ||= '';
print $query->header, <<HTML;
<html>
<body>
$message
<form>
Ping URL: <input type="text" name="ping_url" size="30" /><br />
Title: <input type="text" name="title" size="30" /><br />
Blogname: <input type="text" name="blog_name" size="30" /><br />
Blog URL: <input type="text" name="url" size="30" /><br />
Excerpt: <input type="text" name="excerpt" size="50" /><br />
<input type="submit" value="Send" />
</form>
</body></html>
HTML
;
}
sub send_ping {
my $v = shift;
my $ua = LWP::UserAgent->new();
$ua->agent("tb_send/1.0");
my $req = POST $v->{ping_url}, [
title => $v->{title},
url => $v->{url},
blog_name => $v->{blog_name},
excerpt => $v->{excerpt},
charset => 'utf-8',
];
my $response = $ua->request($req);
unless ($response->is_success) {
return "HTTP error: " . $response->status_line;
}
$response->content =~ m!<error>(\d+).*<message>(.+?)</message>!s;
return $1 ? "Error: $2" : "Ping to $v->{ping_url} successful";
}
Copyright©2002-2003 Tatsuhiko Miyagawa