How to add the URL encoded signature to your request

Amazon changed the way they authenticate user who use Product Advertising API. In the REST call, you must have Signature parameter in order to request for a service. Below is the functions that helps you encode the request URL in order to add to your request before calling Amazon API for product search and details. Make sure your server support mHash functionality. On Windows, you can enable mhas.dll extension in your php.ini file. On Linux, you can follow this instruction


//String sample to be encoded:
//AWSAccessKeyId=YOUR-ACCESS-KEY&Operation=ItemLookup&ResponseGroup=ItemAttributes%2COffers%2CImages%2CReviews&SearchIndex=Apparel&Keywords=Shirt&Timestamp=2014-12-20T10%3A04%3A00Z

function amazonEncode($text){
    $encodedText = "";
    $j = strlen($text);
 
    for($i=0; $i<$j; $i++) { 
        $c = substr($text,$i,1); 
        if (!preg_match("/[A-Za-z0-9-_.~]/",$c)) { 
            $encodedText .= sprintf("%%%02X",ord($c)); 
        } 
        else { $encodedText .= $c; } 
    }
    return $encodedText; 
}

function amazonSign($url,$secretAccessKey) { // 0. Append Timestamp parameter 
$url .= "&Timestamp=".gmdate("Y-m-dTH:i:sZ"); 
// 1a. Sort the UTF-8 query string components by parameter name 
$urlParts = parse_url($url); 
parse_str($urlParts["query"],$queryVars); 
ksort($queryVars); 
// 1b. URL encode the parameter name and values 
$encodedVars = array(); 
foreach($queryVars as $key => $value) {
 $encodedVars[amazonEncode($key)] = amazonEncode($value);
 }

 // 1c. 1d. Reconstruct encoded query
 $encodedQueryVars = array();
 foreach($encodedVars as $key => $value){
 $encodedQueryVars[] = $key."=".$value;
 }
 $encodedQuery = implode("&",$encodedQueryVars);

 // 2. Create the string to sign
 $stringToSign = "GET";
 $stringToSign .= "n".strtolower($urlParts["host"]);
 $stringToSign .= "n".$urlParts["path"];
 $stringToSign .= "n".$encodedQuery;

 // 3. Calculate an RFC 2104-compliant HMAC with the string you just created,
 //    your Secret Access Key as the key, and SHA256 as the hash algorithm.
 if (function_exists("hash_hmac"))
 {
 $hmac = hash_hmac("sha256",$stringToSign,$secretAccessKey,TRUE);
 }
 elseif(function_exists("mhash"))
 {
 $hmac = mhash(MHASH_SHA256,$stringToSign,$secretAccessKey);
 }
 else
 {
 die("No hash function available!");
 }
 // 4. Convert the resulting value to base64
 $hmacBase64 = base64_encode($hmac);
 // 5. Use the resulting value as the value of the Signature request parameter
 // (URL encoded as per step 1b)
 $url .= "&Signature=".amazonEncode($hmacBase64);
 return $url;
 }