├── README ├── config.php ├── friends.php ├── index.php ├── library ├── facebook.php └── fb_ca_chain_bundle.crt ├── photos.php ├── photos_add.php ├── rest_user_isappuser.php ├── status.php ├── status_add.php └── user.php /README: -------------------------------------------------------------------------------- 1 | Here are a few examples on using the Facebook Graph API with the PHP SDK. Download the files, edit the config.php file to enter your app id and secrete, then run the index.php page. For more information visit my blog post at: 2 | 3 | http://www.joeyrivera.com/2010/facebook-graph-api-app-easy-w-php-sdk/ -------------------------------------------------------------------------------- /config.php: -------------------------------------------------------------------------------- 1 | $app_id, 9 | 'secret' => $app_secret, 10 | 'cookie' => true 11 | )); 12 | 13 | if(is_null($facebook->getUser())) 14 | { 15 | header("Location:{$facebook->getLoginUrl(array('req_perms' => 'user_status,publish_stream,user_photos'))}"); 16 | exit; 17 | } -------------------------------------------------------------------------------- /friends.php: -------------------------------------------------------------------------------- 1 | api('/me/friends'); 6 | var_dump($friends); -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | 4 |

Status

5 | View Status 6 | Add Status 7 | 8 |

Photos

9 | View Photos 10 | Add Photo 11 | 12 |

Friends

13 | View List 14 | 15 |

Rest

16 | User: Is App User -------------------------------------------------------------------------------- /library/facebook.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | class FacebookApiException extends Exception 16 | { 17 | /** 18 | * The result from the API server that represents the exception information. 19 | */ 20 | protected $result; 21 | 22 | /** 23 | * Make a new API Exception with the given result. 24 | * 25 | * @param Array $result the result from the API server 26 | */ 27 | public function __construct($result) { 28 | $this->result = $result; 29 | 30 | $code = isset($result['error_code']) ? $result['error_code'] : 0; 31 | 32 | if (isset($result['error_description'])) { 33 | // OAuth 2.0 Draft 10 style 34 | $msg = $result['error_description']; 35 | } else if (isset($result['error']) && is_array($result['error'])) { 36 | // OAuth 2.0 Draft 00 style 37 | $msg = $result['error']['message']; 38 | } else if (isset($result['error_msg'])) { 39 | // Rest server style 40 | $msg = $result['error_msg']; 41 | } else { 42 | $msg = 'Unknown Error. Check getResult()'; 43 | } 44 | 45 | parent::__construct($msg, $code); 46 | } 47 | 48 | /** 49 | * Return the associated result object returned by the API server. 50 | * 51 | * @returns Array the result from the API server 52 | */ 53 | public function getResult() { 54 | return $this->result; 55 | } 56 | 57 | /** 58 | * Returns the associated type for the error. This will default to 59 | * 'Exception' when a type is not available. 60 | * 61 | * @return String 62 | */ 63 | public function getType() { 64 | if (isset($this->result['error'])) { 65 | $error = $this->result['error']; 66 | if (is_string($error)) { 67 | // OAuth 2.0 Draft 10 style 68 | return $error; 69 | } else if (is_array($error)) { 70 | // OAuth 2.0 Draft 00 style 71 | if (isset($error['type'])) { 72 | return $error['type']; 73 | } 74 | } 75 | } 76 | return 'Exception'; 77 | } 78 | 79 | /** 80 | * To make debugging easier. 81 | * 82 | * @returns String the string representation of the error 83 | */ 84 | public function __toString() { 85 | $str = $this->getType() . ': '; 86 | if ($this->code != 0) { 87 | $str .= $this->code . ': '; 88 | } 89 | return $str . $this->message; 90 | } 91 | } 92 | 93 | /** 94 | * Provides access to the Facebook Platform. 95 | * 96 | * @author Naitik Shah 97 | */ 98 | class Facebook 99 | { 100 | /** 101 | * Version. 102 | */ 103 | const VERSION = '2.1.2'; 104 | 105 | /** 106 | * Default options for curl. 107 | */ 108 | public static $CURL_OPTS = array( 109 | CURLOPT_CONNECTTIMEOUT => 10, 110 | CURLOPT_RETURNTRANSFER => true, 111 | CURLOPT_TIMEOUT => 60, 112 | CURLOPT_USERAGENT => 'facebook-php-2.0', 113 | ); 114 | 115 | /** 116 | * List of query parameters that get automatically dropped when rebuilding 117 | * the current URL. 118 | */ 119 | protected static $DROP_QUERY_PARAMS = array( 120 | 'session', 121 | 'signed_request', 122 | ); 123 | 124 | /** 125 | * Maps aliases to Facebook domains. 126 | */ 127 | public static $DOMAIN_MAP = array( 128 | 'api' => 'https://api.facebook.com/', 129 | 'api_read' => 'https://api-read.facebook.com/', 130 | 'graph' => 'https://graph.facebook.com/', 131 | 'www' => 'https://www.facebook.com/', 132 | ); 133 | 134 | /** 135 | * The Application ID. 136 | */ 137 | protected $appId; 138 | 139 | /** 140 | * The Application API Secret. 141 | */ 142 | protected $apiSecret; 143 | 144 | /** 145 | * The active user session, if one is available. 146 | */ 147 | protected $session; 148 | 149 | /** 150 | * The data from the signed_request token. 151 | */ 152 | protected $signedRequest; 153 | 154 | /** 155 | * Indicates that we already loaded the session as best as we could. 156 | */ 157 | protected $sessionLoaded = false; 158 | 159 | /** 160 | * Indicates if Cookie support should be enabled. 161 | */ 162 | protected $cookieSupport = false; 163 | 164 | /** 165 | * Base domain for the Cookie. 166 | */ 167 | protected $baseDomain = ''; 168 | 169 | /** 170 | * Indicates if the CURL based @ syntax for file uploads is enabled. 171 | */ 172 | protected $fileUploadSupport = false; 173 | 174 | /** 175 | * Initialize a Facebook Application. 176 | * 177 | * The configuration: 178 | * - appId: the application ID 179 | * - secret: the application secret 180 | * - cookie: (optional) boolean true to enable cookie support 181 | * - domain: (optional) domain for the cookie 182 | * - fileUpload: (optional) boolean indicating if file uploads are enabled 183 | * 184 | * @param Array $config the application configuration 185 | */ 186 | public function __construct($config) { 187 | $this->setAppId($config['appId']); 188 | $this->setApiSecret($config['secret']); 189 | if (isset($config['cookie'])) { 190 | $this->setCookieSupport($config['cookie']); 191 | } 192 | if (isset($config['domain'])) { 193 | $this->setBaseDomain($config['domain']); 194 | } 195 | if (isset($config['fileUpload'])) { 196 | $this->setFileUploadSupport($config['fileUpload']); 197 | } 198 | } 199 | 200 | /** 201 | * Set the Application ID. 202 | * 203 | * @param String $appId the Application ID 204 | */ 205 | public function setAppId($appId) { 206 | $this->appId = $appId; 207 | return $this; 208 | } 209 | 210 | /** 211 | * Get the Application ID. 212 | * 213 | * @return String the Application ID 214 | */ 215 | public function getAppId() { 216 | return $this->appId; 217 | } 218 | 219 | /** 220 | * Set the API Secret. 221 | * 222 | * @param String $appId the API Secret 223 | */ 224 | public function setApiSecret($apiSecret) { 225 | $this->apiSecret = $apiSecret; 226 | return $this; 227 | } 228 | 229 | /** 230 | * Get the API Secret. 231 | * 232 | * @return String the API Secret 233 | */ 234 | public function getApiSecret() { 235 | return $this->apiSecret; 236 | } 237 | 238 | /** 239 | * Set the Cookie Support status. 240 | * 241 | * @param Boolean $cookieSupport the Cookie Support status 242 | */ 243 | public function setCookieSupport($cookieSupport) { 244 | $this->cookieSupport = $cookieSupport; 245 | return $this; 246 | } 247 | 248 | /** 249 | * Get the Cookie Support status. 250 | * 251 | * @return Boolean the Cookie Support status 252 | */ 253 | public function useCookieSupport() { 254 | return $this->cookieSupport; 255 | } 256 | 257 | /** 258 | * Set the base domain for the Cookie. 259 | * 260 | * @param String $domain the base domain 261 | */ 262 | public function setBaseDomain($domain) { 263 | $this->baseDomain = $domain; 264 | return $this; 265 | } 266 | 267 | /** 268 | * Get the base domain for the Cookie. 269 | * 270 | * @return String the base domain 271 | */ 272 | public function getBaseDomain() { 273 | return $this->baseDomain; 274 | } 275 | 276 | /** 277 | * Set the file upload support status. 278 | * 279 | * @param String $domain the base domain 280 | */ 281 | public function setFileUploadSupport($fileUploadSupport) { 282 | $this->fileUploadSupport = $fileUploadSupport; 283 | return $this; 284 | } 285 | 286 | /** 287 | * Get the file upload support status. 288 | * 289 | * @return String the base domain 290 | */ 291 | public function useFileUploadSupport() { 292 | return $this->fileUploadSupport; 293 | } 294 | 295 | /** 296 | * Get the data from a signed_request token 297 | * 298 | * @return String the base domain 299 | */ 300 | public function getSignedRequest() { 301 | if (!$this->signedRequest) { 302 | if (isset($_REQUEST['signed_request'])) { 303 | $this->signedRequest = $this->parseSignedRequest( 304 | $_REQUEST['signed_request']); 305 | } 306 | } 307 | return $this->signedRequest; 308 | } 309 | 310 | /** 311 | * Set the Session. 312 | * 313 | * @param Array $session the session 314 | * @param Boolean $write_cookie indicate if a cookie should be written. this 315 | * value is ignored if cookie support has been disabled. 316 | */ 317 | public function setSession($session=null, $write_cookie=true) { 318 | $session = $this->validateSessionObject($session); 319 | $this->sessionLoaded = true; 320 | $this->session = $session; 321 | if ($write_cookie) { 322 | $this->setCookieFromSession($session); 323 | } 324 | return $this; 325 | } 326 | 327 | /** 328 | * Get the session object. This will automatically look for a signed session 329 | * sent via the signed_request, Cookie or Query Parameters if needed. 330 | * 331 | * @return Array the session 332 | */ 333 | public function getSession() { 334 | if (!$this->sessionLoaded) { 335 | $session = null; 336 | $write_cookie = true; 337 | 338 | // try loading session from signed_request in $_REQUEST 339 | $signedRequest = $this->getSignedRequest(); 340 | if ($signedRequest) { 341 | // sig is good, use the signedRequest 342 | $session = $this->createSessionFromSignedRequest($signedRequest); 343 | } 344 | 345 | // try loading session from $_REQUEST 346 | if (!$session && isset($_REQUEST['session'])) { 347 | $session = json_decode( 348 | get_magic_quotes_gpc() 349 | ? stripslashes($_REQUEST['session']) 350 | : $_REQUEST['session'], 351 | true 352 | ); 353 | $session = $this->validateSessionObject($session); 354 | } 355 | 356 | // try loading session from cookie if necessary 357 | if (!$session && $this->useCookieSupport()) { 358 | $cookieName = $this->getSessionCookieName(); 359 | if (isset($_COOKIE[$cookieName])) { 360 | $session = array(); 361 | parse_str(trim( 362 | get_magic_quotes_gpc() 363 | ? stripslashes($_COOKIE[$cookieName]) 364 | : $_COOKIE[$cookieName], 365 | '"' 366 | ), $session); 367 | $session = $this->validateSessionObject($session); 368 | // write only if we need to delete a invalid session cookie 369 | $write_cookie = empty($session); 370 | } 371 | } 372 | 373 | $this->setSession($session, $write_cookie); 374 | } 375 | 376 | return $this->session; 377 | } 378 | 379 | /** 380 | * Get the UID from the session. 381 | * 382 | * @return String the UID if available 383 | */ 384 | public function getUser() { 385 | $session = $this->getSession(); 386 | return $session ? $session['uid'] : null; 387 | } 388 | 389 | /** 390 | * Gets a OAuth access token. 391 | * 392 | * @return String the access token 393 | */ 394 | public function getAccessToken() { 395 | $session = $this->getSession(); 396 | // either user session signed, or app signed 397 | if ($session) { 398 | return $session['access_token']; 399 | } else { 400 | return $this->getAppId() .'|'. $this->getApiSecret(); 401 | } 402 | } 403 | 404 | /** 405 | * Get a Login URL for use with redirects. By default, full page redirect is 406 | * assumed. If you are using the generated URL with a window.open() call in 407 | * JavaScript, you can pass in display=popup as part of the $params. 408 | * 409 | * The parameters: 410 | * - next: the url to go to after a successful login 411 | * - cancel_url: the url to go to after the user cancels 412 | * - req_perms: comma separated list of requested extended perms 413 | * - display: can be "page" (default, full page) or "popup" 414 | * 415 | * @param Array $params provide custom parameters 416 | * @return String the URL for the login flow 417 | */ 418 | public function getLoginUrl($params=array()) { 419 | $currentUrl = $this->getCurrentUrl(); 420 | return $this->getUrl( 421 | 'www', 422 | 'login.php', 423 | array_merge(array( 424 | 'api_key' => $this->getAppId(), 425 | 'cancel_url' => $currentUrl, 426 | 'display' => 'page', 427 | 'fbconnect' => 1, 428 | 'next' => $currentUrl, 429 | 'return_session' => 1, 430 | 'session_version' => 3, 431 | 'v' => '1.0', 432 | ), $params) 433 | ); 434 | } 435 | 436 | /** 437 | * Get a Logout URL suitable for use with redirects. 438 | * 439 | * The parameters: 440 | * - next: the url to go to after a successful logout 441 | * 442 | * @param Array $params provide custom parameters 443 | * @return String the URL for the logout flow 444 | */ 445 | public function getLogoutUrl($params=array()) { 446 | return $this->getUrl( 447 | 'www', 448 | 'logout.php', 449 | array_merge(array( 450 | 'next' => $this->getCurrentUrl(), 451 | 'access_token' => $this->getAccessToken(), 452 | ), $params) 453 | ); 454 | } 455 | 456 | /** 457 | * Get a login status URL to fetch the status from facebook. 458 | * 459 | * The parameters: 460 | * - ok_session: the URL to go to if a session is found 461 | * - no_session: the URL to go to if the user is not connected 462 | * - no_user: the URL to go to if the user is not signed into facebook 463 | * 464 | * @param Array $params provide custom parameters 465 | * @return String the URL for the logout flow 466 | */ 467 | public function getLoginStatusUrl($params=array()) { 468 | return $this->getUrl( 469 | 'www', 470 | 'extern/login_status.php', 471 | array_merge(array( 472 | 'api_key' => $this->getAppId(), 473 | 'no_session' => $this->getCurrentUrl(), 474 | 'no_user' => $this->getCurrentUrl(), 475 | 'ok_session' => $this->getCurrentUrl(), 476 | 'session_version' => 3, 477 | ), $params) 478 | ); 479 | } 480 | 481 | /** 482 | * Make an API call. 483 | * 484 | * @param Array $params the API call parameters 485 | * @return the decoded response 486 | */ 487 | public function api(/* polymorphic */) { 488 | $args = func_get_args(); 489 | if (is_array($args[0])) { 490 | return $this->_restserver($args[0]); 491 | } else { 492 | return call_user_func_array(array($this, '_graph'), $args); 493 | } 494 | } 495 | 496 | /** 497 | * Invoke the old restserver.php endpoint. 498 | * 499 | * @param Array $params method call object 500 | * @return the decoded response object 501 | * @throws FacebookApiException 502 | */ 503 | protected function _restserver($params) { 504 | // generic application level parameters 505 | $params['api_key'] = $this->getAppId(); 506 | $params['format'] = 'json-strings'; 507 | 508 | $result = json_decode($this->_oauthRequest( 509 | $this->getApiUrl($params['method']), 510 | $params 511 | ), true); 512 | 513 | // results are returned, errors are thrown 514 | if (is_array($result) && isset($result['error_code'])) { 515 | throw new FacebookApiException($result); 516 | } 517 | return $result; 518 | } 519 | 520 | /** 521 | * Invoke the Graph API. 522 | * 523 | * @param String $path the path (required) 524 | * @param String $method the http method (default 'GET') 525 | * @param Array $params the query/post data 526 | * @return the decoded response object 527 | * @throws FacebookApiException 528 | */ 529 | protected function _graph($path, $method='GET', $params=array()) { 530 | if (is_array($method) && empty($params)) { 531 | $params = $method; 532 | $method = 'GET'; 533 | } 534 | $params['method'] = $method; // method override as we always do a POST 535 | 536 | $result = json_decode($this->_oauthRequest( 537 | $this->getUrl('graph', $path), 538 | $params 539 | ), true); 540 | 541 | // results are returned, errors are thrown 542 | if (is_array($result) && isset($result['error'])) { 543 | $e = new FacebookApiException($result); 544 | switch ($e->getType()) { 545 | // OAuth 2.0 Draft 00 style 546 | case 'OAuthException': 547 | // OAuth 2.0 Draft 10 style 548 | case 'invalid_token': 549 | $this->setSession(null); 550 | } 551 | throw $e; 552 | } 553 | return $result; 554 | } 555 | 556 | /** 557 | * Make a OAuth Request 558 | * 559 | * @param String $path the path (required) 560 | * @param Array $params the query/post data 561 | * @return the decoded response object 562 | * @throws FacebookApiException 563 | */ 564 | protected function _oauthRequest($url, $params) { 565 | if (!isset($params['access_token'])) { 566 | $params['access_token'] = $this->getAccessToken(); 567 | } 568 | 569 | // json_encode all params values that are not strings 570 | foreach ($params as $key => $value) { 571 | if (!is_string($value)) { 572 | $params[$key] = json_encode($value); 573 | } 574 | } 575 | return $this->makeRequest($url, $params); 576 | } 577 | 578 | /** 579 | * Makes an HTTP request. This method can be overriden by subclasses if 580 | * developers want to do fancier things or use something other than curl to 581 | * make the request. 582 | * 583 | * @param String $url the URL to make the request to 584 | * @param Array $params the parameters to use for the POST body 585 | * @param CurlHandler $ch optional initialized curl handle 586 | * @return String the response text 587 | */ 588 | protected function makeRequest($url, $params, $ch=null) { 589 | if (!$ch) { 590 | $ch = curl_init(); 591 | } 592 | 593 | $opts = self::$CURL_OPTS; 594 | if ($this->useFileUploadSupport()) { 595 | $opts[CURLOPT_POSTFIELDS] = $params; 596 | } else { 597 | $opts[CURLOPT_POSTFIELDS] = http_build_query($params, null, '&'); 598 | } 599 | $opts[CURLOPT_URL] = $url; 600 | 601 | // disable the 'Expect: 100-continue' behaviour. This causes CURL to wait 602 | // for 2 seconds if the server does not support this header. 603 | if (isset($opts[CURLOPT_HTTPHEADER])) { 604 | $existing_headers = $opts[CURLOPT_HTTPHEADER]; 605 | $existing_headers[] = 'Expect:'; 606 | $opts[CURLOPT_HTTPHEADER] = $existing_headers; 607 | } else { 608 | $opts[CURLOPT_HTTPHEADER] = array('Expect:'); 609 | } 610 | 611 | curl_setopt_array($ch, $opts); 612 | $result = curl_exec($ch); 613 | 614 | if (curl_errno($ch) == 60) { // CURLE_SSL_CACERT 615 | self::errorLog('Invalid or no certificate authority found, using bundled information'); 616 | curl_setopt($ch, CURLOPT_CAINFO, 617 | dirname(__FILE__) . '/fb_ca_chain_bundle.crt'); 618 | $result = curl_exec($ch); 619 | } 620 | 621 | if ($result === false) { 622 | $e = new FacebookApiException(array( 623 | 'error_code' => curl_errno($ch), 624 | 'error' => array( 625 | 'message' => curl_error($ch), 626 | 'type' => 'CurlException', 627 | ), 628 | )); 629 | curl_close($ch); 630 | throw $e; 631 | } 632 | curl_close($ch); 633 | return $result; 634 | } 635 | 636 | /** 637 | * The name of the Cookie that contains the session. 638 | * 639 | * @return String the cookie name 640 | */ 641 | protected function getSessionCookieName() { 642 | return 'fbs_' . $this->getAppId(); 643 | } 644 | 645 | /** 646 | * Set a JS Cookie based on the _passed in_ session. It does not use the 647 | * currently stored session -- you need to explicitly pass it in. 648 | * 649 | * @param Array $session the session to use for setting the cookie 650 | */ 651 | protected function setCookieFromSession($session=null) { 652 | if (!$this->useCookieSupport()) { 653 | return; 654 | } 655 | 656 | $cookieName = $this->getSessionCookieName(); 657 | $value = 'deleted'; 658 | $expires = time() - 3600; 659 | $domain = $this->getBaseDomain(); 660 | if ($session) { 661 | $value = '"' . http_build_query($session, null, '&') . '"'; 662 | if (isset($session['base_domain'])) { 663 | $domain = $session['base_domain']; 664 | } 665 | $expires = $session['expires']; 666 | } 667 | 668 | // prepend dot if a domain is found 669 | if ($domain) { 670 | $domain = '.' . $domain; 671 | } 672 | 673 | // if an existing cookie is not set, we dont need to delete it 674 | if ($value == 'deleted' && empty($_COOKIE[$cookieName])) { 675 | return; 676 | } 677 | 678 | if (headers_sent()) { 679 | self::errorLog('Could not set cookie. Headers already sent.'); 680 | 681 | // ignore for code coverage as we will never be able to setcookie in a CLI 682 | // environment 683 | // @codeCoverageIgnoreStart 684 | } else { 685 | setcookie($cookieName, $value, $expires, '/', $domain); 686 | } 687 | // @codeCoverageIgnoreEnd 688 | } 689 | 690 | /** 691 | * Validates a session_version=3 style session object. 692 | * 693 | * @param Array $session the session object 694 | * @return Array the session object if it validates, null otherwise 695 | */ 696 | protected function validateSessionObject($session) { 697 | // make sure some essential fields exist 698 | if (is_array($session) && 699 | isset($session['uid']) && 700 | isset($session['access_token']) && 701 | isset($session['sig'])) { 702 | // validate the signature 703 | $session_without_sig = $session; 704 | unset($session_without_sig['sig']); 705 | $expected_sig = self::generateSignature( 706 | $session_without_sig, 707 | $this->getApiSecret() 708 | ); 709 | if ($session['sig'] != $expected_sig) { 710 | self::errorLog('Got invalid session signature in cookie.'); 711 | $session = null; 712 | } 713 | // check expiry time 714 | } else { 715 | $session = null; 716 | } 717 | return $session; 718 | } 719 | 720 | /** 721 | * Returns something that looks like our JS session object from the 722 | * signed token's data 723 | * 724 | * TODO: Nuke this once the login flow uses OAuth2 725 | * 726 | * @param Array the output of getSignedRequest 727 | * @return Array Something that will work as a session 728 | */ 729 | protected function createSessionFromSignedRequest($data) { 730 | if (!isset($data['oauth_token'])) { 731 | return null; 732 | } 733 | 734 | $session = array( 735 | 'uid' => $data['user_id'], 736 | 'access_token' => $data['oauth_token'], 737 | 'expires' => $data['expires'], 738 | ); 739 | 740 | // put a real sig, so that validateSignature works 741 | $session['sig'] = self::generateSignature( 742 | $session, 743 | $this->getApiSecret() 744 | ); 745 | 746 | return $session; 747 | } 748 | 749 | /** 750 | * Parses a signed_request and validates the signature. 751 | * Then saves it in $this->signed_data 752 | * 753 | * @param String A signed token 754 | * @param Boolean Should we remove the parts of the payload that 755 | * are used by the algorithm? 756 | * @return Array the payload inside it or null if the sig is wrong 757 | */ 758 | protected function parseSignedRequest($signed_request) { 759 | list($encoded_sig, $payload) = explode('.', $signed_request, 2); 760 | 761 | // decode the data 762 | $sig = self::base64UrlDecode($encoded_sig); 763 | $data = json_decode(self::base64UrlDecode($payload), true); 764 | 765 | if (strtoupper($data['algorithm']) !== 'HMAC-SHA256') { 766 | self::errorLog('Unknown algorithm. Expected HMAC-SHA256'); 767 | return null; 768 | } 769 | 770 | // check sig 771 | $expected_sig = hash_hmac('sha256', $payload, 772 | $this->getApiSecret(), $raw = true); 773 | if ($sig !== $expected_sig) { 774 | self::errorLog('Bad Signed JSON signature!'); 775 | return null; 776 | } 777 | 778 | return $data; 779 | } 780 | 781 | /** 782 | * Build the URL for api given parameters. 783 | * 784 | * @param $method String the method name. 785 | * @return String the URL for the given parameters 786 | */ 787 | protected function getApiUrl($method) { 788 | static $READ_ONLY_CALLS = 789 | array('admin.getallocation' => 1, 790 | 'admin.getappproperties' => 1, 791 | 'admin.getbannedusers' => 1, 792 | 'admin.getlivestreamvialink' => 1, 793 | 'admin.getmetrics' => 1, 794 | 'admin.getrestrictioninfo' => 1, 795 | 'application.getpublicinfo' => 1, 796 | 'auth.getapppublickey' => 1, 797 | 'auth.getsession' => 1, 798 | 'auth.getsignedpublicsessiondata' => 1, 799 | 'comments.get' => 1, 800 | 'connect.getunconnectedfriendscount' => 1, 801 | 'dashboard.getactivity' => 1, 802 | 'dashboard.getcount' => 1, 803 | 'dashboard.getglobalnews' => 1, 804 | 'dashboard.getnews' => 1, 805 | 'dashboard.multigetcount' => 1, 806 | 'dashboard.multigetnews' => 1, 807 | 'data.getcookies' => 1, 808 | 'events.get' => 1, 809 | 'events.getmembers' => 1, 810 | 'fbml.getcustomtags' => 1, 811 | 'feed.getappfriendstories' => 1, 812 | 'feed.getregisteredtemplatebundlebyid' => 1, 813 | 'feed.getregisteredtemplatebundles' => 1, 814 | 'fql.multiquery' => 1, 815 | 'fql.query' => 1, 816 | 'friends.arefriends' => 1, 817 | 'friends.get' => 1, 818 | 'friends.getappusers' => 1, 819 | 'friends.getlists' => 1, 820 | 'friends.getmutualfriends' => 1, 821 | 'gifts.get' => 1, 822 | 'groups.get' => 1, 823 | 'groups.getmembers' => 1, 824 | 'intl.gettranslations' => 1, 825 | 'links.get' => 1, 826 | 'notes.get' => 1, 827 | 'notifications.get' => 1, 828 | 'pages.getinfo' => 1, 829 | 'pages.isadmin' => 1, 830 | 'pages.isappadded' => 1, 831 | 'pages.isfan' => 1, 832 | 'permissions.checkavailableapiaccess' => 1, 833 | 'permissions.checkgrantedapiaccess' => 1, 834 | 'photos.get' => 1, 835 | 'photos.getalbums' => 1, 836 | 'photos.gettags' => 1, 837 | 'profile.getinfo' => 1, 838 | 'profile.getinfooptions' => 1, 839 | 'stream.get' => 1, 840 | 'stream.getcomments' => 1, 841 | 'stream.getfilters' => 1, 842 | 'users.getinfo' => 1, 843 | 'users.getloggedinuser' => 1, 844 | 'users.getstandardinfo' => 1, 845 | 'users.hasapppermission' => 1, 846 | 'users.isappuser' => 1, 847 | 'users.isverified' => 1, 848 | 'video.getuploadlimits' => 1); 849 | $name = 'api'; 850 | if (isset($READ_ONLY_CALLS[strtolower($method)])) { 851 | $name = 'api_read'; 852 | } 853 | return self::getUrl($name, 'restserver.php'); 854 | } 855 | 856 | /** 857 | * Build the URL for given domain alias, path and parameters. 858 | * 859 | * @param $name String the name of the domain 860 | * @param $path String optional path (without a leading slash) 861 | * @param $params Array optional query parameters 862 | * @return String the URL for the given parameters 863 | */ 864 | protected function getUrl($name, $path='', $params=array()) { 865 | $url = self::$DOMAIN_MAP[$name]; 866 | if ($path) { 867 | if ($path[0] === '/') { 868 | $path = substr($path, 1); 869 | } 870 | $url .= $path; 871 | } 872 | if ($params) { 873 | $url .= '?' . http_build_query($params, null, '&'); 874 | } 875 | return $url; 876 | } 877 | 878 | /** 879 | * Returns the Current URL, stripping it of known FB parameters that should 880 | * not persist. 881 | * 882 | * @return String the current URL 883 | */ 884 | protected function getCurrentUrl() { 885 | $protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on' 886 | ? 'https://' 887 | : 'http://'; 888 | $currentUrl = $protocol . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; 889 | $parts = parse_url($currentUrl); 890 | 891 | // drop known fb params 892 | $query = ''; 893 | if (!empty($parts['query'])) { 894 | $params = array(); 895 | parse_str($parts['query'], $params); 896 | foreach(self::$DROP_QUERY_PARAMS as $key) { 897 | unset($params[$key]); 898 | } 899 | if (!empty($params)) { 900 | $query = '?' . http_build_query($params, null, '&'); 901 | } 902 | } 903 | 904 | // use port if non default 905 | $port = 906 | isset($parts['port']) && 907 | (($protocol === 'http://' && $parts['port'] !== 80) || 908 | ($protocol === 'https://' && $parts['port'] !== 443)) 909 | ? ':' . $parts['port'] : ''; 910 | 911 | // rebuild 912 | return $protocol . $parts['host'] . $port . $parts['path'] . $query; 913 | } 914 | 915 | /** 916 | * Generate a signature for the given params and secret. 917 | * 918 | * @param Array $params the parameters to sign 919 | * @param String $secret the secret to sign with 920 | * @return String the generated signature 921 | */ 922 | protected static function generateSignature($params, $secret) { 923 | // work with sorted data 924 | ksort($params); 925 | 926 | // generate the base string 927 | $base_string = ''; 928 | foreach($params as $key => $value) { 929 | $base_string .= $key . '=' . $value; 930 | } 931 | $base_string .= $secret; 932 | 933 | return md5($base_string); 934 | } 935 | 936 | /** 937 | * Prints to the error log if you aren't in command line mode. 938 | * 939 | * @param String log message 940 | */ 941 | protected static function errorLog($msg) { 942 | // disable error log if we are running in a CLI environment 943 | // @codeCoverageIgnoreStart 944 | if (php_sapi_name() != 'cli') { 945 | error_log($msg); 946 | } 947 | // uncomment this if you want to see the errors on the page 948 | // print 'error_log: '.$msg."\n"; 949 | // @codeCoverageIgnoreEnd 950 | } 951 | 952 | /** 953 | * Base64 encoding that doesn't need to be urlencode()ed. 954 | * Exactly the same as base64_encode except it uses 955 | * - instead of + 956 | * _ instead of / 957 | * 958 | * @param String base64UrlEncodeded string 959 | */ 960 | protected static function base64UrlDecode($input) { 961 | return base64_decode(strtr($input, '-_', '+/')); 962 | } 963 | } 964 | -------------------------------------------------------------------------------- /library/fb_ca_chain_bundle.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFgjCCBGqgAwIBAgIQDKKbZcnESGaLDuEaVk6fQjANBgkqhkiG9w0BAQUFADBm 3 | MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 4 | d3cuZGlnaWNlcnQuY29tMSUwIwYDVQQDExxEaWdpQ2VydCBIaWdoIEFzc3VyYW5j 5 | ZSBDQS0zMB4XDTEwMDExMzAwMDAwMFoXDTEzMDQxMTIzNTk1OVowaDELMAkGA1UE 6 | BhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVBhbG8gQWx0bzEX 7 | MBUGA1UEChMORmFjZWJvb2ssIEluYy4xFzAVBgNVBAMUDiouZmFjZWJvb2suY29t 8 | MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC9rzj7QIuLM3sdHu1HcI1VcR3g 9 | b5FExKNV646agxSle1aQ/sJev1mh/u91ynwqd2BQmM0brZ1Hc3QrfYyAaiGGgEkp 10 | xbhezyfeYhAyO0TKAYxPnm2cTjB5HICzk6xEIwFbA7SBJ2fSyW1CFhYZyo3tIBjj 11 | 19VjKyBfpRaPkzLmRwIDAQABo4ICrDCCAqgwHwYDVR0jBBgwFoAUUOpzidsp+xCP 12 | nuUBINTeeZlIg/cwHQYDVR0OBBYEFPp+tsFBozkjrHlEnZ9J4cFj2eM0MA4GA1Ud 13 | DwEB/wQEAwIFoDAMBgNVHRMBAf8EAjAAMF8GA1UdHwRYMFYwKaAnoCWGI2h0dHA6 14 | Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9jYTMtZmIuY3JsMCmgJ6AlhiNodHRwOi8vY3Js 15 | NC5kaWdpY2VydC5jb20vY2EzLWZiLmNybDCCAcYGA1UdIASCAb0wggG5MIIBtQYL 16 | YIZIAYb9bAEDAAEwggGkMDoGCCsGAQUFBwIBFi5odHRwOi8vd3d3LmRpZ2ljZXJ0 17 | LmNvbS9zc2wtY3BzLXJlcG9zaXRvcnkuaHRtMIIBZAYIKwYBBQUHAgIwggFWHoIB 18 | UgBBAG4AeQAgAHUAcwBlACAAbwBmACAAdABoAGkAcwAgAEMAZQByAHQAaQBmAGkA 19 | YwBhAHQAZQAgAGMAbwBuAHMAdABpAHQAdQB0AGUAcwAgAGEAYwBjAGUAcAB0AGEA 20 | bgBjAGUAIABvAGYAIAB0AGgAZQAgAEQAaQBnAGkAQwBlAHIAdAAgAEMAUAAvAEMA 21 | UABTACAAYQBuAGQAIAB0AGgAZQAgAFIAZQBsAHkAaQBuAGcAIABQAGEAcgB0AHkA 22 | IABBAGcAcgBlAGUAbQBlAG4AdAAgAHcAaABpAGMAaAAgAGwAaQBtAGkAdAAgAGwA 23 | aQBhAGIAaQBsAGkAdAB5ACAAYQBuAGQAIABhAHIAZQAgAGkAbgBjAG8AcgBwAG8A 24 | cgBhAHQAZQBkACAAaABlAHIAZQBpAG4AIABiAHkAIAByAGUAZgBlAHIAZQBuAGMA 25 | ZQAuMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQUF 26 | AAOCAQEACOkTIdxMy11+CKrbGNLBSg5xHaTvu/v1wbyn3dO/mf68pPfJnX6ShPYy 27 | 4XM4Vk0x4uaFaU4wAGke+nCKGi5dyg0Esg7nemLNKEJaFAJZ9enxZm334lSCeARy 28 | wlDtxULGOFRyGIZZPmbV2eNq5xdU/g3IuBEhL722mTpAye9FU/J8Wsnw54/gANyO 29 | Gzkewigua8ip8Lbs9Cht399yAfbfhUP1DrAm/xEcnHrzPr3cdCtOyJaM6SRPpRqH 30 | ITK5Nc06tat9lXVosSinT3KqydzxBYua9gCFFiR3x3DgZfvXkC6KDdUlDrNcJUub 31 | a1BHnLLP4mxTHL6faAXYd05IxNn/IA== 32 | -----END CERTIFICATE----- 33 | -----BEGIN CERTIFICATE----- 34 | MIIGVTCCBT2gAwIBAgIQCFH5WYFBRcq94CTiEsnCDjANBgkqhkiG9w0BAQUFADBs 35 | MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 36 | d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j 37 | ZSBFViBSb290IENBMB4XDTA3MDQwMzAwMDAwMFoXDTIyMDQwMzAwMDAwMFowZjEL 38 | MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 39 | LmRpZ2ljZXJ0LmNvbTElMCMGA1UEAxMcRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug 40 | Q0EtMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9hCikQH17+NDdR 41 | CPge+yLtYb4LDXBMUGMmdRW5QYiXtvCgFbsIYOBC6AUpEIc2iihlqO8xB3RtNpcv 42 | KEZmBMcqeSZ6mdWOw21PoF6tvD2Rwll7XjZswFPPAAgyPhBkWBATaccM7pxCUQD5 43 | BUTuJM56H+2MEb0SqPMV9Bx6MWkBG6fmXcCabH4JnudSREoQOiPkm7YDr6ictFuf 44 | 1EutkozOtREqqjcYjbTCuNhcBoz4/yO9NV7UfD5+gw6RlgWYw7If48hl66l7XaAs 45 | zPw82W3tzPpLQ4zJ1LilYRyyQLYoEt+5+F/+07LJ7z20Hkt8HEyZNp496+ynaF4d 46 | 32duXvsCAwEAAaOCAvcwggLzMA4GA1UdDwEB/wQEAwIBhjCCAcYGA1UdIASCAb0w 47 | ggG5MIIBtQYLYIZIAYb9bAEDAAIwggGkMDoGCCsGAQUFBwIBFi5odHRwOi8vd3d3 48 | LmRpZ2ljZXJ0LmNvbS9zc2wtY3BzLXJlcG9zaXRvcnkuaHRtMIIBZAYIKwYBBQUH 49 | AgIwggFWHoIBUgBBAG4AeQAgAHUAcwBlACAAbwBmACAAdABoAGkAcwAgAEMAZQBy 50 | AHQAaQBmAGkAYwBhAHQAZQAgAGMAbwBuAHMAdABpAHQAdQB0AGUAcwAgAGEAYwBj 51 | AGUAcAB0AGEAbgBjAGUAIABvAGYAIAB0AGgAZQAgAEQAaQBnAGkAQwBlAHIAdAAg 52 | AEMAUAAvAEMAUABTACAAYQBuAGQAIAB0AGgAZQAgAFIAZQBsAHkAaQBuAGcAIABQ 53 | AGEAcgB0AHkAIABBAGcAcgBlAGUAbQBlAG4AdAAgAHcAaABpAGMAaAAgAGwAaQBt 54 | AGkAdAAgAGwAaQBhAGIAaQBsAGkAdAB5ACAAYQBuAGQAIABhAHIAZQAgAGkAbgBj 55 | AG8AcgBwAG8AcgBhAHQAZQBkACAAaABlAHIAZQBpAG4AIABiAHkAIAByAGUAZgBl 56 | AHIAZQBuAGMAZQAuMA8GA1UdEwEB/wQFMAMBAf8wNAYIKwYBBQUHAQEEKDAmMCQG 57 | CCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wgY8GA1UdHwSBhzCB 58 | hDBAoD6gPIY6aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0SGlnaEFz 59 | c3VyYW5jZUVWUm9vdENBLmNybDBAoD6gPIY6aHR0cDovL2NybDQuZGlnaWNlcnQu 60 | Y29tL0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNybDAfBgNVHSMEGDAW 61 | gBSxPsNpA/i/RwHUmCYaCALvY2QrwzAdBgNVHQ4EFgQUUOpzidsp+xCPnuUBINTe 62 | eZlIg/cwDQYJKoZIhvcNAQEFBQADggEBAF1PhPGoiNOjsrycbeUpSXfh59bcqdg1 63 | rslx3OXb3J0kIZCmz7cBHJvUV5eR13UWpRLXuT0uiT05aYrWNTf58SHEW0CtWakv 64 | XzoAKUMncQPkvTAyVab+hA4LmzgZLEN8rEO/dTHlIxxFVbdpCJG1z9fVsV7un5Tk 65 | 1nq5GMO41lJjHBC6iy9tXcwFOPRWBW3vnuzoYTYMFEuFFFoMg08iXFnLjIpx2vrF 66 | EIRYzwfu45DC9fkpx1ojcflZtGQriLCnNseaIGHr+k61rmsb5OPs4tk8QUmoIKRU 67 | 9ZKNu8BVIASm2LAXFszj0Mi0PeXZhMbT9m5teMl5Q+h6N/9cNUm/ocU= 68 | -----END CERTIFICATE----- 69 | -----BEGIN CERTIFICATE----- 70 | MIIEQjCCA6ugAwIBAgIEQoclDjANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMC 71 | VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5u 72 | ZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc 73 | KGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5u 74 | ZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEy 75 | MjIxNTI3MjdaFw0xNDA3MjIxNTU3MjdaMGwxCzAJBgNVBAYTAlVTMRUwEwYDVQQK 76 | EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xKzApBgNV 77 | BAMTIkRpZ2lDZXJ0IEhpZ2ggQXNzdXJhbmNlIEVWIFJvb3QgQ0EwggEiMA0GCSqG 78 | SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGzOVz5vvUu+UtLTKm3+WBP8nNJUm2cSrD 79 | 1ZQ0Z6IKHLBfaaZAscS3so/QmKSpQVk609yU1jzbdDikSsxNJYL3SqVTEjju80lt 80 | cZF+Y7arpl/DpIT4T2JRvvjF7Ns4kuMG5QiRDMQoQVX7y1qJFX5x6DW/TXIJPb46 81 | OFBbdzEbjbPHJEWap6xtABRaBLe6E+tRCphBQSJOZWGHgUFQpnlcid4ZSlfVLuZd 82 | HFMsfpjNGgYWpGhz0DQEE1yhcdNafFXbXmThN4cwVgTlEbQpgBLxeTmIogIRfCdm 83 | t4i3ePLKCqg4qwpkwr9mXZWEwaElHoddGlALIBLMQbtuC1E4uEvLAgMBAAGjggET 84 | MIIBDzASBgNVHRMBAf8ECDAGAQH/AgEBMCcGA1UdJQQgMB4GCCsGAQUFBwMBBggr 85 | BgEFBQcDAgYIKwYBBQUHAwQwMwYIKwYBBQUHAQEEJzAlMCMGCCsGAQUFBzABhhdo 86 | dHRwOi8vb2NzcC5lbnRydXN0Lm5ldDAzBgNVHR8ELDAqMCigJqAkhiJodHRwOi8v 87 | Y3JsLmVudHJ1c3QubmV0L3NlcnZlcjEuY3JsMB0GA1UdDgQWBBSxPsNpA/i/RwHU 88 | mCYaCALvY2QrwzALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8BdiE1U9s/8KAGv7 89 | UISX8+1i0BowGQYJKoZIhvZ9B0EABAwwChsEVjcuMQMCAIEwDQYJKoZIhvcNAQEF 90 | BQADgYEAUuVY7HCc/9EvhaYzC1rAIo348LtGIiMduEl5Xa24G8tmJnDioD2GU06r 91 | 1kjLX/ktCdpdBgXadbjtdrZXTP59uN0AXlsdaTiFufsqVLPvkp5yMnqnuI3E2o6p 92 | NpAkoQSbB6kUCNnXcW26valgOjDLZFOnr241QiwdBAJAAE/rRa8= 93 | -----END CERTIFICATE----- 94 | -----BEGIN CERTIFICATE----- 95 | MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMC 96 | VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5u 97 | ZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc 98 | KGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5u 99 | ZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05OTA1 100 | MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIGA1UE 101 | ChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5j 102 | b3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF 103 | bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUg 104 | U2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUA 105 | A4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQaO2f55M28Qpku0f1BBc/ 106 | I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5gXpa0zf3 107 | wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OC 108 | AdcwggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHb 109 | oIHYpIHVMIHSMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5 110 | BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1p 111 | dHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVk 112 | MTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp 113 | b24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu 114 | dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0 115 | MFqBDzIwMTkwNTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8Bdi 116 | E1U9s/8KAGv7UISX8+1i0BowHQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAa 117 | MAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI 118 | hvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyNEwr75Ji174z4xRAN 119 | 95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9n9cd 120 | 2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI= 121 | -----END CERTIFICATE----- 122 | -------------------------------------------------------------------------------- /photos.php: -------------------------------------------------------------------------------- 1 | api('/me/albums'); 6 | 7 | foreach($albums['data'] as $album) 8 | { 9 | // get all photos for album 10 | $photos = $facebook->api("/{$album['id']}/photos"); 11 | 12 | foreach($photos['data'] as $photo) 13 | { 14 | echo "", "
"; 15 | } 16 | } -------------------------------------------------------------------------------- /photos_add.php: -------------------------------------------------------------------------------- 1 | setFileUploadSupport("http://" . $_SERVER['SERVER_NAME']); 8 | 9 | // add a status message 10 | $photo = $facebook->api('/me/photos', 'POST', 11 | array( 12 | 'source' => '@' . $img, 13 | 'message' => 'This photo came from my app.' 14 | ) 15 | ); 16 | 17 | var_dump($photo); -------------------------------------------------------------------------------- /rest_user_isappuser.php: -------------------------------------------------------------------------------- 1 | api(array('method' => 'users.isappuser')); 5 | echo (string)$return; -------------------------------------------------------------------------------- /status.php: -------------------------------------------------------------------------------- 1 | api('/me/statuses'); 6 | foreach($statuses['data'] as $status) 7 | { 8 | echo $status["message"], "
"; 9 | } -------------------------------------------------------------------------------- /status_add.php: -------------------------------------------------------------------------------- 1 | api('/me/feed', 'POST', array('message' => 'This post came from my app.')); 6 | 7 | var_dump($status); -------------------------------------------------------------------------------- /user.php: -------------------------------------------------------------------------------- 1 | api('/me'); 5 | var_dump($me); --------------------------------------------------------------------------------