Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Facebook Graph API caching JSON response

I am using Facebook Graph API to get contents from a Facebook fan page and then display them into a website. I am doing it like this, and it is working, but somehow, it seems that my hosting provider is limiting my requests every certain time.... So I would like to cache the response and only ask for a new request every 8h for example.

$data = get_data("https://graph.facebook.com/12345678/posts?access_token=1111112222233333&limit=20&fields=full_picture,link,message,likes,comments&date_format=U");
$result = json_decode($data);

The get_data function uses CURL in the following way:

function get_data($url) {
    $ch = curl_init();
    $timeout = 5;
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    $datos = curl_exec($ch);
    curl_close($ch);
    return $datos;
}

This works fine, I can output the JSON data response and use it as I like into my website to display the content. But as I mention, in my hosting, this seems to fail every X time, I guess because I am getting limited. I have tried to cache the response using some code I saw here at Stackoverflow. But I cannot figure out how to integrate and use both codes. I have managed to create the cache file, but I cannot manage to read correctly from the cached file and avoid making a new request to Facebook graph API.

// cache files are created like cache/abcdef123456...
    $cacheFile = 'cache' . DIRECTORY_SEPARATOR . md5($url);

    if (file_exists($cacheFile)) {
        $fh = fopen($cacheFile, 'r');
        $cacheTime = trim(fgets($fh));

        // if data was cached recently, return cached data
        if ($cacheTime > strtotime('-60 minutes')) {
            return fread($fh);
        }

        // else delete cache file
        fclose($fh);
        unlink($cacheFile);
    }

$fh = fopen($cacheFile, 'w');
    fwrite($fh, time() . "\n");
    fwrite($fh, $json);
    fclose($fh);

return $json;

Many thanks in advance for your help!

like image 317
qalbiol Avatar asked Jun 07 '15 09:06

qalbiol


People also ask

Is Facebook Graph API RESTful?

The Legacy REST API is in the process of being deprecated, while the Graph API is the most current, so if you're unsure of which one to use, your best bet is to go with that one. As you suggested, the Graph API, just like the Legacy REST API, is in fact a RESTful API.

What 3 terms does Facebook use to describe what the graph API is composed of?

The Graph API is named after the idea of a "social graph" — a representation of the information on Facebook. It's composed of nodes, edges, and fields.

How do I make a graph API on Facebook?

Go to “My apps” drop down in the top right corner and select “add a new app”. Choose a display name and a category and then “Create App ID”. Again get back to the same link developers.facebook.com/tools/explorer. You will see “Graph API Explorer” below “My Apps” in the top right corner.


4 Answers

There are some thinks that could come in handy when trying to construct cache and to cache actual object (or even arrays).

The functions serialize and unserialize allows you to get a string representation of an object or of an array so you can cache it as plain text and then pop the object/array as it was before from the string.

filectime which allows you to get the last modification date of a file, so when it is created, you can rely on this information to see if your cache is outdated like you tried to implement it.

And for the whole working code, there you go :

function get_data($url) {
    /** @var $cache_file is path/to/the/cache/file/based/on/md5/url */
    $cache_file = 'cache' . DIRECTORY_SEPARATOR . md5($url);
    if(file_exists($cache_file)){
        /** 
         * Using the last modification date of the cache file to check its validity 
         */
        if(filectime($cache_file) < strtotime('-60 minutes')){
            unlink($cache_file);
        } else {
            echo 'TRACE -- REMOVE ME -- out of cache';
            /** 
             * unserializing the object on the cache file 
             * so it gets is original "shape" : object, array, ...  
             */
            return unserialize(file_get_contents($cache_file));
        }
    }

    $ch = curl_init();
    $timeout = 5;
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    $data = curl_exec($ch);
    curl_close($ch);

    /** 
     * We actually did the curl call so we need to (re)create the cache file 
     * with the string representation of our curl return we got from serialize 
     */
    file_put_contents($cache_file, serialize($data));

    return $data;
}

PS : note that I changed the $datos variable on your actual function get_data to a more common $data.

like image 66
β.εηοιτ.βε Avatar answered Oct 05 '22 09:10

β.εηοιτ.βε


This answer will add a few more dependencies to your project, but it may be well worth it instead of rolling your own stuff.

You could use the Guzzle HTTP client, coupled with the HTTP Cache plugin.

$client = new Client('http://www.test.com/');

$cachePlugin = new CachePlugin(array(
    'storage' => new DefaultCacheStorage(
        new DoctrineCacheAdapter(
            new FilesystemCache('/path/to/cache/files')
        )
    )
));

$client->addSubscriber($cachePlugin);

$request = $client->get('https://graph.facebook.com/12345678/posts?access_token=1111112222233333&limit=20&fields=full_picture,link,message,likes,comments&date_format=U');
$request->getParams()->set('cache.override_ttl', 3600*8); // 8hrs

$data = $request->send()->getBody();
$result = json_decode($data);
like image 44
Ja͢ck Avatar answered Oct 05 '22 08:10

Ja͢ck


Not sure is you can use memcache, if you can:

$cacheFile = 'cache' . DIRECTORY_SEPARATOR . md5($url);
$mem = new Memcached();
$mem->addServer("127.0.0.1", 11211);
$cached = $mem->get($cacheFile);
if($cached){
  return $cached;
}
else{
  $data = get_data($url);
  $mem->set($cacheFile, json_encode($data), time() + 60*10); //10 min
}
like image 40
ziggrat Avatar answered Oct 05 '22 08:10

ziggrat


If your hosting provider is pushing all of your outbound requests through a proxy server -- you can try to defeat it by adding an extra parameter near the beginning of the request :

https://graph.facebook.com/12345678/posts?p=(randomstring)&access_token=1111112222233333&limit=20&fields=full_picture,link,message,likes,comments&date_format=U

I have used this successfully for outbound calls to third party data providers. Of course I don't know if your particular issue is this issue. You could also be bitten by the provider if they reject requests with parameters they don't expect.

like image 37
DragonYen Avatar answered Oct 05 '22 07:10

DragonYen