Tom Kincaid
Tom Kincaid

Reputation: 4975

How to use paging in the Facebook Graph API?

When using the Facebook Graph API to return more than 500 elements (like a friend list) paging is required. What's a good way to do this?

Upvotes: 2

Views: 3205

Answers (1)

Tom Kincaid
Tom Kincaid

Reputation: 4975

Here is the way that I use paging on my own apps.

http://developsocialapps.com/facebook-friends-list-and-paging/

The library has most of the code needed. The main method is getGraphObjectWithPaging. It gets the object with the graph API and then keeps looping as long as there is a next page in the response or the $maxpages has been reached. One peculiarity is that sometimes Facebook returns the next page as the same page you just got, so it checks for this and stops at that point too.

class FacebookApp {               

    public $appId;
    private $appSecret;
    private $nameSpace;
    public $userId;
    public $token;
    public $tokenExpires;

    // get your own from http://www.w3.org/P3P/
    public $p3p = 'P3P:CP="IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT"'; 

    /*  construct object 
        appid, secret, and namespace from app settings  */
    public function __construct($id, $secret, $namespace) {
        $this->appId = $id;
        $this->appSecret = $secret;
        $this->nameSpace = $namespace;
    }

    /*  return json data from a graph api object using paging   
        $object = object to get
        limit = limit parameter for API object
        maxpages = maximum number of pages to get   */
    function getGraphObjectWithPaging($object,$limit=500,$maxpages=10) {
        $data = array();
        $url = $this->getGraphUrl($object,$limit);
        // loop through API calls until maxpages or no paging->next
        while ($maxpages > 0) {
            $response = $this->makeCurlRequest($url);
            if ($repsonse === false) {
                // something went wrong
                break;
            } else {
                $jsonarray = json_decode($response,true);
                if (isset($jsonarray['error'])) {
                    // something went wrong
                    break;
                } else {
                    // add current data to data array
                    $data = array_merge ($data,$jsonarray['data']);
                    if (isset($jsonarray['paging']['next'])) {
                        if ($url == $jsonarray['paging']['next']) {
                            // for some reason facebook sometimes returns a next url which is the same as we just got, so exit here
                            break;
                        } else {
                            // keep looping
                            $url = $jsonarray['paging']['next'];
                            $maxpages--;
                        }
                    } else {
                        // no more pages
                        break;
                    }
                }
            }
        }
        return array("data"=>$data); // using data so it is the same format as other API repsonses
    }

    /*  constructs graphs url   */
    public function getGraphUrl($object,$limit=false) {
        $url = "https://graph.facebook.com/".$object;
        if (strpos($url,"?") === false) $url .= "?";
        else $url .= "&";
        $url .= "access_token=".$this->token;
        if ($limit !== false) $url .= "&limit=".$limit;
        return $url;
    }

    /*  uses curl to get a url, use $postarray to make a post, otherwise it will get    */
    public function makeCurlRequest($url,$postarray=false) { 
        $return = false;
        try {
            $ch = curl_init(); 
            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_HEADER, false); 
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 
            if($postarray !== false){ 
                curl_setopt ($ch, CURLOPT_POST, true); 
                curl_setopt ($ch, CURLOPT_POSTFIELDS, $postarray); 
            } 
            $response = curl_exec($ch); 
            $responseInfo = curl_getinfo($ch); 
            curl_close($ch); 
            if ($responseInfo['http_code']==200) { 
                $return = $response; 
            } 
        } catch (Exception $e) {
            $return = false; 
        }
        return $return;
    } 

    /*  sets userid and token from signed request, return true or false if authorized   */
    public function initOauthUserFromSignedRequest() {
        $authorized = false;
        if (isset($_REQUEST['signed_request'])) {
            $data = $this->parseSignedRequest($_REQUEST['signed_request']);
            if ($data !== false) {
                if (isset($data['user_id']) && isset($data['oauth_token'])) {
                    $this->userId = $data['user_id'];
                    $this->token = $data['oauth_token'];
                    $this->tokenExpires = $data['expires'];
                    $authorized = true;
                }
            }
        }
        return $authorized;
    }

    /*  require user to authorize and have permissions for page
        redirect_uri = url to return after user has authorized like redirect.php
        success_uri = url to redirect to on successful authorization like mypage.php
        scope = comma separted list of permissions  */
    function requireAuthorization($redirect_uri,$success_uri=false,$scope=false) {
        if ($success_uri === false) {
            // if no success_uri use current page, all files for app must be in same directory
            $success_uri = substr($_SERVER['REQUEST_URI'],strrpos($_SERVER['REQUEST_URI'],"/")+1); 
        }
        $this->setCookie ("success_uri",$success_uri,0); // we will use this on the redirect_uri page
        $requireauth = true;
        if ($this->initOauthUserFromSignedRequest()) { // user has authorized
            if (($scope === false) || ($this->hasAllPermissions($scope))) { // now check for perms
                $requireauth = false;
            }
        }
        if ($requireauth) { // user is either not authorized or doesn't have permissions
            $url = $this->getAuthUrl($this->getCanvasUrl($redirect_uri),$scope);
            echo "<html>\n<body>\n<script>\ntop.location.href='".$url."';\n</script></body></html>";
            exit();
        }
    }

    /*  checks to see if has permissions, scope is comma separated list */
    public function hasAllPermissions($scope) {
        $return = false;
        $cookiename = "permissions_".$this->appId."_".$this->userId;
        $requiredpermissions = explode(",",$scope);
        // first check cookie
        if (isset($_COOKIE[$cookiename])) {
            $return = true;
            $permissions = json_decode($_COOKIE[$cookiename],true);
            foreach ($requiredpermissions as $perm) {
                if ($permissions['data'][0][$perm] != 1) {
                    $return = false;
                    break;
                }
            }
        }
        // if didn't have all in cookie, then see if it is in graph 
        if ($return == false) {
            $permissions = $this->getGraphObject("me/permissions");
            if ($permissions !== false) {
                $this->setCookie($cookiename,json_encode($permissions),0);
                $return = true;
                foreach ($requiredpermissions as $perm) {
                    if ($permissions['data'][0][$perm] != 1) {
                        $return = false;
                        break;
                    }
                }   
            }
        }
        return $return;
    }

    /*  sets a cookie with p3p headers  */
    public function setCookie($name,$value,$expires) {
        if ($this->p3p != '') {
            header($this->p3p);
            $this->p3p = '';
        }
        setcookie ($name,$value,$expires,"/"); 
    }

    /*  returns url for oauth authorization
        redirect_uri = url to return after user has authorized
        scope = comma separted list of permissions  */
    public function getAuthUrl($redirect_uri,$scope=false) {
        $url = "https://www.facebook.com/dialog/oauth/?client_id=".$this->appId."&redirect_uri=".rawurlencode($redirect_uri);
        if ($scope !== false) $url .= "&scope=".rawurlencode($scope);
        return $url;
    }

    /* returns url to app canvas page, $page like mypage.php?foo=bar    */
    public function getCanvasUrl($page) {
        if ($_SERVER['HTTPS'] == "on") $protocol = "https";
        else $protocol = "http";
        return $protocol."://apps.facebook.com/".$this->nameSpace."/".$page;
    }

    /*  parses signed_request parameter and returns data object, returns false if sigs don't match  */
    public function parseSignedRequest($signed_request) {
        list($encoded_sig, $payload) = explode('.', $signed_request, 2); 
        $data = json_decode(base64_decode(strtr($payload, '-_', '+/')), true);
        $sig = base64_decode(strtr($encoded_sig, '-_', '+/'));
        $expected_sig = hash_hmac('sha256', $payload, $this->appSecret, true);
        if ($sig == $expected_sig) {
            return $data;
        } else {
            return false;
        }
    }

}

Here is how to use it on a page:

$facebookapp = new FacebookApp($GLOBALS['facebookAppId'],$GLOBALS['facebookAppSecret'],$GLOBALS['facebookNamespace']);

$facebookapp->requireAuthorization($GLOBALS['facebookRedirectPage']);

$friends = $facebookapp->getGraphObjectWithPaging("me/friends");

Upvotes: 2

Related Questions