Changeset 1408
- Timestamp:
- 04/22/11 17:55:25 (2 years ago)
- Location:
- facebook/files/lib
- Files:
-
- 1 added
- 2 modified
-
data/facebook/Facebook.class.php (modified) (26 diffs)
-
data/facebook/fb_ca_chain_bundle.crt (added)
-
util/FacebookUtil.class.php (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
facebook/files/lib/data/facebook/Facebook.class.php
r1208 r1408 1 1 <?php 2 /** 3 * 4 * Copyright 2011 Facebook, Inc. 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); you may 7 * not use this file except in compliance with the License. You may obtain 8 * a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 14 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 15 * License for the specific language governing permissions and limitations 16 * under the License. 17 */ 2 18 3 19 if (!function_exists('curl_init')) { … … 29 45 30 46 $code = isset($result['error_code']) ? $result['error_code'] : 0; 31 $msg = isset($result['error']) 32 ? $result['error']['message'] : $result['error_msg']; 47 48 if (isset($result['error_description'])) { 49 // OAuth 2.0 Draft 10 style 50 $msg = $result['error_description']; 51 } else if (isset($result['error']) && is_array($result['error'])) { 52 // OAuth 2.0 Draft 00 style 53 $msg = $result['error']['message']; 54 } else if (isset($result['error_msg'])) { 55 // Rest server style 56 $msg = $result['error_msg']; 57 } else { 58 $msg = 'Unknown Error. Check getResult()'; 59 } 60 33 61 parent::__construct($msg, $code); 34 62 } … … 50 78 */ 51 79 public function getType() { 52 return 53 isset($this->result['error']) && isset($this->result['error']['type']) 54 ? $this->result['error']['type'] 55 : 'Exception'; 80 if (isset($this->result['error'])) { 81 $error = $this->result['error']; 82 if (is_string($error)) { 83 // OAuth 2.0 Draft 10 style 84 return $error; 85 } else if (is_array($error)) { 86 // OAuth 2.0 Draft 00 style 87 if (isset($error['type'])) { 88 return $error['type']; 89 } 90 } 91 } 92 return 'Exception'; 56 93 } 57 94 … … 80 117 * Version. 81 118 */ 82 const VERSION = '2. 0.6';119 const VERSION = '2.1.2'; 83 120 84 121 /** … … 98 135 protected static $DROP_QUERY_PARAMS = array( 99 136 'session', 137 'signed_request', 100 138 ); 101 139 … … 104 142 */ 105 143 public static $DOMAIN_MAP = array( 106 'api' => 'https://api.facebook.com/', 107 'api_read' => 'https://api-read.facebook.com/', 108 'graph' => 'https://graph.facebook.com/', 109 'www' => 'https://www.facebook.com/', 144 'api' => 'https://api.facebook.com/', 145 'api_video' => 'https://api-video.facebook.com/', 146 'api_read' => 'https://api-read.facebook.com/', 147 'graph' => 'https://graph.facebook.com/', 148 'www' => 'https://www.facebook.com/', 110 149 ); 111 150 … … 126 165 127 166 /** 167 * The data from the signed_request token. 168 */ 169 protected $signedRequest; 170 171 /** 128 172 * Indicates that we already loaded the session as best as we could. 129 173 */ … … 139 183 */ 140 184 protected $baseDomain = ''; 185 186 /** 187 * Indicates if the CURL based @ syntax for file uploads is enabled. 188 */ 189 protected $fileUploadSupport = false; 141 190 142 191 /** … … 148 197 * - cookie: (optional) boolean true to enable cookie support 149 198 * - domain: (optional) domain for the cookie 199 * - fileUpload: (optional) boolean indicating if file uploads are enabled 150 200 * 151 201 * @param Array $config the application configuration … … 160 210 $this->setBaseDomain($config['domain']); 161 211 } 212 if (isset($config['fileUpload'])) { 213 $this->setFileUploadSupport($config['fileUpload']); 214 } 162 215 } 163 216 … … 236 289 public function getBaseDomain() { 237 290 return $this->baseDomain; 291 } 292 293 /** 294 * Set the file upload support status. 295 * 296 * @param String $domain the base domain 297 */ 298 public function setFileUploadSupport($fileUploadSupport) { 299 $this->fileUploadSupport = $fileUploadSupport; 300 return $this; 301 } 302 303 /** 304 * Get the file upload support status. 305 * 306 * @return String the base domain 307 */ 308 public function useFileUploadSupport() { 309 return $this->fileUploadSupport; 310 } 311 312 /** 313 * Get the data from a signed_request token 314 * 315 * @return String the base domain 316 */ 317 public function getSignedRequest() { 318 if (!$this->signedRequest) { 319 if (isset($_REQUEST['signed_request'])) { 320 $this->signedRequest = $this->parseSignedRequest( 321 $_REQUEST['signed_request']); 322 } 323 } 324 return $this->signedRequest; 238 325 } 239 326 … … 257 344 /** 258 345 * Get the session object. This will automatically look for a signed session 259 * sent via the Cookie or Query Parameters if needed.346 * sent via the signed_request, Cookie or Query Parameters if needed. 260 347 * 261 348 * @return Array the session … … 266 353 $write_cookie = true; 267 354 355 // try loading session from signed_request in $_REQUEST 356 $signedRequest = $this->getSignedRequest(); 357 if ($signedRequest) { 358 // sig is good, use the signedRequest 359 $session = $this->createSessionFromSignedRequest($signedRequest); 360 } 361 268 362 // try loading session from $_REQUEST 269 if ( isset($_REQUEST['session'])) {363 if (!$session && isset($_REQUEST['session'])) { 270 364 $session = json_decode( 271 365 get_magic_quotes_gpc() … … 308 402 $session = $this->getSession(); 309 403 return $session ? $session['uid'] : null; 404 } 405 406 /** 407 * Gets a OAuth access token. 408 * 409 * @return String the access token 410 */ 411 public function getAccessToken() { 412 $session = $this->getSession(); 413 // either user session signed, or app signed 414 if ($session) { 415 return $session['access_token']; 416 } else { 417 return $this->getAppId() .'|'. $this->getApiSecret(); 418 } 310 419 } 311 420 … … 352 461 */ 353 462 public function getLogoutUrl($params=array()) { 354 $session = $this->getSession();355 463 return $this->getUrl( 356 464 'www', 357 465 'logout.php', 358 466 array_merge(array( 359 'api_key' => $this->getAppId(), 360 'next' => $this->getCurrentUrl(), 361 'session_key' => $session['session_key'], 467 'next' => $this->getCurrentUrl(), 468 'access_token' => $this->getAccessToken(), 362 469 ), $params) 363 470 ); … … 452 559 if (is_array($result) && isset($result['error'])) { 453 560 $e = new FacebookApiException($result); 454 if ($e->getType() === 'OAuthException') { 455 $this->setSession(null); 561 switch ($e->getType()) { 562 // OAuth 2.0 Draft 00 style 563 case 'OAuthException': 564 // OAuth 2.0 Draft 10 style 565 case 'invalid_token': 566 $this->setSession(null); 456 567 } 457 568 throw $e; … … 470 581 protected function _oauthRequest($url, $params) { 471 582 if (!isset($params['access_token'])) { 472 $session = $this->getSession(); 473 // either user session signed, or app signed 474 if ($session) { 475 $params['access_token'] = $session['access_token']; 476 } else { 477 $params['access_token'] = $this->getAppId() .'|'. $this->getApiSecret(); 478 } 583 $params['access_token'] = $this->getAccessToken(); 479 584 } 480 585 … … 504 609 505 610 $opts = self::$CURL_OPTS; 506 $opts[CURLOPT_POSTFIELDS] = http_build_query($params, null, '&'); 611 if ($this->useFileUploadSupport()) { 612 $opts[CURLOPT_POSTFIELDS] = $params; 613 } else { 614 $opts[CURLOPT_POSTFIELDS] = http_build_query($params, null, '&'); 615 } 507 616 $opts[CURLOPT_URL] = $url; 508 617 … … 519 628 curl_setopt_array($ch, $opts); 520 629 $result = curl_exec($ch); 630 631 if (curl_errno($ch) == 60) { // CURLE_SSL_CACERT 632 self::errorLog('Invalid or no certificate authority found, using bundled information'); 633 curl_setopt($ch, CURLOPT_CAINFO, 634 dirname(__FILE__) . '/fb_ca_chain_bundle.crt'); 635 $result = curl_exec($ch); 636 } 637 521 638 if ($result === false) { 522 639 $e = new FacebookApiException(array( … … 577 694 578 695 if (headers_sent()) { 579 self::error _log('Could not set cookie. Headers already sent.');696 self::errorLog('Could not set cookie. Headers already sent.'); 580 697 581 698 // ignore for code coverage as we will never be able to setcookie in a CLI … … 598 715 if (is_array($session) && 599 716 isset($session['uid']) && 600 isset($session['session_key']) &&601 isset($session['secret']) &&602 717 isset($session['access_token']) && 603 718 isset($session['sig'])) { … … 610 725 ); 611 726 if ($session['sig'] != $expected_sig) { 612 self::error _log('Got invalid session signature in cookie.');727 self::errorLog('Got invalid session signature in cookie.'); 613 728 $session = null; 614 729 } … … 618 733 } 619 734 return $session; 735 } 736 737 /** 738 * Returns something that looks like our JS session object from the 739 * signed token's data 740 * 741 * TODO: Nuke this once the login flow uses OAuth2 742 * 743 * @param Array the output of getSignedRequest 744 * @return Array Something that will work as a session 745 */ 746 protected function createSessionFromSignedRequest($data) { 747 if (!isset($data['oauth_token'])) { 748 return null; 749 } 750 751 $session = array( 752 'uid' => $data['user_id'], 753 'access_token' => $data['oauth_token'], 754 'expires' => $data['expires'], 755 ); 756 757 // put a real sig, so that validateSignature works 758 $session['sig'] = self::generateSignature( 759 $session, 760 $this->getApiSecret() 761 ); 762 763 return $session; 764 } 765 766 /** 767 * Parses a signed_request and validates the signature. 768 * Then saves it in $this->signed_data 769 * 770 * @param String A signed token 771 * @param Boolean Should we remove the parts of the payload that 772 * are used by the algorithm? 773 * @return Array the payload inside it or null if the sig is wrong 774 */ 775 protected function parseSignedRequest($signed_request) { 776 list($encoded_sig, $payload) = explode('.', $signed_request, 2); 777 778 // decode the data 779 $sig = self::base64UrlDecode($encoded_sig); 780 $data = json_decode(self::base64UrlDecode($payload), true); 781 782 if (strtoupper($data['algorithm']) !== 'HMAC-SHA256') { 783 self::errorLog('Unknown algorithm. Expected HMAC-SHA256'); 784 return null; 785 } 786 787 // check sig 788 $expected_sig = hash_hmac('sha256', $payload, 789 $this->getApiSecret(), $raw = true); 790 if ($sig !== $expected_sig) { 791 self::errorLog('Bad Signed JSON signature!'); 792 return null; 793 } 794 795 return $data; 620 796 } 621 797 … … 691 867 if (isset($READ_ONLY_CALLS[strtolower($method)])) { 692 868 $name = 'api_read'; 869 } else if (strtolower($method) == 'video.upload') { 870 $name = 'api_video'; 693 871 } 694 872 return self::getUrl($name, 'restserver.php'); … … 776 954 777 955 /** 778 * Prints to the error log if you aren't in command line mode. 956 * Prints to the error log if you aren't in command line mode. 779 957 * 780 958 * @param String log message 781 959 */ 782 protected static function error _log($msg) {960 protected static function errorLog($msg) { 783 961 // disable error log if we are running in a CLI environment 784 962 // @codeCoverageIgnoreStart … … 790 968 // @codeCoverageIgnoreEnd 791 969 } 970 971 /** 972 * Base64 encoding that doesn't need to be urlencode()ed. 973 * Exactly the same as base64_encode except it uses 974 * - instead of + 975 * _ instead of / 976 * 977 * @param String base64UrlEncodeded string 978 */ 979 protected static function base64UrlDecode($input) { 980 return base64_decode(strtr($input, '-_', '+/')); 981 } 792 982 } -
facebook/files/lib/util/FacebookUtil.class.php
r1380 r1408 172 172 173 173 // update avatar (only if avatar is not given) 174 self::updateAvatar('https://graph.facebook.com/'.$me['id'].'/picture ', $user);174 self::updateAvatar('https://graph.facebook.com/'.$me['id'].'/picture?type=large', $user); 175 175 176 176 // either user is new, oder just got a link, but add a facebook link … … 273 273 274 274 // update avatar 275 self::updateAvatar('https://graph.facebook.com/'.$me['id'].'/picture ', $user);275 self::updateAvatar('https://graph.facebook.com/'.$me['id'].'/picture?type=large', $user); 276 276 277 277 // either user is new, oder just got a link, but add a facebook link
