Amazon APIのRequestへの電子署名添付(PHP版)

June 24, 2009 – 4:16 pm

この5月から「AmazonアソシエイトWebサービス」が「Product Advertising API」に変更されること、そして来る8月からはAPIを用いた商品データベースにアクセスする際には電子署名が必要になるとの案内が届いた。我が方も、これに対応するため、簡単なPHP関数を作成した。このエントリーでは、今回作成したPHP関数と、これを用いた従来のコードの修正方法についてメモした。

電子署名添付の手続きその他は、
http://docs.amazonwebservices.com/AWSECommerceService/latest/DG/
に記述されている。このうち、RESTを用いたRequestについては、このなかのExample REST Requestsにおいて、電子署名を付加するための手順がステップ・バイ・ステップでしめされている。今回、私が作成したコードは、この手順に、できる限り忠実に従ったつもりである。

PHP関数の作成: 今回作成したPHP関数は、canonical_Str()とget_Signature()の二つだ。Canonical_Str()では、認証用Signatureを得るためにRequestの前処理を行う。get_Signature()では、処理済のRequest等を用いて、Signatureを求めている。

なお、今回用いたphpのバージョンは、5.2.9である。

この二つの関数は、以下の通り:

function canonical_Str( $request ) {

   $request = str_replace( ',', '%2C', $request );
   $request = str_replace( ':', '%3A', $request );
   $request = str_replace( '%7E', '~', $request );

   $req_split = array();
   $req_split = split("&", $request);
   sort( $req_split );

   $str_join = implode('&', $req_split );
   return $str_join;
}

function get_Signature( $request, $aws_host ) {

   $key = "Your Secret Key is placed here";

   $prep01 = 'GET';
   $prep02 = $aws_host;
   $prep03 = '/onca/xml';
   $str_to_sign = $prep01 . "\n" . $prep02 . "\n" . $prep03 . "\n". $request;

   $algo = "sha256";
   $hash_out  = hash_hmac( $algo, $str_to_sign, $key, true );
   $signature = urlencode(base64_encode($hash_out));
   return $signature;
}

従来コード修正の具体例: 昨年9月に、「アマゾンの書籍データにphpでアクセスしてみた」を書いた。ここでアマゾンの書籍データを取得するために用いた「Request」に対し、上記のPHP関数を使用すると電子署名がどのように付加されるかを示す。

従来方式に対応するRequest(URLストリング)の指定部分:

 $request="http://ecs.amazonaws.jp/onca/xml?Service=AWSECommerceService&AWSAcce
ssKeyId=xxxxxxxxxxxxxxxxxxxx&AssociateTag=yyyyyyyyyyyyyyyy&Version=2006-09-11&
Operation=ItemLookup&ResponseGroup=Large,Offers&SearchIndex=Books&IdType=ISBN&
ItemId=4152085576&ItemPage=1";

を、以下に置き換える:

$aws_host ="ecs.amazonaws.jp";
$request  ="Service=AWSECommerceService&AWSAccessKeyId=xxxxxxxxxxxxxxx&Associa
teTag=yyyyyyyyyyyy&Version=2006-09-11&Operation=ItemLookup&ResponseGroup=Large,
Offers&SearchIndex=Books&IdType=ISBN&ItemId=4152085576&ItemPage=1";

$request .="&Timestamp=".str_replace('GMT','T',gmdate("Y-m-dTH:i:s"))."Z";
$request   = canonical_Str( $request );
$signature = get_Signature( $request, $aws_host );
$request = "http://".$aws_host."/onca/xml?".$request."&Signature=".$signature;

参考のため、以下に書籍データ取得に際して用いたコードの全体、ならびに出力を示しておく:

sample.php:

<?php
   function canonical_Str( $request ) {
      $request = str_replace( ',', '%2C', $request );
      $request = str_replace( ':', '%3A', $request );
      $request = str_replace( '%7E', '~', $request );

      $req_split = array();
      $req_split = split("&", $request);
      sort( $req_split );

      $str_join = implode('&', $req_split );
      return $str_join;
  }

  function get_Signature( $request, $aws_host ) {

      $key = "Your Secret Key is placed here";

      $prep01 = 'GET';
      $prep02 = $aws_host;
      $prep03 = '/onca/xml';
      $str_to_sign = $prep01 . "\n" . $prep02 . "\n" . $prep03 . "\n". $request;

      $algo = "sha256";
      $hash_out  = hash_hmac( $algo, $str_to_sign, $key, true );
      $signature = urlencode(base64_encode($hash_out));

      return $signature;
  }

  $aws_host    ="ecs.amazonaws.jp";
  $request     ="Service=AWSECommerceService&AWSAccessKeyId=xxxxxxxxxxxxxxxxxxxx&Assoc
  iateTag=yyyyyyyyyyyyyyyy&Version=2006-09-11&Operation=ItemLookup&ResponseGroup=Large
  ,Offers&SearchIndex=Books&IdType=ISBN&ItemId=4152085576&ItemPage=1";
  $request    .= "&Timestamp=" . str_replace('GMT','T',gmdate("Y-m-dTH:i:s")) . "Z";
  $request   = canonical_Str( $request );
  $signature = get_Signature( $request, $aws_host );
  $request = "http://".$aws_host."/onca/xml?".$request."&Signature=". $signature;

  $response = file_get_contents($request);
  $parsed_xml = simplexml_load_string($response);

  $Image_URL    = $parsed_xml->Items->Item->MediumImage->URL;
  $Title        = $parsed_xml->Items->Item->ItemAttributes->Title;
  $Author       = $parsed_xml->Items->Item->ItemAttributes->Author;
  $Creator      = $parsed_xml->Items->Item->ItemAttributes->Creator;
  $Creator_Role = $parsed_xml->Items->Item->ItemAttributes->Creator['Role'];
  $Publ_date    = $parsed_xml->Items->Item->ItemAttributes->PublicationDate;

  echo $Title . "written by " . $Author . "\n";
  echo "              translated by " . $Creator . "/" . $Creator['Role'] . "\n";
  echo "              publised on " . $Publ_date . "\n";
?>

実行例:

  $ php sample.php
  盲目の時計職人written by リチャード・ドーキンス
                translated by 日高 敏隆/翻訳
                publised on 2004-03-24

  1. 2 Responses to “Amazon APIのRequestへの電子署名添付(PHP版)”

  2. OperationのパラメータをItemSearchとし、商品名などを日本語(文字コード:UTF-8)で指定した場合、Signatureが正しく導出されないという問題が発生している。
    原因を検討中。
    なお、英文(アルファベット)のみの場合は、問題なく動作する。
    検討の結果: 日本語文字がクエリに含まれる場合には、これをurlencodeしておかなければならない。このあたりを満足するためのコードは別エントリーにて説明予定。

    By yama on Jun 29, 2009

  1. 1 Trackback(s)

  2. Jul 1, 2009: アマゾンAPIの電子署名添付:日本語文字をURL-Encodeしておくことが必須 | Yama's Memorandum

Post a Comment