5月11日からスタートする Amazon Product Advertising API (旧称 Amazon Web Services / アマゾン アソシエイト Web サービス)は、移行期間3ヶ月の後、8月15日から認証のための電子署名付きリクエストが必須となる。アマゾンアフィリエイトWebサービスを使っている人は、認証付きリクエストを発行できるように、プログラムを改修する必要がある。ここでは、PHPを使って、電子署名付きリクエストを作成・送信する方法について解説する。
(5/11 13:00 完全版をアップしました)
(5/11 22:30 ver 0.2 をアップしました。Timestampに関するバグを修正しました。必ずアップデートしてください。)
(5/12 23:00 ver 0.3 をアップしました。複数リクエスト(バッチリクエスト)の場合に、ピリオドがアンダースコアに置換される問題を修正しました。)
(5/16 ver 0.4 をアップしました。連想配列の指定でエラーが出る問題を修正しました。)
0. 手っ取り早く対応したい人向け
0.1 準備
↓の「2. 準備」を参考に、「Secret Access Key」を取得して、「PECL hash」のインストールを確認してください。
0.2 ダウンロード
http://amazon.ringoon.jp/rest_test/pa_sig.txt をダウンロードして、拡張子をphpに変えてください。ライセンスは クリエイティブ・コモンズ 表示 2.1 日本 です。改変・再配布・商用利用が可能です。
0.3 プログラムの改良
0.3.1 Secret Access Keyの変更
pa_sig.phpの "Your Secret Access Key" のところを、自分の「Secret Access Key」に変更してください。
0.3.2 従来のプログラムの改修
http://amazon.ringoon.jp/rest_test/pa_sig_test.txt を参考に、従来のプログラムを改修してください。
- includeする
- リクエストURLに add_signature($url) で署名を付加する
という2点だけです。
1. 全体的な流れ
◆Basic Authentication Process
(電子署名付きリクエストの作成手順)
◆Example REST Requests
(電子署名付きリクエストの例)
流れとしては、
- (従来の)リクエストを、整形する。
- パラメータとしてTimestampが追加された(必須。Timestampから時間が経っているとexpireされる)
- パラメータをソートする。大文字のアルファベット順→小文字のアルファベット順の順番
- パラメータをURLエンコードする(RFC 3986)。カンマ、コロン、セミコロンを変換する。PHPなら rawurlencode() などで。
- 整形したリクエストを元に、署名原文を作る。
- 「Your Secret Access Key」を使って、SHA-256なHMAC(RFC 2104)で署名を得る。
- 従来のリクエストの最後に、パラメータ「Signature」として署名を追加して、リクエストを送る。
2. 準備
2.1 Secret Access Key の取得
電子署名の暗号化の鍵として、Amazon が発行する「Your Secret Access Key」を使う。「Your Secret Access Key」は、Amazon Web Servicesのホームページ(http://aws.amazon.com/)にアクセス・ログインし、「Your Account」から「Access Identifiers」を見ると書かれている。
2.2 PECL hash がインストールされているか確認
Amazon Product Advertising API では、SHA-256をハッシュ関数としたHMACを電子署名として採用している。PHPで、HMACを生成するには、 hash_hmac を使うのが簡単で良いが、サーバに PECL hash という追加モジュールがインストールされていなければならない。
以下のようなサンプルプログラムをサーバで実行してみると、確認できる。
<?php
print( hash_hmac("sha256", "hogehoge", "1234567890") );
?>
もしくは、Amazonのサンプルに沿ったテストコードを、http://amazon.ringoon.jp/rest_test/test.txtに置いたので、ダウンロードし、拡張子をphpに変えて自分のサーバにアップロードしても良い。実行結果は、http://amazon.ringoon.jp/rest_test/test.phpのようになる。なお、RinGoon POP!!はさくらインターネットのレンタルサーバを利用しているが、PECL hashがインストールされていて、何の設定もなく利用できる。
3. プログラム改修のポイント
- リクエストURLを parse_url() で分解する
- クエリ部分を parse_str() で分解する
- このとき、クエリパラメータ中のピリオドがアンダースコアに変換される。複数リクエストを使っている場合は、署名原文を作るときに、変換を戻す必要がある。
- クエリを分解した配列に、TimestampとしてGMTのタイムスタンプを加える。書式が違うとすげー勢いで怒られるので注意。
gmdate("Y-m-d")."T".gmdate("H:i:s")."Z" - クエリを分解した配列を ksort() で昇順ソート
- クエリのデータの方を、 rawurlencode でRFC 3986にエンコード。
- クエリデータをくっつけて、署名原文を作る。 → 署名原文の作り方
- base64_encode( hash_hmac("sha256", $str, $secret_key, "TRUE")
- 最後に、
元のURLに、署名原文として作ったURLに、
&Signature=hogehoge
として付加する
4. 注意点
webservices.amazon.co.jp は、自分の名前を xml-jp.amznxslt.com だと思っているようだ(?)。webservices.amazon.co.jp のままだと署名が違うと怒られる。DNSだと xml-jp.amznxslt.com の方が別名っぽいのに。すぐに対応されると思うが・・・
webservices.amazon.co.jp に対して、XSLTスタイルシートを適用させる電子署名リクエストを送ると、SignatureDoesNotMatchエラーが返ってくる。XSLTを使うには xml-jp.amznxslt.com にリクエストを送ること。- Timestampは必須。
- 現在時刻(GMT)から、ある程度離れた時刻をTimestampで送ると怒られる。URLそのものをキャッシュするような実装の場合は注意が必要。
- XSLTを使っていても、電子署名付きのリクエストを受け付けている。
5. 動作サンプル
9. おまけ
「アパレル」とか「ジュエリー」とか、ItemSearch の SearchIndex がやたらと増えているので、この機会に追加しておくのも良いかもしれない。
◆SearchIndex-ItemSearch Parameter Combinations for JP
(日本のアマゾンのSearchIndex 一覧)
参考にさせていただきました。とてもわかりやすかったです。ありがとうございます。
ただ、複数リクエストの場合"."が"_"に置換されちゃうので多少変更が必要かもしれません。(私の環境だけ?)
例
~~~&Operation=ItemSearch&ItemSearch.1.SearchIndex=Books&ItemSearch.2.SearchIndex=DVD~~~~
↓こうなっちゃう
~~~&Operation=ItemSearch&ItemSearch_1_SearchIndex=Books&ItemSearch_2_SearchIndex=DVD~~~~
imaimaさま、コメントありがとうございます!
調べたところ、ピリオドをアンダースコアに変換するのはPHPの言語仕様でした。今回の場合、 parse_str() で自動的に変換されてしまっているようです。
■PHP: 外部から来る変数 - Manual
http://jp.php.net/manual/ja/language.variables.external.php
Amazon側でどのような文字を使っているのかもう少し調べてから対応したいと思います。
ピリオドがアンダースコアに置換されてしまう問題、ver 0.3で修正いたしました。
貴重な情報をありがとうございました。
Amazon Product Advertising APIでもxsltスタイルシートは
適用できるものなのでしょうか?
新しい電子署名付きリクエストに、今まで利用してきたxsltシートを当ててみたところ、うまく動きませんでした。
「SignatureDoesNotMatch」というCodeが出てしまいます。
kankichiさま、コメントありがとうございます!
Amazon Product Advertising APIでも、XSLTスタイルシートを適用できます。記事中の動作サンプルは、XSLTで表示しています。リクエストURLは以下のようなものです。
http://xml-jp.amznxslt.com/onca/xml?Service=AWSECommerceService&AWSAccessKeyId=00000000000000000000&Version=2008-04-07&Operation=ItemLookup&ItemId=B0021MFB1S&ResponseGroup=Request,Images,ItemAttributes,OfferFull,Reviews&Style=http://amazon.ringoon.jp/af/af.xsl&ContentType=text/html
シグネチャを加えると、以下のようになります。
http://xml-jp.amznxslt.com/onca/xml?AWSAccessKeyId=00000000000000000000&ContentType=text%2Fhtml&ItemId=B001U8ZA1A&Operation=ItemLookup&ResponseGroup=Request%2CImages%2CItemAttributes%2COfferFull%2CReviews&Service=AWSECommerceService&Style=http%3A%2F%2Famazon.ringoon.jp%2Faf%2Faf.xsl&Timestamp=2009-05-13T15%3A25%3A23Z&Version=2008-04-07&Signature=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
ちなみに webservices.amazon.co.jp に対してXSLTの署名付きリクエストを送ると SignatureDoesNotMatch が返ってきます。理由は不明です。私は xml-jp.amznxslt.com を使っています。お試し下さい。
ありがとうございました。
ドメインをxml-jp.amznxslt.comに変更したら、表示されるようになりました。Amazon側で手違いが発生しているのでしょうね。
参考にさせて頂いております。
突然ですが、失礼します。
XAMPPを使用してローカル環境のPHP5でエントリ通りに作業をしているのですが、
「リクエストには、Serviceパラメータが含まれていません。リクエストに Serviceパラメータを追加し、再度リクエストを実行してください。」というエラーが返ってきてしまいます。
urlは、pa_sig.phpを用いて生成した結果、
http://webservices.amazon.co.jp/onca/xml?AWSAccessKeyId=0000000000000000&AssociateTag=00000000-22&Keywords=%E9%80%A0%E5%9C%92%E5%AD%A6%E4%BC%9A&Operation=ItemSearch&Page=1&ResponseGroup=Medium%2CImages&SearchIndex=Blended&Service=AWSECommerceService&Timestamp=2009-07-17T07%3A15%3A03Z&Version=2009-01-06&Signature=i0oiXRleu4G2DpywGmdFOQAsiRZGzh4I1TuCcuCcZtA%3D
という風に表示されており、特にミスをしているようには感じません。(勿論、KeyIDやAssociateTag、SeacretKey等は書き換えています。)
もしエラーの原因が分かるようでしたら、お教え頂けませんでしょうか。
pokoさま、コメントありがとうございます。
私の方で、同じリクエストを送ったところ、レスポンスが正常に返ってきています(ランドスケープ関連の書籍が何冊か返ってきました)。パラメータやpa_sig.phpには問題はなさそうです。
参考までに、URLは以下の通りです。
http://webservices.amazon.co.jp/onca/xml?AWSAccessKeyId=00000000000000000000&AssociateTag=xxxxxxxxx-22&Keywords=%E9%80%A0%E5%9C%92%E5%AD%A6%E4%BC%9A&Operation=ItemSearch&Page=1&ResponseGroup=Medium%2CImages&SearchIndex=Blended&Service=AWSECommerceService&Timestamp=2009-07-17T10%3A09%3A43Z&Version=2009-01-06&Signature=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
「リクエストには、Serviceパラメータが含まれていません。」エラー( AWS.MissingServiceParameter )は、リクエストに何も含まれていない時にも表示されます。例えば、 http://webservices.amazon.co.jp/onca/xml にクエリ文字列無しでアクセスしたときなど。プログラムの処理で、クエリ文字列が消えてしまっていたりしませんでしょうか?
はじめまして。
このたび、自分のホームページにAmazon Product Advertising API を利用してなんらかの商品を表示したいと思い検索してるとRingoon POP!さんのサイトにたどり着きました。
(ちなみに、phpは全くさわったことがなく、html、css、javascriptを多少かじってる程度です。)
そこで、書かれたとおりにやってみたのですがよく分からない箇所があり困っています。
まず、やったことを書くと
■0.1 準備
⇒「2. 準備」を参考に、「Secret Access Key」を取得して、「PECL hash」のインストールを確認しました。
■0.2 ダウンロード
http://amazon.ringoon.jp/rest_test/pa_sig.txt をダウンロードして、拡張子をphpに変えてください。ライセンスは クリエイティブ・コモンズ 表示 2.1 日本 です。改変・再配布・商用利用が可能です。
⇒http://amazon.ringoon.jp/rest_test/pa_sig.txtをダウンロードし拡張子をphpに変更しました。
■0.3 プログラムの改良
0.3.1 Secret Access Keyの変更
pa_sig.phpの "Your Secret Access Key" のところを、自分の「Secret Access Key」に変更してください。
⇒自分の「Secret Access Key」に変更しました。
0.3.2 従来のプログラムの改修
http://amazon.ringoon.jp/rest_test/pa_sig_test.txt を参考に、従来のプログラムを改修してください。
・includeする
・リクエストURLに add_signature($url) で署名を付加する
という2点だけです。
⇒ここの「従来のプログラム」とは一体どれなんでしょうか?また、このプログラムから一体どのようにしてブラウザのURLにアクセスするのでしょうか?
最後にもう1つ質問です。
「Secret Access Key」をjavascriptやphpに含めるとなると他から見られる可能性ってないのでしょうか?Secret Access Keyは、誰にも見られてはいけないと書いてありましたので・・・
以上、よろしくお願いします。
ホームページ初心者さま、コメントありがとうございます。
Q1. ここの「従来のプログラム」とは一体どれなんでしょうか?
この記事は、2009年5月9日以前に、Amazon Web Services(当時)から情報を取得するPHPプログラムを書いた人を対象にしていました。「従来のプログラム」とは2009年5月9日以前に書いたプログラムのことです。ホームページ初心者さまは、今からプログラムを作るということですので、「従来のプログラム」はありません。
Q2. このプログラムから一体どのようにしてブラウザのURLにアクセスするのでしょうか?
URLと聞いて、javascriptの location.href のようなものをイメージしていらっしゃいますか? 少し違います。
例えば、Amazon Product Advertising APIから商品の情報を取得するには、商品のID(ASINと言います)を含んだURLにアクセスします。アクセスするのはプログラムで、ブラウザではありません。
と、言葉だけで書いても分かりにくいと思いますので、サンプルプログラムを用意しました。
http://amazon.ringoon.jp/rest_test/sample.txt
サンプルプログラムの$accesskeyを、自分の「Access Key ID」に変えてください。
サンプルプログラムの11行目で、fopen($url, 'r') というところが、「Amazon Product Advertising APIのURLにプログラムがアクセスしている」ところです。
サンプルプログラムを実行すると、http://amazon.ringoon.jp/rest_test/sample.xmlのような情報が帰ってくると思います。
あとは、情報をそのまま表示するのではなく、HTMLとして見映え良く加工してあげればプログラムの完成です。一番手っ取り早いのは、XSLTを使う方法でしょうか。
Q3. 「Secret Access Key」をjavascriptやphpに含めるとなると他から見られる可能性ってないのでしょうか?
javascriptに「Secret Access Key」を書くと、他の人に見られてしまいます。隠す方法はわかりません。思い付きません。
PHPでは、通常は、見られることはありません。例えば、サーバの設定を間違えて、phpという拡張子をPHPとして登録し忘れると、PHPプログラムがテキストとして表示されてしまい「Secret Access Key」が丸見えになります。外からは見えないディレクトリに「Secret Access Key」を書いたファイルを置いて、PHPで読み込む、という風にすると隠すことができると思います。
管理人さま、お返事ありがとうございます。
とりあえず、なんとか表示できました!
あとは、これに検索ボックスをつけて検索結果を表示できるように頑張ります。
どうもありがとうございました。