で、案の定先ほどの記事をポストした際にASIN書いたら見事に記事が壊れて泣くハメに...
ええいと重い腰を上げて修正してみました。
修正方法はhail2uさんが書いた物をベースに修正しました。
あまりawxsomの原形を留めていないので修正後のファイルで...
#!/usr/bin/perl
# ---------------------------------------------------------------------
# awsxom: AWSからデータを取得して書影その他を作成(ECS v4対応版)
# Author: Fukazawa Tsuyoshi <tsuyoshi.fukazawa@gmail.com>
# Version: 2006-11-24
# http://fukaz55.main.jp/
# Modified: Yasuhiro Matsumoto <mattn.jp@gmail.com>
# ---------------------------------------------------------------------
package awsxom;
use strict;
use LWP::UserAgent;
use CGI qw/:standard/;
use FileHandle;
use URI::Escape;
use Digest::SHA::PurePerl qw(hmac_sha256_base64);
# --- Plug-in package variables --------
my $asoid = "XXXXXX-22"; # AmazonアソシエイトID
my $devkey = "XXXXXXXXXXXXXXXXXXXX"; # デベロッパートークン
my $secret = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; # シークレットキー
my $cachedir = "$blosxom::plugin_state_dir/aws_cache"; # XMLのキャッシュ用ディレクトリ
my $EXPIRE = 24 * 7; # データを再読込する間隔(単位:時間)
my $default_template = "awsxom"; # デフォルトのテンプレートファイル名
my $VERSION = '1.4';
my $ua_name = "awsxom $VERSION";
my $endpoint = "ecs.amazonaws.jp";
my $unsafe = "^A-Za-z0-9\-_.~";
my $debug_mode = 0;
# ---------------------------------------------------------------------
sub start {
# キャッシュ用ディレクトリの作成
if (!-e $cachedir) {
my $mkdir_r = mkdir($cachedir, 0755);
warn $mkdir_r
? "blosxom : aws plugin > \$cachedir, $cachedir, created.\n"
: "blosxom : aws plugin > mkdir missed:$!";
$mkdir_r or return 0;
}
1;
}
# ---------------------------------------------------------------------
sub story {
my ($pkg, $path, $filename, $story_ref, $title_ref, $body_ref) = @_;
$$body_ref = conv($$body_ref);
1;
}
# ---------------------------------------------------------------------
sub foot {
my($pkg, $currentdir, $foot_ref) = @_;
$$foot_ref = conv($$foot_ref);
1;
}
# ---------------------------------------------------------------------
sub conv {
$_ = shift;
# ASIN/ISBNが書かれていたら置き換える
# テンプレート指定版
s/(?:ASIN|ISBN):([A-Z0-9]{10}):(.*?):/to_html_asin($1,$2)/ge;
# テンプレート無指定版
s/(?:ASIN|ISBN):([A-Z0-9]{10})/to_html_asin($1,$default_template)/ge;
# テンプレート無指定版
s/(?:AWSWORD):([a-zA-Z0-9_]*?):/to_html_word($1,$default_template)/ge;
return $_;
}
# ---------------------------------------------------------------------
# ASINからAmazonのアフィリエイト用HTMLを作成
sub to_html_asin {
my ($asin, $template) = @_; # ASINとテンプレ名称
my $cache = "$cachedir/$asin.xml";
my $outfile = "$cachedir/$asin.html";
my $q = CGI->new;
$q->param("AWSAccessKeyId", $devkey);
$q->param("AssociateTag", $asoid);
$q->param("Timestamp", sprintf("%04d-%02d-%02dT%02d:%02d:%02d.000Z", sub { ($_[5]+1900, $_[4]+1, $_[3], $_[2], $_[1], $_[0] ) }->(gmtime(time))));
$q->param("Service", "AWSECommerceService");
$q->param("Operation", "ItemLookup");
$q->param("ItemId", $asin);
$q->param("ResponseGroup", "Medium,Offers");
$q->param("Version", "2009-01-06");
my @p = $q->param();
foreach (@p) {
$_ = escape($_) . "=" . escape($q->param($_));
}
my $qs = join("&", sort(@p));
my $signature = hmac_sha256_base64("GET\n$endpoint\n/onca/xml\n$qs", $secret) . "=";
my $url = "http://$endpoint/onca/xml?$qs&Signature=" . escape($signature);
# 取り込み直す必要はあるか?
if (!(-e $cache) || (-M $cache > ($EXPIRE / 24))) {
# AWSから情報を取得してキャッシュファイルに保存
# UserAgent初期化
my $ua = new LWP::UserAgent;
$ua->agent($ua_name);
$ua->timeout(60);
my $rtn = $ua->mirror($url, $cache);
}
# キャッシュからXMLを読み込んで解析
my $content = getFile($cache);
my %detail = parseXML($content, $asin);
# テンプレートを展開。エラーの場合はエラー文字列を返す
my $form;
if (!defined($detail{"ErrorMsg"})) {
#$form = &$blosxom::template($blosxom::path, $template, 'html');
my $fh = new FileHandle;
if ($fh->open("< $blosxom::datadir/$template.html")) {
$form = join '', <$fh>;
$form =~ s/\$(\w+)/$detail{$1}/ge;
$fh->close();
}
}
else {
$form = "<p>" . $detail{"ErrorMsg"} . "</p>";
}
return $form;
}
# ---------------------------------------------------------------------
# ASINからAmazonのアフィリエイト用HTMLを作成
sub to_html_word {
my ($word, $template) = @_; # ASINとテンプレ名称
my $cache = "$cachedir/$word.xml";
my $outfile = "$cachedir/$word.html";
my $q = CGI->new;
$q->param("AWSAccessKeyId", $devkey);
$q->param("AssociateTag", $asoid);
$q->param("Timestamp", sprintf("%04d-%02d-%02dT%02d:%02d:%02d.000Z", sub { ($_[5]+1900, $_[4]+1, $_[3], $_[2], $_[1], $_[0] ) }->(gmtime(time))));
$q->param("Service", "AWSECommerceService");
$q->param("Operation", "ItemSearch");
$q->param("Keywords", $word);
$q->param("SearchIndex", "Books");
$q->param("ResponseGroup", "Medium,Offers");
$q->param("Version", "2009-01-06");
my @p = $q->param();
foreach (@p) {
$_ = escape($_) . "=" . escape($q->param($_));
}
my $qs = join("&", sort(@p));
my $signature = hmac_sha256_base64("GET\n$endpoint\n/onca/xml\n$qs", $secret) . "=";
my $url = "http://$endpoint/onca/xml?$qs&Signature=" . escape($signature);
# 取り込み直す必要はあるか?
if (!(-e $cache) || (-M $cache > ($EXPIRE / 24))) {
# AWSから情報を取得してキャッシュファイルに保存
# UserAgent初期化
my $ua = new LWP::UserAgent;
$ua->agent($ua_name);
$ua->timeout(60);
my $rtn = $ua->mirror($url, $cache);
}
# キャッシュからXMLを読み込んで解析
my $content = getFile($cache);
$content =~ s!.*?(<Item>.*?</Item>).*!$1!is;
my $asin = "";
$asin = $1 if ($content =~ /<ASIN>([^<]*)<\/ASIN>/);
return "" if !$asin;
my %detail = parseXML($content, $asin);
# テンプレートを展開。エラーの場合はエラー文字列を返す
my $form;
if (!defined($detail{"ErrorMsg"})) {
#$form = &$blosxom::template($blosxom::path, $template, 'html');
my $fh = new FileHandle;
if ($fh->open("< $blosxom::datadir/$template.html")) {
$form = join '', <$fh>;
$form =~ s/\$(\w+)/$detail{$1}/ge;
$fh->close();
}
}
else {
$form = "<p>" . $detail{"ErrorMsg"} . "</p>";
}
return $form;
}
# ---------------------------------------------------------------------
# ファイルを読み込む
sub getFile {
my $cache = shift;
my $fh = new FileHandle;
$fh->open($cache);
my @data = <$fh>;
$fh->close();
my $content = join('', @data);
return undef if (!$content);
return $content;
}
# ---------------------------------------------------------------------
sub parseXML {
my ($buf, $asin) = @_;
my %detail;
# Amazonへのリンク
$detail{"Link"} = "http://www.amazon.co.jp/exec/obidos/ASIN/$asin/ref=nosim/$asoid";
# 個々の要素の抽出
$detail{"Asin"} = $1 if ($buf =~ /<ASIN>([^<]*)<\/ASIN>/);
$detail{"ProductName"} = $1 if ($buf =~ /<Title>([^<]*)<\/Title>/);
$detail{"Catalog"} = $1 if ($buf =~ /<Binding>([^<]*)<\/Binding>/);
$detail{"ReleaseDate"} = $1 if ($buf =~ /<PublicationDate>([^<]*)<\/PublicationDate>/);
$detail{"ReleaseDate"} = $1 if ($buf =~ /<ReleaseDate>([^<]*)<\/ReleaseDate>/);
$detail{"Manufacturer"} = $1 if ($buf =~ /<Manufacturer>([^<]*)<\/Manufacturer>/);
$detail{"ImageUrlSmall"} = $1 if ($buf =~ /<SmallImage>[^<]*?<URL>([^<]*)<\/URL>/);
$detail{"ImageUrlMedium"} = $1 if ($buf =~ /<MediumImage>[^<]*?<URL>([^<]*)<\/URL>/);
$detail{"ImageUrlLarge"} = $1 if ($buf =~ /<LargeImage>[^<]*?<URL>([^<]*)<\/URL>/);
$detail{"Availability"} = $1 if ($buf =~ /<Availability>([^<]*)<\/Availability>/);
$detail{"ListPrice"} = $1 if ($buf =~ /<LowestNewPrice>.*?<FormattedPrice>([^<]*)<\/FormattedPrice>/);
$detail{"OurPrice"} = $1 if ($buf =~ /<ListPrice>.*?<FormattedPrice>([^<]*)<\/FormattedPrice>/);
$detail{"UsedPrice"} = $1 if ($buf =~ /<LowestUsedPrice>.*?<FormattedPrice>([^<]*)<\/FormattedPrice>/);
$detail{"Author"} = $1 if ($buf =~ /<Author>([^<]*)<\/Author>/);
# エラー?
if ($buf =~ /<Errors>.*?<Message>([^<]*)<\/Message>/) {
$detail{"ErrorMsg"} = $1;
}
return %detail;
}
# ---------------------------------------------------------------------
# デバッグ用
sub print_debug {
return if (!$debug_mode);
my $fd = new FileHandle;
$fd->open("/path/to/log/output/directory/logfile.log", "a");
print $fd "$_[0]";
$fd->close();
}
sub escape {
my $s = shift;
$s =~ s/([^\0-\x7F])/do {
my $o = ord($1);
sprintf("%c%c", 0xc0 | ($o >> 6), 0x80 | ($o & 0x3f));
}/ge;
return uri_escape($s, $unsafe);
}
1;
ちなみに、オリジナルに追加した機能は「AWSWORD:perl」と書くとItemSearch結果の1番目を表示する...というモノグサ機能です。