phpでSP-APIを利用する方法(認証編)

program、code、SP-API、Amazon 10_コーディング

2022.9.30でMWSが廃止となり、SP-APIへの移行が避けられないため、
アプリを修正しています。phpでの実装例が少ないので参考になれば。

例えば、情報をうまく使えば、こんなの作れます^^

フロー

 大まかな処理の流れは下記の通り。
 事前にAWS IAMユーザの作成とAmazon Seller Centralの開発者情報を取得しておく。

SP-API、フロー

詳細版)

ソース公開

 動作確認用の暫定コードです。2022-04-01版で動作確認済@2022.7.4
 ※php7.4、php8.0環境で動作済み
 ※php7.2、php5.4環境では、jsonのデータ引き渡しでNG

  1. <?php
  2.     //出品者毎に固有のパラメータ
  3.     $AWS_CLIENT_ID            = 'am--------------------';
  4.     $AWS_CLIENT_SECRET_KEY    = 'cf-------------------------';
  5.     $AWS_REFRESH_TOKEN        = 'At-----------------------------------------------------------------';
  6.     
  7.     $DEV_ACCESS_KEY            = 'A-----------------';
  8.     $DEV_SECRET_ACCESS_KEY    = 'yV----------------------------------';
  9.     
  10.     ////////////////////////////////////////////////////////////
  11.     //0.初期化処理
  12.     //        固定値と変数枠を準備する。
  13.     //
  14.     ////////////////////////////////////////////////////////////
  15.     
  16.     $DEBUG_MODE=0;        //0:通常モード 1:デバッグモード
  17.     $GMT_DATE            = gmdate("Ymd\THis\Z");
  18.     $DATE                = substr($GMT_DATE, 0, 8);
  19.     
  20.     $ASIN_CODE            = "B007BFMY3I";                                //サンプル商品
  21.     $REQUEST_SUB_URL    = "/catalog/2022-04-01/items/".$ASIN_CODE;
  22.     
  23.     $F_CANONICALREQUEST_QUERY    = "marketplaceIds=A1VC38T7YXB528";    //日本のマーケットプレイス
  24.     $F_REQUEST_URL                = "https://sellingpartnerapi-fe.amazon.com" .$REQUEST_SUB_URL ."?" . $F_CANONICALREQUEST_QUERY;
  25.     
  26.     
  27.     $F_CURLOPT_HTTPHEADER_ARRAY = array(
  28.             'CONTENT-TYPE'    => 'Content-Type: application/x-www-form-urlencoded;charset=UTF-8',
  29.             'HOST'            => 'Host: api.amazon.com',
  30.             'ACT'            => 'POST /auth/o2/token HTTP/l.l'
  31.     );
  32.     $F_CURLOPT_POSTFIELDS_ARRAY = array(
  33.             'grant_type'        => 'refresh_token',
  34.             'refresh_token'        => $AWS_REFRESH_TOKEN,
  35.             'client_id'            => $AWS_CLIENT_ID,
  36.             'client_secret'        => $AWS_CLIENT_SECRET_KEY
  37.     );
  38.     $F_ACC_CURLOPT_ARRAY = array(
  39.             'CUSTOMREQUEST'        => 'POST',
  40.             'HTTPHEADER_ARRAY'    => $F_CURLOPT_HTTPHEADER_ARRAY,
  41.             'TOKEN_URL'            => 'https://api.amazon.com/auth/o2/token',
  42.             'RETURNTRANSFER'    => 'TRUE',
  43.             'POST'                => 'TRUE',
  44.             'VERIFYPEER'        => 'FALSE',
  45.             'VERIFYHOST'        => 'FALSE',
  46.             'POSTFIELDS_ARRAY'    => $F_CURLOPT_POSTFIELDS_ARRAY
  47.     );
  48.     $F_CANONICALREQUEST_HEADERS    = array(
  49.             'HOST'            => 'host:sellingpartnerapi-fe.amazon.com',
  50.             'USER_AGENT'    => 'user-agent:test_pg',
  51.             'ACCESS_TOKEN'    => '',                    //アクセストークン取得後に代入する。
  52.             'DATE'            => 'x-amz-date:' . $GMT_DATE
  53.     );
  54.     $F_CANONICALREQUEST_ARRAY = array(
  55.             'METHOD'        => 'GET',
  56.             'URL'            => $REQUEST_SUB_URL,
  57.             'QUERY'            => $F_CANONICALREQUEST_QUERY,
  58.             'HEADERS'        => '',                    //アクセストークン取得後に代入する。
  59.             'SIGNED_HEADERS'=> 'host;user-agent;x-amz-access-token;x-amz-date',
  60.             'PAYLOAD'        => hash('sha256','')
  61.     );
  62.     $F_SIGNATURE_ARRAY_0        = array(
  63.             'DATE'                    => $DATE,
  64.             'DEV_SECRET_ACCESS_KEY'    => $DEV_SECRET_ACCESS_KEY,
  65.             'HEAD'                    => 'AWS4',
  66.             'HASH'                    => 'sha256',
  67.             'AWS_REGION'            => 'us-west-2',
  68.             'AWS_SERVICE'            => 'execute-api',
  69.             'AWS_TERMINATION'        => 'aws4_request',
  70.     );
  71.     $F_SIGNATURE_ARRAY_1        = array(
  72.             'GMT_DATE'                => $GMT_DATE,
  73.             'DATE'                    => $F_SIGNATURE_ARRAY_0['DATE'],
  74.             'CANONICAL_REQUEST'        => '',            //正規リクエスと作成後に代入する。
  75.             'SIGNATURE_ALGORITHM'    => 'AWS4-HMAC-SHA256',
  76.             'SIGNING_KEY'            => '',            //署名キー作成後に代入する。
  77.             'AWS_REGION'            => $F_SIGNATURE_ARRAY_0['AWS_REGION'],
  78.             'AWS_SERVICE'            => $F_SIGNATURE_ARRAY_0['AWS_SERVICE'],
  79.             'AWS_TERMINATION'        => $F_SIGNATURE_ARRAY_0['AWS_TERMINATION']
  80.     );
  81.     $F_SIGNATURE_ARRAY_2        = array(
  82.             'DATE'                        => $F_SIGNATURE_ARRAY_0['DATE'],
  83.             'CANONICAL_REQUEST_ARRAY'    => '',        //アクセストークン取得後に代入する。
  84.             'SIGNATURE'                    => '',        //署名作成後に代入する。
  85.             'SIGNATURE_ALGORITHM'        => $F_SIGNATURE_ARRAY_1['SIGNATURE_ALGORITHM'],
  86.             'DEV_ACCESS_KEY'            => $DEV_ACCESS_KEY,
  87.             'AWS_REGION'                => $F_SIGNATURE_ARRAY_0['AWS_REGION'],
  88.             'AWS_SERVICE'                => $F_SIGNATURE_ARRAY_0['AWS_SERVICE'],
  89.             'AWS_TERMINATION'            => $F_SIGNATURE_ARRAY_0['AWS_TERMINATION']
  90.     );
  91.     $F_GET_CURLOPT_HTTPHEADER_ARRAY = array(
  92.             'AUTH_HEADER'    => '',                    //認証ヘッダを作成後に代入する。
  93.             'HOST'             => 'host:sellingpartnerapi-fe.amazon.com',
  94.             'USER-AGENT'    => 'user-agent:test_pg',
  95.             'ACCESS_TOKEN'    => '',                    //アクセストークン取得後に代入する。
  96.             'GMT_DATE'        => 'x-amz-date:' . $GMT_DATE
  97.     );
  98.     $F_GET_CURLOPT_ARRAY = array(
  99.             'CUSTOMREQUEST'        => 'GET',
  100.             'HTTPHEADER_ARRAY'    => '',                //認証ヘッダを作成後に代入する。
  101.             'REQUEST_URL'        => $F_REQUEST_URL,
  102.             'RETURNTRANSFER'    => 'TRUE',
  103.             'POST'                => 'FALSE',
  104.             'VERIFYPEER'        => 'FALSE',
  105.             'VERIFYHOST'        => 'FALSE',
  106.             'HEADER'            => 'TRUE'
  107.     );
  108.     
  109.     ////////////////////////////////////////////////////////////
  110.     //1.アクセストークンの取得
  111.     //
  112.     //    input    :固定値、AWS情報、開発者キーなど
  113.     //    output    :アクセストークン
  114.     //
  115.     ////////////////////////////////////////////////////////////
  116.     
  117.     //Processing
  118.     // initialize curl header
  119.     $CURL_HEADER = curl_init();
  120.     
  121.     // set curl options
  122.     curl_setopt($CURL_HEADER, CURLOPT_CUSTOMREQUEST, $F_ACC_CURLOPT_ARRAY['CUSTOMREQUEST']);
  123.     curl_setopt($CURL_HEADER, CURLOPT_HTTPHEADER, $F_ACC_CURLOPT_ARRAY['HTTPHEADER_ARRAY']);
  124.     curl_setopt($CURL_HEADER, CURLOPT_URL, $F_ACC_CURLOPT_ARRAY['TOKEN_URL']);
  125.     curl_setopt($CURL_HEADER, CURLOPT_RETURNTRANSFER, $F_ACC_CURLOPT_ARRAY['RETURNTRANSFER']);
  126.     curl_setopt($CURL_HEADER, CURLOPT_POST, $F_ACC_CURLOPT_ARRAY['POST']);
  127.     curl_setopt($CURL_HEADER, CURLOPT_SSL_VERIFYPEER, $F_ACC_CURLOPT_ARRAY['VERIFYPEER']);
  128.     curl_setopt($CURL_HEADER, CURLOPT_SSL_VERIFYHOST, $F_ACC_CURLOPT_ARRAY['VERIFYHOST']);
  129.     curl_setopt($CURL_HEADER, CURLOPT_POSTFIELDS, http_build_query($F_ACC_CURLOPT_ARRAY['POSTFIELDS_ARRAY']));
  130.     
  131.     // running curl
  132.     $CUR_RES = curl_exec($CURL_HEADER);
  133.     curl_close($CURL_HEADER);
  134.     
  135.     // formatting
  136.     $json_response = json_decode($CUR_RES);
  137.     // get access_token(output)
  138.     $ACCESS_TOCKEN = $json_response->access_token;
  139.     
  140.     
  141.     $F_CANONICALREQUEST_HEADERS['ACCESS_TOKEN'] = 'x-amz-access-token:'.$ACCESS_TOCKEN;
  142.     $F_CANONICALREQUEST_ARRAY['HEADERS'] = $F_CANONICALREQUEST_HEADERS;
  143.     $F_SIGNATURE_ARRAY_2['CANONICAL_REQUEST_ARRAY'] = $F_CANONICALREQUEST_ARRAY;
  144.     $F_GET_CURLOPT_HTTPHEADER_ARRAY['ACCESS_TOKEN'] = 'x-amz-access-token:' . $ACCESS_TOCKEN;
  145.     
  146.     
  147.     if( $DEBUG_MODE == 1){
  148.         echo $ACCESS_TOCKEN . "\n";
  149.     }
  150.     
  151.     ////////////////////////////////////////////////////////////
  152.     //2.署名
  153.     //
  154.     //    input    :固定値、AWS情報、開発者キー、アクセストークンなど
  155.     //    output    :認証ヘッダー
  156.     //
  157.     ////////////////////////////////////////////////////////////
  158.     
  159.     //リクエスト生成
  160.     $F_SIGNATURE_ARRAY_1['CANONICAL_REQUEST']=CanonicalRequest($F_CANONICALREQUEST_ARRAY);
  161.     
  162.     //署名を計算
  163.     $F_SIGNATURE_ARRAY_1['SIGNING_KEY']=SignatureKey($F_SIGNATURE_ARRAY_0);
  164.     
  165.     if( $DEBUG_MODE == 1){
  166.         echo "-----signature array-------------------\n";
  167.         echo "GMT_DATE:"                . $F_SIGNATURE_ARRAY_1['GMT_DATE']                    . "\n";
  168.         echo "DATE:"                     . $F_SIGNATURE_ARRAY_1['DATE']                         . "\n";
  169.         echo "CANONICAL_REQUEST:"        . bin2hex($F_SIGNATURE_ARRAY_1['CANONICAL_REQUEST'])     . "\n";
  170.         echo "SIGNATURE_ALGORITHM:"     . $F_SIGNATURE_ARRAY_1['SIGNATURE_ALGORITHM']         . "\n";
  171.         echo "SIGNING_KEY:"             . bin2hex($F_SIGNATURE_ARRAY_1['SIGNING_KEY'])         . "\n";
  172.         echo "AWS_REGION:"             . $F_SIGNATURE_ARRAY_1['AWS_REGION']                     . "\n";
  173.         echo "AWS_SERVICE:"             . $F_SIGNATURE_ARRAY_1['AWS_SERVICE']                 . "\n";
  174.         echo "AWS_TERMINATION:"         . $F_SIGNATURE_ARRAY_1['AWS_TERMINATION']             . "\n";
  175.         echo "---------------------------------------\n";
  176.     }
  177.     
  178.     $F_SIGNATURE_ARRAY_2['SIGNATURE'] = SignatureByAlgo($F_SIGNATURE_ARRAY_1);
  179.     
  180.     if( $DEBUG_MODE == 1){
  181.         echo "signature:" . bin2hex($F_SIGNATURE_ARRAY_2['SIGNATURE']) . "\n";
  182.     }
  183.     
  184.     //認証ヘッダ作成
  185.     $AuthorizationHeader = CreateAuthorization($F_SIGNATURE_ARRAY_2);
  186.     
  187.     if( $DEBUG_MODE == 1){
  188.         echo "AuthorizationHeader :" . $AuthorizationHeader . "\n";
  189.     }
  190.     
  191.     ////////////////////////////////////////////////////////////
  192.     //3.データ取得
  193.     //
  194.     //    input    :認証ヘッダー
  195.     //    output    :クエリ結果
  196.     //
  197.     ////////////////////////////////////////////////////////////
  198.     
  199.     $F_GET_CURLOPT_HTTPHEADER_ARRAY['AUTH_HEADER']=$AuthorizationHeader; //認証ヘッダ
  200.     $F_GET_CURLOPT_ARRAY['HTTPHEADER_ARRAY']= $F_GET_CURLOPT_HTTPHEADER_ARRAY;
  201.     
  202.     // 必要に応じてオプションを追加。
  203.     $CURL_HEADER = curl_init();
  204.     curl_setopt($CURL_HEADER, CURLOPT_CUSTOMREQUEST,    $F_GET_CURLOPT_ARRAY['CUSTOMREQUEST']);
  205.     curl_setopt($CURL_HEADER, CURLOPT_HTTPHEADER,        $F_GET_CURLOPT_ARRAY['HTTPHEADER_ARRAY']);
  206.     curl_setopt($CURL_HEADER, CURLOPT_URL,                $F_GET_CURLOPT_ARRAY['REQUEST_URL']);
  207.     curl_setopt($CURL_HEADER, CURLOPT_RETURNTRANSFER,    $F_GET_CURLOPT_ARRAY['RETURNTRANSFER']);
  208.     curl_setopt($CURL_HEADER, CURLOPT_POST,                $F_GET_CURLOPT_ARRAY['POST']);
  209.     curl_setopt($CURL_HEADER, CURLOPT_SSL_VERIFYPEER,    $F_GET_CURLOPT_ARRAY['VERIFYPEER']);
  210.     curl_setopt($CURL_HEADER, CURLOPT_SSL_VERIFYHOST,    $F_GET_CURLOPT_ARRAY['VERIFYHOST']);
  211.     curl_setopt($CURL_HEADER, CURLOPT_HEADER,            $F_GET_CURLOPT_ARRAY['HEADER']);
  212.     
  213.     $CUR_RES = curl_exec($CURL_HEADER);
  214.     curl_close($CURL_HEADER);
  215.     $json_response = json_decode($CUR_RES);
  216.     
  217.     echo count( $json_response -> summaries ) . "\n";
  218.     
  219.     echo "ASIN:"                     . $json_response -> asin . "\n";
  220.     echo "brand    :"                    . $json_response -> summaries['0'] -> brand . "\n";
  221.     echo "browseClassification(classificationId):"    . $json_response -> summaries['0'] -> browseClassification -> classificationId . "\n";
  222.     echo "browseClassification(displayName):"    . $json_response -> summaries['0'] -> browseClassification -> displayName . "\n";
  223.     echo "itemClassification:"        . $json_response -> summaries['0'] -> itemClassification . "\n";
  224.     echo "itemName:"                . $json_response -> summaries['0'] -> itemName . "\n";
  225.     echo "manufacturer:"            . $json_response -> summaries['0'] -> manufacturer . "\n";
  226.     echo "marketplaceId:"            . $json_response -> summaries['0'] -> marketplaceId . "\n";
  227.     echo "websiteDisplayGroup:"        . $json_response -> summaries['0'] -> websiteDisplayGroup . "\n";
  228.     echo "websiteDisplayGroupName:"    . $json_response -> summaries['0'] -> websiteDisplayGroupName . "\n";
  229.     
  230. //以降、関数--------------------------------------
  231.     function CanonicalRequest($IN_CR_ARRAY) {
  232.         $STR    = $IN_CR_ARRAY['METHOD']    . "\n"
  233.                 . $IN_CR_ARRAY['URL']        . "\n"
  234.                 . $IN_CR_ARRAY['QUERY']        . "\n";
  235.                         
  236.         if (count($IN_CR_ARRAY['HEADERS']) > 0) {
  237.             foreach ($IN_CR_ARRAY['HEADERS'] as $HEAD) {
  238.                 $STR .= $HEAD . "\n";
  239.             }
  240.         } else {
  241.             $STR .= "\n";
  242.         }
  243.         
  244.         $STR    .= "" . "\n"
  245.                 . $IN_CR_ARRAY['SIGNED_HEADERS'] . "\n"
  246.                 . $IN_CR_ARRAY['PAYLOAD'];
  247.                 
  248.         return hash('sha256', $STR, true);
  249.     }
  250.     
  251.     function SignatureKey($IN_SIG_ARR) {
  252.         $S_Key    =hash_hmac($IN_SIG_ARR['HASH'], $IN_SIG_ARR['AWS_TERMINATION'],
  253.                 hash_hmac($IN_SIG_ARR['HASH'], $IN_SIG_ARR['AWS_SERVICE'],
  254.                 hash_hmac($IN_SIG_ARR['HASH'], $IN_SIG_ARR['AWS_REGION'],
  255.                 hash_hmac($IN_SIG_ARR['HASH'], $IN_SIG_ARR['DATE'], $IN_SIG_ARR['HEAD'] . $IN_SIG_ARR['DEV_SECRET_ACCESS_KEY'], true), true), true), true);
  256.         return $S_Key;
  257.     }
  258.     
  259.     function SignatureByAlgo($IN_SIG_ARR) {
  260.         //認証情報スコープ(日付/リージョン/サービス/終端文字)
  261.         $TAEGET_STR    = $IN_SIG_ARR['SIGNATURE_ALGORITHM']     . "\n"
  262.                     . $IN_SIG_ARR['GMT_DATE']                 . "\n"
  263.                     . $IN_SIG_ARR['DATE']                     . "/"
  264.                     . $IN_SIG_ARR['AWS_REGION']             . "/"
  265.                     . $IN_SIG_ARR['AWS_SERVICE']             . "/"
  266.                     . $IN_SIG_ARR['AWS_TERMINATION']        . "\n"
  267.                     . bin2hex($IN_SIG_ARR['CANONICAL_REQUEST']);
  268.                                                         
  269.         //        echo "-----sign_func-------------------\n";
  270.         //        echo $TAEGET_STR . "\n";
  271.         //        echo "-----sign_func-------------------\n";
  272.         return hash_hmac('sha256', $TAEGET_STR, $IN_SIG_ARR['SIGNING_KEY'], true);
  273.     }
  274.     
  275.     function CreateAuthorization($IN_SIG_ARR) {
  276.         //Authorizationヘッダー(アルゴ Credential=AWSアクセスID/認証スコープ,SignedHeaders=host;user-agent;x-amz-accesstoken;xamz-date, )
  277.         $STR    = 'Authorization: '
  278.                 . $IN_SIG_ARR['SIGNATURE_ALGORITHM']
  279.                 . ' Credential='         . $IN_SIG_ARR['DEV_ACCESS_KEY'] . "/". $IN_SIG_ARR['DATE'] . "/". $IN_SIG_ARR['AWS_REGION'] . "/". $IN_SIG_ARR['AWS_SERVICE'] . "/". $IN_SIG_ARR['AWS_TERMINATION']
  280.                 . ', SignedHeaders='     . $IN_SIG_ARR['CANONICAL_REQUEST_ARRAY']['SIGNED_HEADERS']
  281.                 . ', Signature='         . bin2hex($IN_SIG_ARR['SIGNATURE']);
  282.                 
  283.         return $STR;
  284.     }
  285. ?>

関連記事

SP-APIリクエストをPostmanで確認する方法
SP-APIリクエスト(アクセストークン取得)
SP-APIリクエスト(商品情報取得)
SP-APIリクエスト(商品情報取得JAN)
SP-APIリクエスト(価格取得)

参考サイト

SP-API関連)
Amazon MWS から SP-API への移行 [準備編]
【解決済】2022年10月以降、MWSで全ての商品情報が、SP-APIで…
Amazon SP-APIをPHP ノンフレームワークで実装してみたので使い方を説明します
ブログ記載関連)
マージナルソフト:ソースをHTML化

コメント

  1. shigeo より:

    ソース参考にさせていただきました。
    クエリに「includedData」を追加した場合にデータ取得がうまくいきませんでした。

    ・OK
    https://sellingpartnerapi-fe.amazon.com/catalog/2022-04-01/items/B00K85QDQM?marketplaceIds=A1VC38T7YXB528&i

    ・NG
    https://sellingpartnerapi-fe.amazon.com/catalog/2022-04-01/items/B00K85QDQM?marketplaceIds=A1VC38T7YXB528&includedData=attributes%2CsalesRanks

    何か追加の処理が必要でしょうか??

    • shigeo より:

      解決しまいた。
      クエリのパラメータの順番がアルファベット順でないとエラーになるようです。

      https://sellingpartnerapi-fe.amazon.com/catalog/2022-04-01/items/B0BQHHNV9V?includedData=attributes%2Csummaries&marketplaceIds=A1VC38T7YXB528

      このURLでデータ取得できました。

      • ちびきー より:

        コメントありがとうございます。
         ※スパムが多すぎて返信できておらず、すんません。

        確かに、「アルファベット順でないとエラーが出る」ということもありましたね。
        マニュアルにも記載があったように記憶していますが、そんな仕様いる?と疑問ですね。
        なにはともあれ、自己解決されて何よりです^^

        ただ、逆に言えば、微妙な仕様がありすぎて理解するのが大変なので、
        ソースのたたき台を丸々公開させていただいている次第です。

  2. […] ・phpでSP-APIを利用する方法(認証編) […]

タイトルとURLをコピーしました