Signing AWS requests in PHP

by admin on August 19, 2009

Recently Amazon added the requirement that all requests must be signed. The process of signing requests is documented on this product advertising API page. Based on the steps listed there, and with a lot of help from @giltotherescue, I was able to create a PHP function to create a signed request URI based on a simple set of request parameters.

function makeAWSUrl($parameters, $associate_tag, $access_key, $secret_key, $aws_version = '2009-06-01') {
  $host = 'ecs.amazonaws.com';
  $path = '/onca/xml';
 
  $query = array(        
    'Service' => 'AWSECommerceService',
    'AWSAccessKeyId' => $access_key,
    'AssociateTag' => $associate_tag,
    'Timestamp' => gmdate('Y-m-d\TH:i:s\Z'),
    'Version' => $aws_version,
  );
 
  // Merge in any options that were passed in
  if (is_array($parameters)) {
    $query = array_merge($query, $parameters);
   }
 
  // Do a case-insensitive, natural order sort on the array keys.
  ksort($query);
 
  // create the signable string
  $temp = array();
  foreach ($query as $k => $v) {
    $temp[] = str_replace('%7E', '~', rawurlencode($k)) . '=' . str_replace('%7E', '~', rawurlencode($v));
  }
  $signable = implode('&', $temp);
 
  $stringToSign = "GET\n$host\n$path\n$signable";
 
  // Hash the AWS secret key and generate a signature for the request.
  $hex_str = hash_hmac('sha256', $stringToSign, $secret_key);
  $raw = '';
  for ($i = 0; $i < strlen($hex_str); $i += 2) {
    $raw .= chr(hexdec(substr($hex_str, $i, 2)));
  }
 
  $query['Signature'] = base64_encode($raw);
  ksort($query);
 
  $temp = array();
  foreach ($query as $k => $v) {
    $temp[] = rawurlencode($k) . '=' . rawurlencode($v);
  }
  $final = implode('&', $temp);
 
  return 'http://' . $host . $path . '?' . $final;
}

Using the function is simple. The first parameter is a PHP array of AWS parameters, the others are standard associate tags and keys. Here’s an example:

$url = makeAWSUrl(array('Keywords' => 'Jaco Pastorius',                           
                      'Operation' => 'ItemSearch',                          
                      'ResponseGroup' => 'Medium',                           
                      'SearchIndex' => 'Music',                           
                      'salesrank' => 'Bestselling'),  
  'YOUR_ASSOC_TAG', 'YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY');

The result of the above call (using my tags and keys) is:

http://ecs.amazonaws.com/onca/xml?AWSAccessKeyId=[MYKEY]&AssociateTag=blakesblogand-20&Keywords=Jaco%20Pastorius&Operation=ItemSearch&ResponseGroup=Medium&SearchIndex=Music&Service=AWSECommerceService&Signature=qZ%2BheDqfZi79b2Xg0JSP2kgG2FgQn823GLn0m1sVmnM%3D&Timestamp=2009-08-19T22%3A53%3A29Z&Version=2009-06-01&salesrank=Bestselling

As always, give me some feedback, take the code and make it better. Share it and include it in your libraries … have fun!

Comments:

Comments on this entry are closed.