*当サイトのリンクにはAmazonアソシエイトやアフィリエイトリンクが含まれております。

Amazon SP-API のPHPコーディングメモ

サラリーのほうで、各ショッピングサイトの在庫連動システムをLaravelを用いて構築したのですが、
MWSが近々終了という事でSPAPIに移行しました。
すでに大半の移行が完了していたのですが、なぜかFBA在庫レポートのみ動作せずMWSを使っていました。
しかしながらMWS終了のメールが何度も来るので、重い腰を上げて再度向き合った時のメモ。

広告

Amazon SP-API の署名のメモ

上記のFBA在庫レポートに関してはどうしても動作しませんでした。
GET_AFN_INVENTORY_DATA を reportType に渡すとどうにもエラーです。

GIT上でもバグがあるってのが議論されてました。

日本では使えないのだろうか・・・

という事で別の方法で取得しました。

その時、署名の計算でハマったのでメモを残します。

GETの場合


        $spapi = new AmazonSpapiController;

        $access_token = $spapi->get_actoken();

        $host = $spapi::Api_set['host'];
        $mid = $spapi::Api_set['MarketplaceId'];
        $user_agent = $spapi::Api_set['user-agent'];

        if ($queryString !== '') {
            $queryString .= '&MarketplaceIds=' . $mid;
            $request_url = 'https://' . $host . $request . '?' . $queryString;
        } else {
            $request_url = 'https://' . $host . $request;
        }

        $gmtDate = gmdate("Ymd\THis\Z");
        $ymdData = substr($gmtDate, 0, 8);

        $headers = [
            'content-type:application/json;charset=UTF-8',
            'host:' . $host,
            'user-agent:' . $user_agent,
            'x-amz-access-token:' . $access_token, //事前取得アクセストークン
            'x-amz-date:' . $gmtDate
        ];

        $canonicalRequest = [
            'method' => 'GET',
            'uri' => $request, //署名作成のまえに作ったリクエストURL
            'query' => $queryString, //署名作成のまえに作ったリクエストパラメーター
            'headers' => $headers,
            'signedheaders' => 'content-type;host;user-agent;x-amz-access-token;x-amz-date',
            'payload' => hash('sha256', ''),
        ];

        //リクエスト生成 -1
        $canonical_request = $spapi->CanonicalRequest($canonicalRequest);

        //署名を計算 -2
        $signing_key = $spapi->signatureKey($ymdData);

        $algorithm = 'AWS4-HMAC-SHA256';
        $param['amzdate'] = $gmtDate;
        $param['datestamp'] = $ymdData;
        $param['method'] = 'GET';
        $signature = $spapi->signature($param, $canonical_request, $algorithm, $signing_key);

        $auth = $spapi->createAuthorization($param, $canonicalRequest, $signature, $algorithm);

        //これがバージョン4の署名で必要になる文字列
        //ヘッダ情報に追加
        $headers[] =  'Authorization: ' . $auth;

        $json_response = $spapi->get_spapi_json($headers, $request_url, false);

こんな感じ。
他の関数とやり取りしてるので、コピペじゃ動きませんのであしからず・・・。

POSTの場合


        $spapi = new AmazonSpapiController;
        $access_token = $spapi->get_actoken();

        $host = $spapi::Api_set['host'];
        $mid = $spapi::Api_set['MarketplaceId'];
        $user_agent = $spapi::Api_set['user-agent'];

        $request = "/reports/2021-06-30/reports";
        $request_url = 'https://' . $host . $request;

        /**
         * GET_FLAT_FILE_OPEN_LISTINGS_DATA -> 出品レポート
         */
        $queryString = '{
           "reportType": "GET_FLAT_FILE_OPEN_LISTINGS_DATA",
           "marketplaceIds":["' . $mid . '"]
        }';

        $gmtDate = gmdate("Ymd\THis\Z"); //リクエストごとの先頭で予め取得しとくといいです。
        $ymdData = substr($gmtDate, 0, 8);

        $request_headers = [];
        $request_headers['content-type'] = 'application/json';
        $request_headers['host'] = $host;
        $request_headers['x-amz-access-token'] = $access_token;
        $request_headers['x-amz-content-sha256'] = hash('sha256', $queryString);
        $request_headers['x-amz-date'] = $gmtDate;

        //Canonical headers & Signed headers
        $csheaders = $spapi->MakeheadInner($request_headers);

        $canonicalRequest = [
            'method' => 'POST',
            'uri' => $request, //署名作成のまえに作ったリクエストURL
            'headers' => [$csheaders['ch']],
            'signedheaders' => $csheaders['sh'],
            'payload' => hash('sha256', $queryString),
        ];

        //リクエスト生成 -1
        $hashed_canonical = $spapi->CanonicalRequest($canonicalRequest);

        //署名を計算 -2
        $signature = $spapi->signatureKey($ymdData);

        $algorithm = 'AWS4-HMAC-SHA256';
        $param['amzdate'] = $gmtDate;
        $param['datestamp'] = $ymdData;
        $param['method'] = 'POST';
        $signature = $spapi->signature($param, $hashed_canonical, $algorithm, $signature);

        $auth = $spapi->createAuthorization($param, $canonicalRequest, $signature, $algorithm);

        // Curl headers
        $curl_headers = ['Authorization: ' . $auth];
        foreach ($request_headers as $key => $value) {
            $curl_headers[] = $key . ": " . $value;
        }

        $json_response = $spapi->get_spapi_json($curl_headers, $request_url, $queryString);

GETとちょっとだけ違う。
たしかこれ作った時、どっちかを先に作って使いまわしたんで、無駄なコードがあると思います。

FBA在庫取得の解消方法

/fba/inventory/v1/summaries にリクエスト出すとFBAの在庫を取得できました。
こっちのがFBA在庫レポートを発行させるより効率良いようです。

だから GET_AFN_INVENTORY_DATA は動かないのかな??
分からんけど。

ちなみにバイト代くれればSPAPI対応のPHP作れなくもないです。
ではでは。


おすすめのコンテンツ

広告

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください