【问题标题】:How to make a call to Amazon MWS Orders with PHP?如何使用 PHP 调用亚马逊 MWS 订单?
【发布时间】:2015-11-26 18:36:23
【问题描述】:

在设置对亚马逊MWS订单部分进行API调用时,我遇到了很多麻烦和沮丧。

当我使用Amazon MWS Scratchpad 时,我能够获得成功的响应,但是当我自己拨打电话时,我得到了错误:

The request signature we calculated does not match the signature you provided.
Check your AWS Secret Access Key and signing method.
Consult the service documentation for details.

我可能是错的,但我认为我实际拨打电话的方式一定有问题,因为即使我使用通过 Scratchpad 创建的确切呼叫,我仍然收到相同的错误。

尽管如此,这是我试图构建请求的代码:

<?php

$secretKey = '<MY SECRET KEY>';

$parameters = array();

// required parameters
$parameters['Action']               = 'ListOrders';
$parameters['AWSAccessKeyId']       = '<MY ACCESS KEY>';
$parameters['MWSAuthToken']         = '<MY AUTH TOKEN>';
$parameters['SellerId']             = '<MY SELLER ID>';
$parameters['SignatureMethod']      = 'HmacSHA256';
$parameters['SignatureVersion']     = '2';
$parameters['Timestamp']            = gmdate("Y-m-d\TH:i:s.\\0\\0\\0\\Z", time());
$parameters['Version']              = '2013-09-01';

// optional parameters
$parameters['MarketplaceId.Id.1']   = '<MARKETPLACE ID>';
$parameters['CreatedAfter']         = '2015-10-04T04%3A00%3A00Z';

/**
 * Calculate String to Sign
 * 
 * @param array $parameters request parameters
 * @return String to Sign
 */
function _calculateStringToSign(array $parameters) {
    $data = "POST\n";
    $data .= "mws.amazonservices.com\n";
    $data .= "/Orders/2013-09-01\n";        
    $data .= _getParametersAsString($parameters);
    return $data;
}


/**
 * Convert paremeters to Url encoded query string
 */
function _getParametersAsString(array $parameters)
{
    uksort($parameters, 'strcmp');
    $queryParameters = array();
    foreach ($parameters as $key => $value) {
        $queryParameters[] = $key . '=' . _urlencode($value);
    }
    return implode('&', $queryParameters);
}

function _urlencode($value) {
    return str_replace('%7E', '~', rawurlencode($value));
}

/**
 * Computes RFC 2104-compliant HMAC signature.
 */
function _sign($stringToSign, $secretKey)
{
    $hash = 'sha256';

    return urlencode(base64_encode(
        hash_hmac($hash, $stringToSign, $secretKey, true)
    ));
}

/**
 * Builds up the request.
 */
function buildRequest(array $parameters, $secretKey) {
    $endpoint = 'https://mws.amazonservices.com/Orders/2013-09-01';

    $signature = _sign(_calculateStringToSign($parameters), $secretKey);
    $parameters['Signature'] = $signature;

    uksort($parameters, 'strcmp');
    return $endpoint . '?' . _getParametersAsString($parameters);
}

下面是实际调用的代码:

$request = buildRequest($parameters, $secretKey);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $request);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) chrome/39.0.2171.71 Safari/537.36');
$page = curl_exec($ch);
curl_close($ch);
var_dump($page);

我需要帮助确定此脚本的问题所在以及为什么我无法获得成功的响应。

【问题讨论】:

  • 您的问题解决了吗?我想我也面临同样的问题(stackoverflow.com/questions/40874090/…)
  • @A.. 这是很久以前的事了,我几乎不记得了。我认为这里的答案很有帮助,我还必须更改参数的顺序。我可以试着找到我今天稍后使用的代码,如果你那时还没有得到它
  • 稍后我将更改参数的顺序......但如果你能告诉我你的代码,我将不胜感激!
  • @A.. 我刚刚将我使用的代码复制到了gist。我没有时间去测试或真正去体验它,它是 Laravel 项目的一部分。不确定代码有多好或前一段时间的任何内容,但您应该能够使用它来获得成功的响应。等我有时间再回来看看你有没有得到它
  • 非常感谢,今晚我要试试!!如果有效,请回复我的问题,我会给你正确的答案。

标签: php amazon-web-services curl amazon-mws


【解决方案1】:

解决方案:

$secretKey = 'ENTERVALUE';

$parameters = array();

// required parameters
$parameters['AWSAccessKeyId']       = 'ENTERVALUE';
$parameters['Action']               = 'GetOrder';
$parameters['AmazonOrderId.Id.1']   = 'ENTERVALUE';
$parameters['SellerId']             = 'ENTERVALUE';
$parameters['SignatureMethod']      = 'HmacSHA256';
$parameters['SignatureVersion']     = '2';
$parameters['Timestamp']            = gmdate("Y-m-d\TH:i:s.\\0\\0\\0\\Z", time());
$parameters['Version']              = '2013-09-01';




/**
 * Calculate String to Sign
 * 
 * @param array $parameters request parameters
 * @return String to Sign
 */
function _calculateStringToSign(array $parameters) {
    $data = "POST\n";
    $data .= "mws.amazonservices.com\n";
    $data .= "/Orders/2013-09-01\n";        
    $data .= _getParametersAsString($parameters);
    return $data;
}


/**
 * Convert paremeters to Url encoded query string
 */
function _getParametersAsString(array $parameters)
{
    uksort($parameters, 'strcmp');
    $queryParameters = array();
    foreach ($parameters as $key => $value) {
        $queryParameters[] = $key . '=' . _urlencode($value);
    }
    return implode('&', $queryParameters);
}

function _urlencode($value) {
    return str_replace('%7E', '~', rawurlencode($value));
}

/**
 * Computes RFC 2104-compliant HMAC signature.
 */
function _sign($stringToSign, $secretKey)
{
    //HmacSHA1
    $hash = 'sha256';

    return base64_encode(
        hash_hmac($hash, $stringToSign, $secretKey, true)
    );
}

/**
 * Builds up the request.
 */
function buildRequest(array $parameters, $secretKey) {
    //$endpoint = 'https://mws.amazonservices.com/Orders/2013-09-01';

    $signature = _sign(_calculateStringToSign($parameters), $secretKey);
    $parameters['Signature'] = $signature;

    uksort($parameters, 'strcmp');
    return _getParametersAsString($parameters);
}

$request = buildRequest($parameters, $secretKey);



$allHeaders = array();
    $allHeaders['Content-Type'] = "application/x-www-form-urlencoded; charset=utf-8"; // We need to make sure to set utf-8 encoding here
    $allHeaders['Expect'] = null; // Don't expect 100 Continue
    $allHeadersStr = array();
    foreach($allHeaders as $name => $val) {
        $str = $name . ": ";
        if(isset($val)) {
            $str = $str . $val;
        }
        $allHeadersStr[] = $str;
    }


//complete string
//echo $endpoint . '?' .$request;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://mws.amazonservices.com/Orders/2013-09-01');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $request);
curl_setopt($ch, CURLOPT_HTTPHEADER, $allHeadersStr);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) chrome/39.0.2171.71 Safari/537.36');
$response = curl_exec($ch);
echo $response;
$xml = simplexml_load_string( $response );
echo curl_error($ch);
curl_close($ch);

【讨论】:

  • 虽然这段代码 sn-p 可以解决问题,但including an explanation 确实有助于提高帖子的质量。请记住,您是在为将来的读者回答问题,而这些人可能不知道您提出代码建议的原因。
【解决方案2】:

这听起来很愚蠢,但是使用您当前拥有的代码,您正在发出GET 请求,但您将其签名为POST

将签名的第一行从POST 更改为GET,签名应该可以通过了。

【讨论】:

  • @tam - 好的,如果是 POST 请求,请添加 curl_setopt($ch, CURLOPT_POST, true);。它将使用空的 postbody 发送请求。但是,我怀疑是否是这种情况,因为 v2 签名仅适用于 GET 请求。此外,您用于对参数进行排序的比较是错误的 - 它不是 str 比较而是字节比较。加入参数然后sort他们。
  • 你大部分是对的。事实上,我确实需要发出GET 请求而不是POST,所以感谢您的支持和+1。还有另一个问题,由于某种原因,Signature 必须放在查询的末尾,这样做对我有用。不知道为什么,尤其是不知道为什么在任何地方都没有提到它,但是让它起作用了。我将使用最终有效的代码更新我的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-25
  • 2018-12-29
  • 2012-12-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多