0

我正在尝试实现 keek.com API,特别是“搜索 keek”功能(https://developers.keek.com/api/commands/search_keek)。一个搜索词一切正常,但如果我尝试使用两个或多个词搜索词,则会出现错误“4006 Signature Is Invalid”。据我了解,这是因为空格或其他一些非字母字符的 url 编码不正确。这是我的代码,它适用于单词短语,但不适用于多词短语:

    $apiKey = Yii::app()->params['keek']['api_key'];
    $apiSecret = Yii::app()->params['keek']['api_secret'];
    $timestamp = time();

    $paramsArr = array(
        'auth_api' => $apiKey,
        'auth_timestamp' => $timestamp,
        'term' => $searchPhrase,         
        'number' => Yii::app()->params['keek']['keeks_per_page'],
    );

    // calculate min id (for pagination)
    if(isset($socialPageParam[Yii::app()->params['searchEngines']['enginesUrls']['keek']])
        && !empty($socialPageParam[Yii::app()->params['searchEngines']['enginesUrls']['keek']]))
    {
        $sinceId = min(
            $socialPageParam[Yii::app()->params['searchEngines']['enginesUrls']['keek']]
        );

        if($sinceId)
            $paramsArr['since_id'] = $sinceId;
    }         

    // sort alphabeticaly
    ksort($paramsArr);

    $paramsOfQueryStr = http_build_query($paramsArr);

    $paramsOfQueryStr = str_replace(
        array('+', '%7E'), 
        array('%20', '~'), 
        $paramsOfQueryStr
    );


    $urlEncodedRequest = rawurlencode($paramsOfQueryStr);

    $apiUrl = Yii::app()->params['keek']['api_search_keeks_url'];

    $initalAPIurl = rawurlencode($apiUrl);

    // forming signature base
    $signatureBase = 'GET&' . $initalAPIurl . '&' .  $urlEncodedRequest;

    // forming signing token
    $signingToken = $apiKey . '&' . $timestamp . '&' . $apiSecret;

    // forming signature as hashed by sha1 string in binary
    $signature = base64_encode(hash_hmac('sha1', $signatureBase, $signingToken, true));

    // add signature to headers
    $headersArr = array(
        "API: $apiKey",
        "Timestamp: $timestamp",
        "Signature: $signature",                
    );

    // forming full url to call
    $fullUrl = $apiUrl . '?' . $paramsOfQueryStr;

    // make call to keek's API
    $apiRes = Yii::app()->utils->curlGetContent($fullUrl, $headersArr);                   

    var_dump($apiRes);die;

如果知道如何解决此问题,请帮助我。先感谢您。

4

1 回答 1

0

我已经想通了。现在我有这个代码的两个工作版本 - 一个是 js,另一个是 php。

js:

var timestamp = Math.round(new Date().getTime() / 1000);
var api = '(your api)';
var secret = '(your secret)';

var theUrl = "http://api.keek.com/v/1/keek/search?term="+encodeURIComponent("message me");
var parameterString = "auth_api=" + encodeURIComponent(api) + "&auth_timestamp=" + encodeURIComponent(timestamp) + "&term=" + encodeURIComponent(encodeURIComponent("message me"));
console.log("PARAMSTRING: "+parameterString);
var signatureBaseString = "GET&" + encodeURIComponent("http://api.keek.com/v/1/keek/search") + "&" + encodeURIComponent(parameterString);
console.log("SIGBASE: "+signatureBaseString);

var signingToken = api + "&" + timestamp + "&" + secret;

var hash = CryptoJS.HmacSHA1(signatureBaseString, signingToken);

var signature = hash.toString(CryptoJS.enc.Base64);

console.log('cmd: ','curl -v -H "API:'+api+'" -H "Timestamp:'+timestamp+'" -H "Signature:'+signature+'" '+ theUrl);

var thisCode = 'curl -v -H "API:'+api+'" -H "Timestamp:'+timestamp+'" -H "Signature:'+signature+'" '+ theUrl;


window.onload = function() {
output = document.getElementById("output");
output.value = thisCode;
};

PHP:

    $apiKey = 'api key here';
    $apiSecret = 'api secret here';
    $timestamp = time();

    $searchStr = Yii::app()->utils->encodeURIComponent('usa today');

    $data = array(
        'auth_api'=>'1e8b017d015d690a69a487995339561ed7d8cce7',
        'auth_timestamp'=>$timestamp,
        'term' => $searchStr,
    );

    ksort($data);

    $urlEncodedRequest = '';

    foreach($data as $paramName => $paramVal)
    {
        $urlEncodedRequest .= "&$paramName=" . Yii::app()->utils->encodeURIComponent($paramVal);
    }

    $urlEncodedRequest = substr($urlEncodedRequest, 1, strlen($urlEncodedRequest));        
    $urlEncodedRequest = Yii::app()->utils->encodeURIComponent($urlEncodedRequest);

    $url = 'http://api.keek.com/v/1/user/search?term=' . $searchStr;

    $initalAPIurl = Yii::app()->utils->encodeURIComponent('http://api.keek.com/v/1/user/search');

    $signatureBase = 'GET&' . $initalAPIurl . '&' .  $urlEncodedRequest;

    $signingToken = $apiKey . '&' . $timestamp . '&' . $apiSecret;
    $signature = base64_encode(hash_hmac('sha1', $signatureBase, $signingToken, true));

    $headersArr = array(
        "API: $apiKey",
        "Timestamp: $timestamp",
        "Signature: $signature",                
    );

    var_dump(Yii::app()->utils->curlGetContent($url, $headersArr));   

错误出现在 php rawurlencode() 函数中。相反,我使用了 js encodeURIComponent() 函数的 php 模拟:

function encodeURIComponent($str) 
{
    $revert = array('%21'=>'!', '%2A'=>'*', '%27'=>"'", '%28'=>'(', '%29'=>')');
    return strtr(rawurlencode($str), $revert);
}

您还应该对搜索短语(在我的第一个示例中为 $searchPhrase)进行两次编码。现在一切正常。享受您的 keek api 实现。

于 2013-09-18T11:41:49.133 回答