bsnap_asin plug-in †
bracket_fep プラグイン 専用としてインプリメントし直した asin_complex プラグイン 相当の bfep です。
ただし、asin_complex プラグイン と違って、asin プラグイン 相当の機能は有していませんので、この機能が必要な場合は jasin プラグイン を併用いただくようお願いします。
注意事項 †
このプラグインは、bracket_fep プラグイン 専用のプラグイン (bfep) で、単体では使用できません。
bracket_fep プラグイン が未導入の場合は、そちらを先にご導入いただきますようお願いします。
開発ログ †
Feb 7, 2009
- 初期リリース
Jul 18, 2009
- Product Advertising API 対応版
- コード一部見直し
Jul 18, 2009 版全ソース
# Bracket Front End Plugin for blosxom: bsnap_asin
# Author(s) : kay <info@ellinikonblue.com>
# Version : 2009 Jun.
package bsnap_asin;
# --------------------------------------
# Configurable Variable
my $associatetag = "YourAssociateTag"; # Associate Tag
my $subscriptionid = "YourSubscriptionID"; # Subscription ID
my $secretkey = "YourSecretKey"; # Secret Key
my $xslfile = "http://yourdomain.net/path/bsnap_asin.xsl";
# Cache Configuration
my $asin_dir = "$blosxom::plugin_state_dir/asin";
my $modify = "24";
# Path to no image
my $noImage = "http://yourdomain.net/path/no-image.png";
my $noImageHeight = "130";
my $noImageWidth = "130";
# --------------------------------------
# Base URL
my $requesturl = "http://xml-jp.amznxslt.com/onca/xml"; # for Amazon.co.jp
# Constant value for deadlock routine
my $LockName = "$asin_dir/Locked";
my $retry = 10;
# for debug
my $dbsw = 0; # Switch for Debug (0: off, 1: on)
# ======================================
# use lib '/your/perl/library/path'; # for PurePerl SHA.pm
#
use LWP::Simple;
use LWP::UserAgent;
use Digest::SHA qw(hmac_sha256_base64);
# use Digest::SHA::PurePerl qw(hmac_sha256_base64); # for PurePerl SHA.pm
use URI::Escape;
sub start {
if (!-e $asin_dir) {
my $mkdir_r = mkdir($asin_dir, 0755) or die "Can't creat $asin_dir : $1";
$mkdir_r or return 0;
}
return 1;
}
sub story {
my ($pkg, $pattern) = @_;
return 0 if ( $pattern !~ m/^asin:([A-Z0-9]{10})$/is );
return requestAWS( $1 );
}
sub requestAWS { # SubRoutine to request to AWS
my ($asinCode) = @_;
my $cache = "$asin_dir/$asinCode.html";
my $rtn = "";
# ロック処理待ち
## ロック処理に対する待ち処理、またロックしたままになって
## 180 秒以上経過しているものはロックを解除
if ( -e "$LockName$asinCode" ) {
my $r = $retry;
if ( (stat("$LockName$asinCode"))[8] + 180 < time() ) {
# ロックファイルのクリーニング
rmdir( "$LockName$asinCode" );
} else {
while ( -e "$LockName$asinCode" and $r-- > 0 ) { sleep( 1 ) };
return $rtn if ( $r < 1 ); # 待ちきれなかった場合は終了
}
}
# キャッシュ更新判定
## キャッシュは新規作成のときでも空ファイルを作成して、
## 既存キャッシュと同じアルゴリズムで作成するとともに、
## 連続して AWS にリクエストがかからないようにする
if ( -e $cache ) {
if ( -M $cache > $modify /24 ) {
my $time = time;
utime( $time, $time, $cache ); # ひとまずキャッシュの更新時間を更新
refresh_cache( $asinCode, $cache );
}
} else { # 新規キャッシュ作成
close CACHE if ( open CACHE, "> $cache" ); # 空ファイルを作成
refresh_cache( $asinCode, $cache );
}
# キャッシュから読み込み
if ( open CACHE, "< $cache" ) {
$rtn = join( '', <CACHE> );
$rtn = '<div class="asinSimple">' . $rtn . '</div>';
close CACHE;
}
return $rtn;
}
sub refresh_cache { # キャッシュ更新ルーチン本体
my ( $asinCode, $cache_file ) = @_;
my $tmp_file = "$asin_dir/$asinCode.tmp";
my $debuf = '';
my $rtn = '';
my $url = "s?https?://[-_.!~*'()a-zA-Z0-9;/?:@&=+$,%#]+";
my ( $sec, $min, $hour, $mday, $mon, $year ) = gmtime(time);
$mon = $mon + 1; $year = $year + 1900;
my $timestamp = sprintf( "%04d-%02d-%02dT%02d:%02d:%02dZ",
$year, $mon, $mday, $hour, $min, $sec );
my %param = ( # Signature 作成用パラメータ
AWSAccessKeyId => $subscriptionid,
AssociateTag => $associatetag,
ContentType => 'text/html',
ItemId => $asinCode,
Operation => 'ItemLookup',
ResponseGroup => 'Medium',
Service => 'AWSECommerceService',
Style => $xslfile,
Timestamp => $timestamp,
Version => '2005-07-26' );
my $request = join '&',
map { $_.'='.URI::Escape::uri_escape_utf8( $param{ $_ } ) } sort keys %param;
# Signature を生成
my $u = URI->new( $requesturl );
my $signature = join "\n",'GET', $u->host, $u->path, $request;
$debuf .= $signature."\n" if ( $dbsw ); # for debug
$signature = hmac_sha256_base64( $signature, $secretkey );
$signature .= '=' while length( $signature ) % 4; # Sign 長が 4 の倍数でないときは = を足し込む
$debuf .= "Signature: $signature\n" if ( $dbsw ); # for debug
$signature = URI::Escape::uri_escape_utf8( $signature ); # URI エスケープして Signature 完成
# 生成した Signature を末尾に付け足してリクエスト URL を生成
$request = $requesturl.'?'.$request.'&Signature='.$signature;
$debuf .= "Request: $request\n" if ( $dbsw ); # for debug
# AWS にリクエストして結果をテンポラリに出力
my $ua = new LWP::UserAgent;
$ua->agent("bsnap_asin");
$ua->timeout(30);
my $r = $ua->mirror($request, $tmp_file);
if ( $dbsw and open DEBUG, "> $asin_dir/debug.dmp" ) { # for debug
$debuf .= 'Response: '.$r->status_line."\n";
print DEBUG $debuf;
close DEBUG;
}
if ( (stat($tmp_file))[7] > 3000 ) { # 極端に大きい応答が帰ってきた場合は無視
unlink( $tmp_file );
return 0;
}
# テンポラリに出力されたデータをコンバージョン
if ( open CACHE, "< $tmp_file" ) {
while ( <CACHE> ) {
if ( /<img\s+src="(.*?)"\s*\/?>/ ) { # 取得した画像の有効性判定
my $imgsrc = $1;
my $convtag = '<img src="' . $noImage . '" ' .
'height="' . $noImageHeight . 'px" ' .
'width="' . $noImageWidth . 'px" />';
if ( $imgsrc =~ /$url/ ) {
my $header;
my $r = $retry;
while ( $r-- > 0 ) {
last if ( $header = head( $imgsrc ) );
sleep(5);
}
if ( $header && $header->content_length > 820 ) {
# Image file less 820bytes is "No Image".
$convtag = '<img src="' . $imgsrc . '" />';
}
} else {
return 0;
}
$_ =~ s/<img\s+src=".*?"\s*\/?>/$convtag/gs;
}
$_ =~ s/<br>/<br \/>/gs; # for HTML 1.0
$rtn .= $_;
}
close CACHE;
# コンバージョンしたデータをテンポラリに書き出し
if ( open CACHE, "> $tmp_file" ) {
print CACHE $rtn;
close CACHE;
}
# テンポラリデータを実際のキャッシュファイルにリネーム
mkdir( "$LockName$asinCode", 0755 ); # キャッシュ書き出しロック
if ( unlink( $cache_file ) ) {
rename( $tmp_file, $cache_file );
}
rmdir( "$LockName$asinCode" ); # キャッシュロック解除
}
return 1;
}
1;
導入 †
このプラグインの利用にあたっては Digest::SHA モジュールがサーバ側にインストールされている必要があります。このモジュールがインストールされていないとき、もしくはインストールしてもうまく動作しない場合は、Perl のみで動作するDigest::SHA::PurePerl をインストールしてください。
その際、プラグイン本体のライブラリパスの追加、モジュールの読み込み指定部分は環境によって書き換えてください。
プラグイン本体の編集 †
以下の変数を必要に応じて書き換えてください。
- $associatetag
- Amazon アソシエイト に登録すると取得できるトラッキング ID を指定します。
- $subscriptionid
- Product Advertising API で取得できる Access Key ID を指定します。
- $secretkey
- Product Advertising API で取得できる Secret Access Key を指定します。
- $xslfile
- XSL スタイルシートの設置場所を URL で指定します。スタイルシートの作成にあたってはダウンロードファイルに同梱されているスタイルシートファイルを参考にしてください。
- $asin_dir
- キャッシュを保存するディレクトリを指定します。初期値は blosxom の plugin_state_dir で指定されるディレクトリ以下の asin ディレクトリ*1。問題がなければ通常変更する必要はありません。
- $modify
- キャッシュの更新頻度を指定します。初期値は 24 ( 1 日)です。問題がなければ変更する必要はありません。
- $noImage
- 商品画像が登録されていないとき、もしくは画像の取得に失敗したときに使用する画像を指定します。URL で指定してください。
- $noImageHeight
- $noImage で指定した画像の高さを指定します。
- $noImageWidth
- $noImage で指定した画像の幅を指定します。
アップロード †
プラグイン本体ファイルの編集が終了したら、bfep プラグインディレクトリにアップロードしてください。また併せて XSL スタイルシートも上記 $xslfile でアクセスされるディレクトリにアップロードしてください。