【问题标题】:PHP Handling API to not exceed its limit?PHP处理API不超过其限制?
【发布时间】:2012-10-28 04:47:33
【问题描述】:

我想知道我该怎么做才能不对 API 进行多次调用?例如,如果我尝试使用 yelp 的 api,他们会在超出之前限制调用次数(一旦超出该数量,他们就会停止向您提供信息)。

我能做什么?现在,我需要从他们的网站获取信息的每个页面都有这个(来自他们的 API PHP 示例):

// For example, request business with id 'the-waterboy-sacramento'
//$unsigned_url = "http://api.yelp.com/v2/business/the-waterboy-sacramento";


// For examaple, search for 'tacos' in 'sf'
//$unsigned_url = "http://api.yelp.com/v2/search?term=tacos&location=sf";

// My own code
$unsigned_url = "http://api.yelp.com/v2/search?term=".$term."";
// $term is coming from searching

// Set your keys here
$consumer_key = "some_id";
$consumer_secret = "some_id";
$token = "some_id";
$token_secret = "some_id";

// Token object built using the OAuth library
$token = new OAuthToken($token, $token_secret);

// Consumer object built using the OAuth library
$consumer = new OAuthConsumer($consumer_key, $consumer_secret);

// Yelp uses HMAC SHA1 encoding
$signature_method = new OAuthSignatureMethod_HMAC_SHA1();

// Build OAuth Request using the OAuth PHP library. Uses the consumer and token object created above.
$oauthrequest = OAuthRequest::from_consumer_and_token($consumer, $token, 'GET', $unsigned_url);

// Sign the request
$oauthrequest->sign_request($signature_method, $consumer, $token);

// Get the signed URL
$signed_url = $oauthrequest->to_url();

// Send Yelp API Call
$ch = curl_init($signed_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, 0);
$data = curl_exec($ch); // Yelp response
curl_close($ch);

当我想打电话给某家公司时,在每个页面上都这样做似乎有些过分。

【问题讨论】:

    标签: php api function caching oauth


    【解决方案1】:

    我不使用它,但作为一般答案,考虑将数据缓存在数据库中以减少 API 调用。它还将提高您网站的性能,尤其是在需要来自 API 的相同数据的同一页面多次加载时。

    这是一个基于文件的通用实现

    /**
    * Cache friendly function call stub.
    * 
    * @param callback $Callback
    * @param array $Arguments
    * @param integer $Expiration
    * @return mixed
    */
    function CallFunctionAndCacheResult($Callback, array $Arguments, $Expiration = 3600){
        // Validate $Callback
        if(!is_callable($Callback)){
            trigger_error('$Callback must be a callback.', E_USER_WARNING);
            return false;
        }
        // Validate $Arguments (we need some to hash)
        if(empty($Arguments)){
            trigger_error('$Arguments cannot be empty.', E_USER_WARNING);
            return false;
        }
        // Empty $Expiration means live calls
        if(empty($Expiration)){
            return call_user_func_array($Callback, $Arguments);
        }
        // Validate $Expiration (we need some to hash)
        if(!is_numeric($Expiration) or (($Expiration = intval($Expiration)) < 1)){
            trigger_error('$Expiration has to be a positive integer.', E_USER_WARNING);
            return false;
        }
        // Hash the Arguments (Unique Call ID)
        $Hash = md5(serialize($Arguments));
        // Check if Cache file exists
        if(is_file($Cache = dirname(__FILE__)."/{$Hash}.serial")){
            // Test if file expired
            if(($MTime = filemtime($Cache)) >= (time() - $Expiration)){
                // Attempt to load data, assume it's corrupted
                if(($Data = unserialize(file_get_contents($Cache))) !== false){
                    return $Data;
                }
            }
        }
        // Now regenerate the data if you got here
        $Data = call_user_func_array($Callback, $Arguments);
        // Store it, with  LOCK_EX enabled to prevent collisions
        file_put_contents($Cache, serialize($Data), LOCK_EX);
        // Return the data
        return $Data;
    }
    
    // Test case (store current time for 10 seconds, keep refreshing)
    var_dump($Data = CallFunctionAndCacheResult(function(){
        // Return some data to be cached
        return array_merge(func_get_args(), array(
            'cached'    => gmstrftime('%A, %d %B %Y %H:%M:%S'),
        ));
    }, array(
        'Username',
        'Password',
        // ...
    ), 10));
    

    希望它有意义。只需对其进行测试,弄清楚并使用数据库引擎来获得相同的结果。

    【讨论】:

    • 你有什么可以参考的吗?谢谢
    • @andrewliu 不是真的,这对我来说很自然......而且我是个坏老师:) 你必须进入 API 调用的中间并缓存到数据库。然后,在以后的调用中,检查参数哈希是否匹配并从数据库返回结果而不是进行实时调用......但还要设置过期时间,以便最终刷新数据。您需要使用数据库和函数来处理调用以允许轻松缓存。查看 mysqli 对象并从那里开始。但也许你会在这里找到关于 SO 的提示。
    • 所以我的代码仍然必须在每个页面中?但是我还需要将缓存添加到每个页面中?
    • @andrewliu 这完全取决于您的设计。但我会编写一个函数(或更多函数来处理您的 API 调用)并将其放在一个文件中,并将该文件包含在您需要用于查询 API 的函数的位置。然后根据您所在的页面和需要在该页面上检索的数据调用具有不同参数的函数。重复代码进入通常在全局 include_once 中包含的函数中。
    • 请注意,Yelp API 使用条款似乎禁止缓存:“您同意您不会……缓存、记录、预取或以其他方式存储 Yelp 内容的任何部分。 .." yelp.com/developers/getting_started/api_terms
    【解决方案2】:

    缓存在这里是您的朋友。当您认为自己一遍又一遍地执行不需要的 API 查询时,您应该将信息缓存到 cookie(如果它是次要/非关键的),或者缓存到数据库。

    例如,如果用户希望刷新我运行查询以获取他的姓名的页面,我不想超出限制。你可以得到他的名字一次,把它存储到一个 cookie 中,然后使用它而不是每次都查询。就像另一个答案所说,更快,更高效。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-08-28
      • 2021-04-26
      • 2015-05-11
      • 1970-01-01
      • 2018-09-23
      • 1970-01-01
      • 1970-01-01
      • 2015-02-13
      相关资源
      最近更新 更多