root/facebook/files/lib/data/facebook/Facebook.class.php @ 1408

Revision 1408, 26.7 kB (checked in by Torben Brodt, 2 years ago)

update facebook php api from 2.0.6 to 2.1.2

Line 
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 */
18
19if (!function_exists('curl_init')) {
20  throw new Exception('Facebook needs the CURL PHP extension.');
21}
22if (!function_exists('json_decode')) {
23  throw new Exception('Facebook needs the JSON PHP extension.');
24}
25
26/**
27 * Thrown when an API call returns an exception.
28 *
29 * @author Naitik Shah <naitik@facebook.com>
30 */
31class FacebookApiException extends Exception
32{
33  /**
34   * The result from the API server that represents the exception information.
35   */
36  protected $result;
37
38  /**
39   * Make a new API Exception with the given result.
40   *
41   * @param Array $result the result from the API server
42   */
43  public function __construct($result) {
44    $this->result = $result;
45
46    $code = isset($result['error_code']) ? $result['error_code'] : 0;
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
61    parent::__construct($msg, $code);
62  }
63
64  /**
65   * Return the associated result object returned by the API server.
66   *
67   * @returns Array the result from the API server
68   */
69  public function getResult() {
70    return $this->result;
71  }
72
73  /**
74   * Returns the associated type for the error. This will default to
75   * 'Exception' when a type is not available.
76   *
77   * @return String
78   */
79  public function getType() {
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';
93  }
94
95  /**
96   * To make debugging easier.
97   *
98   * @returns String the string representation of the error
99   */
100  public function __toString() {
101    $str = $this->getType() . ': ';
102    if ($this->code != 0) {
103      $str .= $this->code . ': ';
104    }
105    return $str . $this->message;
106  }
107}
108
109/**
110 * Provides access to the Facebook Platform.
111 *
112 * @author Naitik Shah <naitik@facebook.com>
113 */
114class Facebook
115{
116  /**
117   * Version.
118   */
119  const VERSION = '2.1.2';
120
121  /**
122   * Default options for curl.
123   */
124  public static $CURL_OPTS = array(
125    CURLOPT_CONNECTTIMEOUT => 10,
126    CURLOPT_RETURNTRANSFER => true,
127    CURLOPT_TIMEOUT        => 60,
128    CURLOPT_USERAGENT      => 'facebook-php-2.0',
129  );
130
131  /**
132   * List of query parameters that get automatically dropped when rebuilding
133   * the current URL.
134   */
135  protected static $DROP_QUERY_PARAMS = array(
136    'session',
137    'signed_request',
138  );
139
140  /**
141   * Maps aliases to Facebook domains.
142   */
143  public static $DOMAIN_MAP = array(
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/',
149  );
150
151  /**
152   * The Application ID.
153   */
154  protected $appId;
155
156  /**
157   * The Application API Secret.
158   */
159  protected $apiSecret;
160
161  /**
162   * The active user session, if one is available.
163   */
164  protected $session;
165
166  /**
167   * The data from the signed_request token.
168   */
169  protected $signedRequest;
170
171  /**
172   * Indicates that we already loaded the session as best as we could.
173   */
174  protected $sessionLoaded = false;
175
176  /**
177   * Indicates if Cookie support should be enabled.
178   */
179  protected $cookieSupport = false;
180
181  /**
182   * Base domain for the Cookie.
183   */
184  protected $baseDomain = '';
185
186  /**
187   * Indicates if the CURL based @ syntax for file uploads is enabled.
188   */
189  protected $fileUploadSupport = false;
190
191  /**
192   * Initialize a Facebook Application.
193   *
194   * The configuration:
195   * - appId: the application ID
196   * - secret: the application secret
197   * - cookie: (optional) boolean true to enable cookie support
198   * - domain: (optional) domain for the cookie
199   * - fileUpload: (optional) boolean indicating if file uploads are enabled
200   *
201   * @param Array $config the application configuration
202   */
203  public function __construct($config) {
204    $this->setAppId($config['appId']);
205    $this->setApiSecret($config['secret']);
206    if (isset($config['cookie'])) {
207      $this->setCookieSupport($config['cookie']);
208    }
209    if (isset($config['domain'])) {
210      $this->setBaseDomain($config['domain']);
211    }
212    if (isset($config['fileUpload'])) {
213      $this->setFileUploadSupport($config['fileUpload']);
214    }
215  }
216
217  /**
218   * Set the Application ID.
219   *
220   * @param String $appId the Application ID
221   */
222  public function setAppId($appId) {
223    $this->appId = $appId;
224    return $this;
225  }
226
227  /**
228   * Get the Application ID.
229   *
230   * @return String the Application ID
231   */
232  public function getAppId() {
233    return $this->appId;
234  }
235
236  /**
237   * Set the API Secret.
238   *
239   * @param String $appId the API Secret
240   */
241  public function setApiSecret($apiSecret) {
242    $this->apiSecret = $apiSecret;
243    return $this;
244  }
245
246  /**
247   * Get the API Secret.
248   *
249   * @return String the API Secret
250   */
251  public function getApiSecret() {
252    return $this->apiSecret;
253  }
254
255  /**
256   * Set the Cookie Support status.
257   *
258   * @param Boolean $cookieSupport the Cookie Support status
259   */
260  public function setCookieSupport($cookieSupport) {
261    $this->cookieSupport = $cookieSupport;
262    return $this;
263  }
264
265  /**
266   * Get the Cookie Support status.
267   *
268   * @return Boolean the Cookie Support status
269   */
270  public function useCookieSupport() {
271    return $this->cookieSupport;
272  }
273
274  /**
275   * Set the base domain for the Cookie.
276   *
277   * @param String $domain the base domain
278   */
279  public function setBaseDomain($domain) {
280    $this->baseDomain = $domain;
281    return $this;
282  }
283
284  /**
285   * Get the base domain for the Cookie.
286   *
287   * @return String the base domain
288   */
289  public function getBaseDomain() {
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;
325  }
326
327  /**
328   * Set the Session.
329   *
330   * @param Array $session the session
331   * @param Boolean $write_cookie indicate if a cookie should be written. this
332   * value is ignored if cookie support has been disabled.
333   */
334  public function setSession($session=null, $write_cookie=true) {
335    $session = $this->validateSessionObject($session);
336    $this->sessionLoaded = true;
337    $this->session = $session;
338    if ($write_cookie) {
339      $this->setCookieFromSession($session);
340    }
341    return $this;
342  }
343
344  /**
345   * Get the session object. This will automatically look for a signed session
346   * sent via the signed_request, Cookie or Query Parameters if needed.
347   *
348   * @return Array the session
349   */
350  public function getSession() {
351    if (!$this->sessionLoaded) {
352      $session = null;
353      $write_cookie = true;
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
362      // try loading session from $_REQUEST
363      if (!$session && isset($_REQUEST['session'])) {
364        $session = json_decode(
365          get_magic_quotes_gpc()
366            ? stripslashes($_REQUEST['session'])
367            : $_REQUEST['session'],
368          true
369        );
370        $session = $this->validateSessionObject($session);
371      }
372
373      // try loading session from cookie if necessary
374      if (!$session && $this->useCookieSupport()) {
375        $cookieName = $this->getSessionCookieName();
376        if (isset($_COOKIE[$cookieName])) {
377          $session = array();
378          parse_str(trim(
379            get_magic_quotes_gpc()
380              ? stripslashes($_COOKIE[$cookieName])
381              : $_COOKIE[$cookieName],
382            '"'
383          ), $session);
384          $session = $this->validateSessionObject($session);
385          // write only if we need to delete a invalid session cookie
386          $write_cookie = empty($session);
387        }
388      }
389
390      $this->setSession($session, $write_cookie);
391    }
392
393    return $this->session;
394  }
395
396  /**
397   * Get the UID from the session.
398   *
399   * @return String the UID if available
400   */
401  public function getUser() {
402    $session = $this->getSession();
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    }
419  }
420
421  /**
422   * Get a Login URL for use with redirects. By default, full page redirect is
423   * assumed. If you are using the generated URL with a window.open() call in
424   * JavaScript, you can pass in display=popup as part of the $params.
425   *
426   * The parameters:
427   * - next: the url to go to after a successful login
428   * - cancel_url: the url to go to after the user cancels
429   * - req_perms: comma separated list of requested extended perms
430   * - display: can be "page" (default, full page) or "popup"
431   *
432   * @param Array $params provide custom parameters
433   * @return String the URL for the login flow
434   */
435  public function getLoginUrl($params=array()) {
436    $currentUrl = $this->getCurrentUrl();
437    return $this->getUrl(
438      'www',
439      'login.php',
440      array_merge(array(
441        'api_key'         => $this->getAppId(),
442        'cancel_url'      => $currentUrl,
443        'display'         => 'page',
444        'fbconnect'       => 1,
445        'next'            => $currentUrl,
446        'return_session'  => 1,
447        'session_version' => 3,
448        'v'               => '1.0',
449      ), $params)
450    );
451  }
452
453  /**
454   * Get a Logout URL suitable for use with redirects.
455   *
456   * The parameters:
457   * - next: the url to go to after a successful logout
458   *
459   * @param Array $params provide custom parameters
460   * @return String the URL for the logout flow
461   */
462  public function getLogoutUrl($params=array()) {
463    return $this->getUrl(
464      'www',
465      'logout.php',
466      array_merge(array(
467        'next'         => $this->getCurrentUrl(),
468        'access_token' => $this->getAccessToken(),
469      ), $params)
470    );
471  }
472
473  /**
474   * Get a login status URL to fetch the status from facebook.
475   *
476   * The parameters:
477   * - ok_session: the URL to go to if a session is found
478   * - no_session: the URL to go to if the user is not connected
479   * - no_user: the URL to go to if the user is not signed into facebook
480   *
481   * @param Array $params provide custom parameters
482   * @return String the URL for the logout flow
483   */
484  public function getLoginStatusUrl($params=array()) {
485    return $this->getUrl(
486      'www',
487      'extern/login_status.php',
488      array_merge(array(
489        'api_key'         => $this->getAppId(),
490        'no_session'      => $this->getCurrentUrl(),
491        'no_user'         => $this->getCurrentUrl(),
492        'ok_session'      => $this->getCurrentUrl(),
493        'session_version' => 3,
494      ), $params)
495    );
496  }
497
498  /**
499   * Make an API call.
500   *
501   * @param Array $params the API call parameters
502   * @return the decoded response
503   */
504  public function api(/* polymorphic */) {
505    $args = func_get_args();
506    if (is_array($args[0])) {
507      return $this->_restserver($args[0]);
508    } else {
509      return call_user_func_array(array($this, '_graph'), $args);
510    }
511  }
512
513  /**
514   * Invoke the old restserver.php endpoint.
515   *
516   * @param Array $params method call object
517   * @return the decoded response object
518   * @throws FacebookApiException
519   */
520  protected function _restserver($params) {
521    // generic application level parameters
522    $params['api_key'] = $this->getAppId();
523    $params['format'] = 'json-strings';
524
525    $result = json_decode($this->_oauthRequest(
526      $this->getApiUrl($params['method']),
527      $params
528    ), true);
529
530    // results are returned, errors are thrown
531    if (is_array($result) && isset($result['error_code'])) {
532      throw new FacebookApiException($result);
533    }
534    return $result;
535  }
536
537  /**
538   * Invoke the Graph API.
539   *
540   * @param String $path the path (required)
541   * @param String $method the http method (default 'GET')
542   * @param Array $params the query/post data
543   * @return the decoded response object
544   * @throws FacebookApiException
545   */
546  protected function _graph($path, $method='GET', $params=array()) {
547    if (is_array($method) && empty($params)) {
548      $params = $method;
549      $method = 'GET';
550    }
551    $params['method'] = $method; // method override as we always do a POST
552
553    $result = json_decode($this->_oauthRequest(
554      $this->getUrl('graph', $path),
555      $params
556    ), true);
557
558    // results are returned, errors are thrown
559    if (is_array($result) && isset($result['error'])) {
560      $e = new FacebookApiException($result);
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);
567      }
568      throw $e;
569    }
570    return $result;
571  }
572
573  /**
574   * Make a OAuth Request
575   *
576   * @param String $path the path (required)
577   * @param Array $params the query/post data
578   * @return the decoded response object
579   * @throws FacebookApiException
580   */
581  protected function _oauthRequest($url, $params) {
582    if (!isset($params['access_token'])) {
583      $params['access_token'] = $this->getAccessToken();
584    }
585
586    // json_encode all params values that are not strings
587    foreach ($params as $key => $value) {
588      if (!is_string($value)) {
589        $params[$key] = json_encode($value);
590      }
591    }
592    return $this->makeRequest($url, $params);
593  }
594
595  /**
596   * Makes an HTTP request. This method can be overriden by subclasses if
597   * developers want to do fancier things or use something other than curl to
598   * make the request.
599   *
600   * @param String $url the URL to make the request to
601   * @param Array $params the parameters to use for the POST body
602   * @param CurlHandler $ch optional initialized curl handle
603   * @return String the response text
604   */
605  protected function makeRequest($url, $params, $ch=null) {
606    if (!$ch) {
607      $ch = curl_init();
608    }
609
610    $opts = self::$CURL_OPTS;
611    if ($this->useFileUploadSupport()) {
612      $opts[CURLOPT_POSTFIELDS] = $params;
613    } else {
614      $opts[CURLOPT_POSTFIELDS] = http_build_query($params, null, '&');
615    }
616    $opts[CURLOPT_URL] = $url;
617
618    // disable the 'Expect: 100-continue' behaviour. This causes CURL to wait
619    // for 2 seconds if the server does not support this header.
620    if (isset($opts[CURLOPT_HTTPHEADER])) {
621      $existing_headers = $opts[CURLOPT_HTTPHEADER];
622      $existing_headers[] = 'Expect:';
623      $opts[CURLOPT_HTTPHEADER] = $existing_headers;
624    } else {
625      $opts[CURLOPT_HTTPHEADER] = array('Expect:');
626    }
627
628    curl_setopt_array($ch, $opts);
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
638    if ($result === false) {
639      $e = new FacebookApiException(array(
640        'error_code' => curl_errno($ch),
641        'error'      => array(
642          'message' => curl_error($ch),
643          'type'    => 'CurlException',
644        ),
645      ));
646      curl_close($ch);
647      throw $e;
648    }
649    curl_close($ch);
650    return $result;
651  }
652
653  /**
654   * The name of the Cookie that contains the session.
655   *
656   * @return String the cookie name
657   */
658  protected function getSessionCookieName() {
659    return 'fbs_' . $this->getAppId();
660  }
661
662  /**
663   * Set a JS Cookie based on the _passed in_ session. It does not use the
664   * currently stored session -- you need to explicitly pass it in.
665   *
666   * @param Array $session the session to use for setting the cookie
667   */
668  protected function setCookieFromSession($session=null) {
669    if (!$this->useCookieSupport()) {
670      return;
671    }
672
673    $cookieName = $this->getSessionCookieName();
674    $value = 'deleted';
675    $expires = time() - 3600;
676    $domain = $this->getBaseDomain();
677    if ($session) {
678      $value = '"' . http_build_query($session, null, '&') . '"';
679      if (isset($session['base_domain'])) {
680        $domain = $session['base_domain'];
681      }
682      $expires = $session['expires'];
683    }
684
685    // prepend dot if a domain is found
686    if ($domain) {
687      $domain = '.' . $domain;
688    }
689
690    // if an existing cookie is not set, we dont need to delete it
691    if ($value == 'deleted' && empty($_COOKIE[$cookieName])) {
692      return;
693    }
694
695    if (headers_sent()) {
696      self::errorLog('Could not set cookie. Headers already sent.');
697
698    // ignore for code coverage as we will never be able to setcookie in a CLI
699    // environment
700    // @codeCoverageIgnoreStart
701    } else {
702      setcookie($cookieName, $value, $expires, '/', $domain);
703    }
704    // @codeCoverageIgnoreEnd
705  }
706
707  /**
708   * Validates a session_version=3 style session object.
709   *
710   * @param Array $session the session object
711   * @return Array the session object if it validates, null otherwise
712   */
713  protected function validateSessionObject($session) {
714    // make sure some essential fields exist
715    if (is_array($session) &&
716        isset($session['uid']) &&
717        isset($session['access_token']) &&
718        isset($session['sig'])) {
719      // validate the signature
720      $session_without_sig = $session;
721      unset($session_without_sig['sig']);
722      $expected_sig = self::generateSignature(
723        $session_without_sig,
724        $this->getApiSecret()
725      );
726      if ($session['sig'] != $expected_sig) {
727        self::errorLog('Got invalid session signature in cookie.');
728        $session = null;
729      }
730      // check expiry time
731    } else {
732      $session = null;
733    }
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;
796  }
797
798  /**
799   * Build the URL for api given parameters.
800   *
801   * @param $method String the method name.
802   * @return String the URL for the given parameters
803   */
804  protected function getApiUrl($method) {
805    static $READ_ONLY_CALLS =
806      array('admin.getallocation' => 1,
807            'admin.getappproperties' => 1,
808            'admin.getbannedusers' => 1,
809            'admin.getlivestreamvialink' => 1,
810            'admin.getmetrics' => 1,
811            'admin.getrestrictioninfo' => 1,
812            'application.getpublicinfo' => 1,
813            'auth.getapppublickey' => 1,
814            'auth.getsession' => 1,
815            'auth.getsignedpublicsessiondata' => 1,
816            'comments.get' => 1,
817            'connect.getunconnectedfriendscount' => 1,
818            'dashboard.getactivity' => 1,
819            'dashboard.getcount' => 1,
820            'dashboard.getglobalnews' => 1,
821            'dashboard.getnews' => 1,
822            'dashboard.multigetcount' => 1,
823            'dashboard.multigetnews' => 1,
824            'data.getcookies' => 1,
825            'events.get' => 1,
826            'events.getmembers' => 1,
827            'fbml.getcustomtags' => 1,
828            'feed.getappfriendstories' => 1,
829            'feed.getregisteredtemplatebundlebyid' => 1,
830            'feed.getregisteredtemplatebundles' => 1,
831            'fql.multiquery' => 1,
832            'fql.query' => 1,
833            'friends.arefriends' => 1,
834            'friends.get' => 1,
835            'friends.getappusers' => 1,
836            'friends.getlists' => 1,
837            'friends.getmutualfriends' => 1,
838            'gifts.get' => 1,
839            'groups.get' => 1,
840            'groups.getmembers' => 1,
841            'intl.gettranslations' => 1,
842            'links.get' => 1,
843            'notes.get' => 1,
844            'notifications.get' => 1,
845            'pages.getinfo' => 1,
846            'pages.isadmin' => 1,
847            'pages.isappadded' => 1,
848            'pages.isfan' => 1,
849            'permissions.checkavailableapiaccess' => 1,
850            'permissions.checkgrantedapiaccess' => 1,
851            'photos.get' => 1,
852            'photos.getalbums' => 1,
853            'photos.gettags' => 1,
854            'profile.getinfo' => 1,
855            'profile.getinfooptions' => 1,
856            'stream.get' => 1,
857            'stream.getcomments' => 1,
858            'stream.getfilters' => 1,
859            'users.getinfo' => 1,
860            'users.getloggedinuser' => 1,
861            'users.getstandardinfo' => 1,
862            'users.hasapppermission' => 1,
863            'users.isappuser' => 1,
864            'users.isverified' => 1,
865            'video.getuploadlimits' => 1);
866    $name = 'api';
867    if (isset($READ_ONLY_CALLS[strtolower($method)])) {
868      $name = 'api_read';
869    } else if (strtolower($method) == 'video.upload') {
870      $name = 'api_video';
871    }
872    return self::getUrl($name, 'restserver.php');
873  }
874
875  /**
876   * Build the URL for given domain alias, path and parameters.
877   *
878   * @param $name String the name of the domain
879   * @param $path String optional path (without a leading slash)
880   * @param $params Array optional query parameters
881   * @return String the URL for the given parameters
882   */
883  protected function getUrl($name, $path='', $params=array()) {
884    $url = self::$DOMAIN_MAP[$name];
885    if ($path) {
886      if ($path[0] === '/') {
887        $path = substr($path, 1);
888      }
889      $url .= $path;
890    }
891    if ($params) {
892      $url .= '?' . http_build_query($params, null, '&');
893    }
894    return $url;
895  }
896
897  /**
898   * Returns the Current URL, stripping it of known FB parameters that should
899   * not persist.
900   *
901   * @return String the current URL
902   */
903  protected function getCurrentUrl() {
904    $protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on'
905      ? 'https://'
906      : 'http://';
907    $currentUrl = $protocol . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
908    $parts = parse_url($currentUrl);
909
910    // drop known fb params
911    $query = '';
912    if (!empty($parts['query'])) {
913      $params = array();
914      parse_str($parts['query'], $params);
915      foreach(self::$DROP_QUERY_PARAMS as $key) {
916        unset($params[$key]);
917      }
918      if (!empty($params)) {
919        $query = '?' . http_build_query($params, null, '&');
920      }
921    }
922
923    // use port if non default
924    $port =
925      isset($parts['port']) &&
926      (($protocol === 'http://' && $parts['port'] !== 80) ||
927       ($protocol === 'https://' && $parts['port'] !== 443))
928      ? ':' . $parts['port'] : '';
929
930    // rebuild
931    return $protocol . $parts['host'] . $port . $parts['path'] . $query;
932  }
933
934  /**
935   * Generate a signature for the given params and secret.
936   *
937   * @param Array $params the parameters to sign
938   * @param String $secret the secret to sign with
939   * @return String the generated signature
940   */
941  protected static function generateSignature($params, $secret) {
942    // work with sorted data
943    ksort($params);
944
945    // generate the base string
946    $base_string = '';
947    foreach($params as $key => $value) {
948      $base_string .= $key . '=' . $value;
949    }
950    $base_string .= $secret;
951
952    return md5($base_string);
953  }
954
955  /**
956   * Prints to the error log if you aren't in command line mode.
957   *
958   * @param String log message
959   */
960  protected static function errorLog($msg) {
961    // disable error log if we are running in a CLI environment
962    // @codeCoverageIgnoreStart
963    if (php_sapi_name() != 'cli') {
964      error_log($msg);
965    }
966    // uncomment this if you want to see the errors on the page
967    // print 'error_log: '.$msg."\n";
968    // @codeCoverageIgnoreEnd
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  }
982}
Note: See TracBrowser for help on using the browser.