トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS

blosxom/bracket_fep plug-in

bsnap_asin plug-in

ダウンロード filebsnap_asin20090718.zip

 bracket_fep プラグイン 専用としてインプリメントし直した asin_complex プラグイン 相当の bfep です。

 ただし、asin_complex プラグイン と違って、asin プラグイン 相当の機能は有していませんので、この機能が必要な場合は jasin プラグイン を併用いただくようお願いします。

注意事項

 このプラグインは、bracket_fep プラグイン 専用のプラグイン (bfep) で、単体では使用できません。

 bracket_fep プラグイン が未導入の場合は、そちらを先にご導入いただきますようお願いします。

開発ログ

Feb 7, 2009

  • 初期リリース

Jul 18, 2009


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 でアクセスされるディレクトリにアップロードしてください。

リンク集



*1 プラグイン起動時になければ自動的に作成されます
添付ファイル: filebsnap_asin20090718.zip 161件 [詳細] filebsnapasin20090207.zip 160件 [詳細]

© 2004-2010 Ellinikonblue.com All Rights Reserved.