Reputation: 3237
I am having much trouble and frustration getting set up making API calls to the orders section of Amazon MWS.
When I use Amazon MWS Scratchpad I am able to get a successful response, but when I make the call on my own I get the error:
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.
I could be wrong, but I think there must be something wrong with the way I am actually making the call, because even when I use the exact call that's created through the Scratchpad, I am still receiving the same error.
Nonetheless, here is the code I am trying to build up the request:
<?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);
}
And here is the code that actually makes the call:
$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);
I need help identifying where this script is going wrong and why I am not able to get a successful response.
Upvotes: 4
Views: 2365
Reputation: 41
Solution:
$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);
Upvotes: 4
Reputation: 19672
This is going to sound stupid, but with the code you have currently, you're making a GET
request yet you sign it as POST
.
Change the first line of the signature from POST
to GET
and the signature should go through perfectly fine.
Upvotes: 2