如何使用PHP中的私钥签署有效负载?

I am trying to utilize the GoodRx API using PHP.

Here is my code:

 $hash = hash_hmac('sha256', $query_string, MY_SECRET_KEY);
 $encoded = base64_encode($hash);
 $private_key = str_replace('+', '_', $encoded);
 $private_key = str_replace('/', '_', $encoded);
 //$private_key = urlencode($private_key);
 $query_string .= '&sig=' . $private_key;

 echo $query_string;    
 // https://api.goodrx.com/low-price?name=Lipitor&api_key=MY_API_KEY&sig=MY_SECRET_KEY

It is returning an error saying that my sig is not right.

Could you help me please.

Thank you.

Thomas.

You're not doing your string replacements correctly:

$private_key = str_replace('+', '_', $encoded);
   ^^---new string                       ^---original string
$private_key = str_replace('/', '_', $encoded);
   ^--overwrite previous replacement     ^---with original string again

If you want to chain replacements, you have to do something more like:

$orig = 'foo';
$temp = str_replace(..., $orig);
$temp = str_replace(..., $temp);
...
$final = str_replace(..., $temp);

Note how you pass in the result of the PREVIOUS replacement into the next call, which is what you're not doing. You just keep taking the originals tring, replace one thing, then trash that replacement on the next call. So effectively you're ONLY doing a /->_ replacement, and sending the + as-is.

Posting this in case anyone needs a complete example of how to make a basic call to the GoodRx API:

In Python:

import requests
import hashlib
import hmac
import base64

# python --version returns:
#        Python 3.5.1 :: Anaconda 2.4.1 (32-bit)

# my_api_key is the API key for your account, provided by GoodRx
my_api_key = "YOUR_API_KEY";

# s_skey is the secret key for your account, provided by GoodRx
my_secret_key=str.encode("YOUR_SECRET_KEY", 'utf-8')

# Create the base URL and the URL parameters
# The url_params start as text and then have to be encoded into bytes
url_base = "https://api.goodrx.com/fair-price?"
url_params = str.encode("name=lipitor&api_key=" + my_api_key, 'utf-8')

# This does the hash of url_params with my_secret_key    
tmpsig = hmac.new(my_secret_key, msg=url_params,     digestmod=hashlib.sha256).digest()

# Base64 encoding gets rid of characters that can't go in to URLs. 
# GoodRx specifically asks for these to be replaced with "_"
sig = base64.b64encode(tmpsig, str.encode("__", 'utf-8') )    

# Convert the sig back to ascii
z = sig.decode('ascii')

# add the sig to the URL base
url_base += url_params.decode('ascii') + "&sig=" + z

# request the URL base
r = requests.get(url_base)

# print the response
print(r.content)

You should get something like this for the output:

{"errors": [], "data": {"mobile_url": "http://m.goodrx.com/?grx_ref=api#/drug/atorvastatin/tablet", "form": "tablet", "url": "http://www.goodrx.com/atorvastatin?grx_ref=api", "brand": ["lipitor"], "dosage": "20mg", "price": 12.0, "generic": ["atorvastatin"], "quantity": 30, "display": "Lipitor (atorvastatin)", "manufacturer": "generic"}, "success": true}

Here's similar code in PHP, looking up the drug Apidra Solostar, which has NDC 00088250205:

<?php
function base64url_encode($data) { 
    return strtr(base64_encode($data), '+/', '__'); 
} 

$my_api_key = "YOUR_API_KEY";
$s_key="YOUR_SECRET_KEY";
$ndc = "00088250205";

// Initialize the CURL package. This is the thing that sends HTTP requests
$ch = curl_init();

// Create the URL and the hash
$url = "https://api.goodrx.com/fair-price?";

$query_string="ndc=" . $ndc . "&api_key=" . $my_api_key;

$tmp_sig = hash_hmac('sha256', $query_string, $s_key, true);
$sig = base64url_encode( $tmp_sig );

$url = $url . $query_string . "&sig=" . $sig;

// set some curl options
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_HEADER, FALSE);
curl_setopt($ch, CURLOPT_VERBOSE, true);

// run the query
$response = curl_exec($ch);

var_dump($response);
?>

Thanks to Thomas for talking with me on this.